feat(editor): streamline cell editing and navigation with improved keyboard support (#12770)

https://github.com/user-attachments/assets/6bce5fa3-fb25-4906-bef1-50d4da4a13f6

This PR addresses #12769 and improves table editing UX by making Enter
commit changes and move focus down, and Tab/Shift+Tab move focus
horizontally—matching spreadsheet-like behavior.

Typing now immediately enters edit mode for selected cells without
double-clicking.
These updates apply to both the standard and virtual table views.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- You can now start editing a table cell by simply typing any character
while the cell is selected.
- **Improvements**
- Pressing Enter while editing a cell will exit editing and move focus
down.
- Pressing Tab or Shift-Tab while editing a cell will exit editing and
move focus right or left, respectively.
- **Tests**
- Added unit tests for table cell hotkey behaviors to ensure reliable
editing and navigation.
- **Chores**
- Introduced Vitest configuration for streamlined testing and coverage
reporting.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: L-Sun <zover.v@gmail.com>
This commit is contained in:
Richard Lora 2025-06-23 08:24:22 -04:00 committed by GitHub
parent 74106ba7c6
commit a8c18cd631
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 536 additions and 185 deletions

View File

@ -28,6 +28,7 @@
"lit": "^3.2.0",
"lodash-es": "^4.17.21",
"rxjs": "^7.8.1",
"vitest": "^3.2.3",
"yjs": "^13.6.21",
"zod": "^3.23.8"
},

View File

@ -0,0 +1,120 @@
import { describe, expect, it, vi } from 'vitest';
import { TableHotkeysController } from '../view-presets/table/pc/controller/hotkeys.js';
import { TableHotkeysController as VirtualHotkeysController } from '../view-presets/table/pc-virtual/controller/hotkeys.js';
import {
TableViewAreaSelection,
TableViewRowSelection,
} from '../view-presets/table/selection';
function createLogic() {
const view = {
rowsDelete: vi.fn(),
rows$: { value: [] },
groupTrait: { groupsDataList$: { value: [] } },
};
const ui = { disposables: { add: vi.fn() }, requestUpdate: vi.fn() };
const selectionController = {
selection: undefined as any,
getCellContainer: vi.fn(),
insertRowAfter: vi.fn(),
focusToCell: vi.fn(),
rowSelectionChange: vi.fn(),
areaToRows: vi.fn().mockReturnValue([]),
rowsToArea: vi.fn(),
navigateRowSelection: vi.fn(),
selectionAreaUp: vi.fn(),
selectionAreaDown: vi.fn(),
selectionAreaLeft: vi.fn(),
selectionAreaRight: vi.fn(),
isRowSelection: vi.fn().mockReturnValue(false),
};
const logic: any = {
view,
ui$: { value: ui },
selectionController,
bindHotkey: vi.fn((hotkeys: any) => {
logic.hotkeys = hotkeys;
return { dispose: vi.fn() };
}),
handleEvent: vi.fn((name: string, handler: any) => {
if (name === 'keyDown') logic.keyDown = handler;
return { dispose: vi.fn() };
}),
};
return { logic, view, ui, selectionController };
}
describe('TableHotkeysController', () => {
it('deletes rows on Backspace', () => {
const { logic, view, ui, selectionController } = createLogic();
const ctrl = new TableHotkeysController(logic as any);
ctrl.hostConnected();
selectionController.selection = TableViewRowSelection.create({
rows: [{ id: 'r1' }],
});
logic.hotkeys.Backspace();
expect(selectionController.selection).toBeUndefined();
expect(view.rowsDelete).toHaveBeenCalledWith(['r1']);
expect(ui.requestUpdate).toHaveBeenCalled();
});
it('starts editing on character key', () => {
const { logic, selectionController } = createLogic();
const ctrl = new TableHotkeysController(logic as any);
ctrl.hostConnected();
const cell = {
rowId: 'r1',
dataset: { rowId: 'r1', columnId: 'c1' },
column: { valueSetFromString: vi.fn() },
};
selectionController.getCellContainer.mockReturnValue(cell);
selectionController.selection = TableViewAreaSelection.create({
focus: { rowIndex: 0, columnIndex: 0 },
isEditing: false,
});
const evt = {
key: 'A',
metaKey: false,
ctrlKey: false,
altKey: false,
preventDefault: vi.fn(),
};
logic.keyDown({ get: () => ({ raw: evt }) });
expect(cell.column.valueSetFromString).toHaveBeenCalledWith('r1', 'A');
expect(selectionController.selection.isEditing).toBe(true);
expect(evt.preventDefault).toHaveBeenCalled();
});
});
describe('Virtual TableHotkeysController', () => {
it('writes character to cell', () => {
const { logic, selectionController } = createLogic();
const ctrl = new VirtualHotkeysController(logic as any);
ctrl.hostConnected();
const cell = {
rowId: 'r1',
dataset: { rowId: 'r1', columnId: 'c1' },
column$: { value: { valueSetFromString: vi.fn() } },
};
selectionController.getCellContainer.mockReturnValue(cell);
selectionController.selection = TableViewAreaSelection.create({
focus: { rowIndex: 1, columnIndex: 0 },
isEditing: false,
});
const evt = {
key: 'b',
metaKey: false,
ctrlKey: false,
altKey: false,
preventDefault: vi.fn(),
};
logic.keyDown({ get: () => ({ raw: evt }) });
expect(cell.column$.value.valueSetFromString).toHaveBeenCalledWith(
'r1',
'b'
);
expect(selectionController.selection.isEditing).toBe(true);
expect(evt.preventDefault).toHaveBeenCalled();
});
});

View File

@ -3,6 +3,8 @@ import { DisposableGroup } from '@blocksuite/global/disposable';
import type { ReactiveController } from 'lit';
import { TableViewAreaSelection, TableViewRowSelection } from '../../selection';
import { handleCharStartEdit } from '../../utils.js';
import type { DatabaseCellContainer } from '../row/cell.js';
import { popRowMenu } from '../row/menu';
import type { VirtualTableViewUILogic } from '../table-view-ui-logic';
@ -138,7 +140,11 @@ export class TableHotkeysController implements ReactiveController {
});
}
} else if (selection.isEditing) {
return false;
this.selectionController.selection = {
...selection,
isEditing: false,
};
this.selectionController.focusToCell('down');
} else {
this.selectionController.selection = {
...selection,
@ -172,27 +178,31 @@ export class TableHotkeysController implements ReactiveController {
},
Tab: ctx => {
const selection = this.selectionController.selection;
if (
!selection ||
TableViewRowSelection.is(selection) ||
selection.isEditing
) {
if (!selection || TableViewRowSelection.is(selection)) {
return false;
}
ctx.get('keyboardState').raw.preventDefault();
if (selection.isEditing) {
this.selectionController.selection = {
...selection,
isEditing: false,
};
}
this.selectionController.focusToCell('right');
return true;
},
'Shift-Tab': ctx => {
const selection = this.selectionController.selection;
if (
!selection ||
TableViewRowSelection.is(selection) ||
selection.isEditing
) {
if (!selection || TableViewRowSelection.is(selection)) {
return false;
}
ctx.get('keyboardState').raw.preventDefault();
if (selection.isEditing) {
this.selectionController.selection = {
...selection,
isEditing: false,
};
}
this.selectionController.focusToCell('left');
return true;
},
@ -390,5 +400,19 @@ export class TableHotkeysController implements ReactiveController {
},
})
);
this.disposables.add(
this.logic.handleEvent('keyDown', ctx => {
const event = ctx.get('keyboardState').raw;
return handleCharStartEdit<DatabaseCellContainer>({
event,
selection: this.selectionController.selection,
getCellContainer: this.selectionController.getCellContainer.bind(
this.selectionController
),
updateSelection: sel => (this.selectionController.selection = sel),
getColumn: cell => cell.column$.value,
});
})
);
}
}

View File

@ -2,6 +2,8 @@ import { popupTargetFromElement } from '@blocksuite/affine-components/context-me
import type { ReactiveController } from 'lit';
import { TableViewAreaSelection, TableViewRowSelection } from '../../selection';
import { handleCharStartEdit } from '../../utils.js';
import type { TableViewCellContainer } from '../cell.js';
import { popRowMenu } from '../menu.js';
import type { TableViewUILogic } from '../table-view-ui-logic';
@ -136,7 +138,11 @@ export class TableHotkeysController implements ReactiveController {
});
}
} else if (selection.isEditing) {
return false;
this.selectionController.selection = {
...selection,
isEditing: false,
};
this.selectionController.focusToCell('down');
} else {
this.selectionController.selection = {
...selection,
@ -170,27 +176,31 @@ export class TableHotkeysController implements ReactiveController {
},
Tab: ctx => {
const selection = this.selectionController.selection;
if (
!selection ||
TableViewRowSelection.is(selection) ||
selection.isEditing
) {
if (!selection || TableViewRowSelection.is(selection)) {
return false;
}
ctx.get('keyboardState').raw.preventDefault();
if (selection.isEditing) {
this.selectionController.selection = {
...selection,
isEditing: false,
};
}
this.selectionController.focusToCell('right');
return true;
},
'Shift-Tab': ctx => {
const selection = this.selectionController.selection;
if (
!selection ||
TableViewRowSelection.is(selection) ||
selection.isEditing
) {
if (!selection || TableViewRowSelection.is(selection)) {
return false;
}
ctx.get('keyboardState').raw.preventDefault();
if (selection.isEditing) {
this.selectionController.selection = {
...selection,
isEditing: false,
};
}
this.selectionController.focusToCell('left');
return true;
},
@ -388,5 +398,19 @@ export class TableHotkeysController implements ReactiveController {
},
})
);
this.host?.disposables.add(
this.logic.handleEvent('keyDown', ctx => {
const event = ctx.get('keyboardState').raw;
return handleCharStartEdit<TableViewCellContainer>({
event,
selection: this.selectionController.selection,
getCellContainer: this.selectionController.getCellContainer.bind(
this.selectionController
),
updateSelection: sel => (this.selectionController.selection = sel),
getColumn: cell => cell.column,
});
})
);
}
}

View File

@ -0,0 +1,58 @@
import type { TableViewSelectionWithType } from './selection';
import { TableViewRowSelection } from './selection';
export interface TableCell {
rowId: string;
}
export type ColumnAccessor<T extends TableCell> = (
cell: T
) => { valueSetFromString(rowId: string, value: string): void } | undefined;
export interface StartEditOptions<T extends TableCell> {
event: KeyboardEvent;
selection: TableViewSelectionWithType | undefined;
getCellContainer: (
groupKey: string | undefined,
rowIndex: number,
columnIndex: number
) => T | undefined;
updateSelection: (sel: TableViewSelectionWithType) => void;
getColumn: ColumnAccessor<T>;
}
export function handleCharStartEdit<T extends TableCell>(
options: StartEditOptions<T>
): boolean {
const { event, selection, getCellContainer, updateSelection, getColumn } =
options;
const target = event.target as HTMLElement | null;
if (target && (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA')) {
return false;
}
if (
selection &&
!TableViewRowSelection.is(selection) &&
!selection.isEditing &&
!event.metaKey &&
!event.ctrlKey &&
!event.altKey &&
event.key.length === 1
) {
const cell = getCellContainer(
selection.groupKey,
selection.focus.rowIndex,
selection.focus.columnIndex
);
if (cell) {
const column = getColumn(cell);
column?.valueSetFromString(cell.rowId, event.key);
updateSelection({ ...selection, isEditing: true });
event.preventDefault();
return true;
}
}
return false;
}

View File

@ -0,0 +1,25 @@
import { defineConfig } from 'vitest/config';
export default defineConfig({
esbuild: {
target: 'es2018',
},
test: {
globalSetup: '../../scripts/vitest-global.js',
include: ['src/__tests__/**/*.unit.spec.ts'],
testTimeout: 1000,
coverage: {
provider: 'istanbul',
reporter: ['lcov'],
reportsDirectory: '../../.coverage/data-view',
},
onConsoleLog(log, type) {
if (log.includes('lit.dev/msg/dev-mode')) {
return false;
}
console.warn(`Unexpected ${type} log`, log);
throw new Error(log);
},
environment: 'happy-dom',
},
});

425
yarn.lock
View File

@ -4270,6 +4270,7 @@ __metadata:
lit: "npm:^3.2.0"
lodash-es: "npm:^4.17.21"
rxjs: "npm:^7.8.1"
vitest: "npm:^3.2.3"
yjs: "npm:^13.6.21"
zod: "npm:^3.23.8"
languageName: unknown
@ -12445,142 +12446,142 @@ __metadata:
languageName: node
linkType: hard
"@rollup/rollup-android-arm-eabi@npm:4.40.2":
version: 4.40.2
resolution: "@rollup/rollup-android-arm-eabi@npm:4.40.2"
"@rollup/rollup-android-arm-eabi@npm:4.43.0":
version: 4.43.0
resolution: "@rollup/rollup-android-arm-eabi@npm:4.43.0"
conditions: os=android & cpu=arm
languageName: node
linkType: hard
"@rollup/rollup-android-arm64@npm:4.40.2":
version: 4.40.2
resolution: "@rollup/rollup-android-arm64@npm:4.40.2"
"@rollup/rollup-android-arm64@npm:4.43.0":
version: 4.43.0
resolution: "@rollup/rollup-android-arm64@npm:4.43.0"
conditions: os=android & cpu=arm64
languageName: node
linkType: hard
"@rollup/rollup-darwin-arm64@npm:4.40.2":
version: 4.40.2
resolution: "@rollup/rollup-darwin-arm64@npm:4.40.2"
"@rollup/rollup-darwin-arm64@npm:4.43.0":
version: 4.43.0
resolution: "@rollup/rollup-darwin-arm64@npm:4.43.0"
conditions: os=darwin & cpu=arm64
languageName: node
linkType: hard
"@rollup/rollup-darwin-x64@npm:4.40.2":
version: 4.40.2
resolution: "@rollup/rollup-darwin-x64@npm:4.40.2"
"@rollup/rollup-darwin-x64@npm:4.43.0":
version: 4.43.0
resolution: "@rollup/rollup-darwin-x64@npm:4.43.0"
conditions: os=darwin & cpu=x64
languageName: node
linkType: hard
"@rollup/rollup-freebsd-arm64@npm:4.40.2":
version: 4.40.2
resolution: "@rollup/rollup-freebsd-arm64@npm:4.40.2"
"@rollup/rollup-freebsd-arm64@npm:4.43.0":
version: 4.43.0
resolution: "@rollup/rollup-freebsd-arm64@npm:4.43.0"
conditions: os=freebsd & cpu=arm64
languageName: node
linkType: hard
"@rollup/rollup-freebsd-x64@npm:4.40.2":
version: 4.40.2
resolution: "@rollup/rollup-freebsd-x64@npm:4.40.2"
"@rollup/rollup-freebsd-x64@npm:4.43.0":
version: 4.43.0
resolution: "@rollup/rollup-freebsd-x64@npm:4.43.0"
conditions: os=freebsd & cpu=x64
languageName: node
linkType: hard
"@rollup/rollup-linux-arm-gnueabihf@npm:4.40.2":
version: 4.40.2
resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.40.2"
"@rollup/rollup-linux-arm-gnueabihf@npm:4.43.0":
version: 4.43.0
resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.43.0"
conditions: os=linux & cpu=arm & libc=glibc
languageName: node
linkType: hard
"@rollup/rollup-linux-arm-musleabihf@npm:4.40.2":
version: 4.40.2
resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.40.2"
"@rollup/rollup-linux-arm-musleabihf@npm:4.43.0":
version: 4.43.0
resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.43.0"
conditions: os=linux & cpu=arm & libc=musl
languageName: node
linkType: hard
"@rollup/rollup-linux-arm64-gnu@npm:4.40.2":
version: 4.40.2
resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.40.2"
"@rollup/rollup-linux-arm64-gnu@npm:4.43.0":
version: 4.43.0
resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.43.0"
conditions: os=linux & cpu=arm64 & libc=glibc
languageName: node
linkType: hard
"@rollup/rollup-linux-arm64-musl@npm:4.40.2":
version: 4.40.2
resolution: "@rollup/rollup-linux-arm64-musl@npm:4.40.2"
"@rollup/rollup-linux-arm64-musl@npm:4.43.0":
version: 4.43.0
resolution: "@rollup/rollup-linux-arm64-musl@npm:4.43.0"
conditions: os=linux & cpu=arm64 & libc=musl
languageName: node
linkType: hard
"@rollup/rollup-linux-loongarch64-gnu@npm:4.40.2":
version: 4.40.2
resolution: "@rollup/rollup-linux-loongarch64-gnu@npm:4.40.2"
"@rollup/rollup-linux-loongarch64-gnu@npm:4.43.0":
version: 4.43.0
resolution: "@rollup/rollup-linux-loongarch64-gnu@npm:4.43.0"
conditions: os=linux & cpu=loong64 & libc=glibc
languageName: node
linkType: hard
"@rollup/rollup-linux-powerpc64le-gnu@npm:4.40.2":
version: 4.40.2
resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.40.2"
"@rollup/rollup-linux-powerpc64le-gnu@npm:4.43.0":
version: 4.43.0
resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.43.0"
conditions: os=linux & cpu=ppc64 & libc=glibc
languageName: node
linkType: hard
"@rollup/rollup-linux-riscv64-gnu@npm:4.40.2":
version: 4.40.2
resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.40.2"
"@rollup/rollup-linux-riscv64-gnu@npm:4.43.0":
version: 4.43.0
resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.43.0"
conditions: os=linux & cpu=riscv64 & libc=glibc
languageName: node
linkType: hard
"@rollup/rollup-linux-riscv64-musl@npm:4.40.2":
version: 4.40.2
resolution: "@rollup/rollup-linux-riscv64-musl@npm:4.40.2"
"@rollup/rollup-linux-riscv64-musl@npm:4.43.0":
version: 4.43.0
resolution: "@rollup/rollup-linux-riscv64-musl@npm:4.43.0"
conditions: os=linux & cpu=riscv64 & libc=musl
languageName: node
linkType: hard
"@rollup/rollup-linux-s390x-gnu@npm:4.40.2":
version: 4.40.2
resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.40.2"
"@rollup/rollup-linux-s390x-gnu@npm:4.43.0":
version: 4.43.0
resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.43.0"
conditions: os=linux & cpu=s390x & libc=glibc
languageName: node
linkType: hard
"@rollup/rollup-linux-x64-gnu@npm:4.40.2":
version: 4.40.2
resolution: "@rollup/rollup-linux-x64-gnu@npm:4.40.2"
"@rollup/rollup-linux-x64-gnu@npm:4.43.0":
version: 4.43.0
resolution: "@rollup/rollup-linux-x64-gnu@npm:4.43.0"
conditions: os=linux & cpu=x64 & libc=glibc
languageName: node
linkType: hard
"@rollup/rollup-linux-x64-musl@npm:4.40.2":
version: 4.40.2
resolution: "@rollup/rollup-linux-x64-musl@npm:4.40.2"
"@rollup/rollup-linux-x64-musl@npm:4.43.0":
version: 4.43.0
resolution: "@rollup/rollup-linux-x64-musl@npm:4.43.0"
conditions: os=linux & cpu=x64 & libc=musl
languageName: node
linkType: hard
"@rollup/rollup-win32-arm64-msvc@npm:4.40.2":
version: 4.40.2
resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.40.2"
"@rollup/rollup-win32-arm64-msvc@npm:4.43.0":
version: 4.43.0
resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.43.0"
conditions: os=win32 & cpu=arm64
languageName: node
linkType: hard
"@rollup/rollup-win32-ia32-msvc@npm:4.40.2":
version: 4.40.2
resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.40.2"
"@rollup/rollup-win32-ia32-msvc@npm:4.43.0":
version: 4.43.0
resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.43.0"
conditions: os=win32 & cpu=ia32
languageName: node
linkType: hard
"@rollup/rollup-win32-x64-msvc@npm:4.40.2":
version: 4.40.2
resolution: "@rollup/rollup-win32-x64-msvc@npm:4.40.2"
"@rollup/rollup-win32-x64-msvc@npm:4.43.0":
version: 4.43.0
resolution: "@rollup/rollup-win32-x64-msvc@npm:4.43.0"
conditions: os=win32 & cpu=x64
languageName: node
linkType: hard
@ -14568,6 +14569,15 @@ __metadata:
languageName: node
linkType: hard
"@types/chai@npm:^5.2.2":
version: 5.2.2
resolution: "@types/chai@npm:5.2.2"
dependencies:
"@types/deep-eql": "npm:*"
checksum: 10/de425e7b02cc1233a93923866e019dffbafa892774813940b780ebb1ac9f8a8c57b7438c78686bf4e5db05cd3fc8a970fedf6b83638543995ecca88ef2060668
languageName: node
linkType: hard
"@types/connect-history-api-fallback@npm:^1.5.4":
version: 1.5.4
resolution: "@types/connect-history-api-fallback@npm:1.5.4"
@ -14663,6 +14673,13 @@ __metadata:
languageName: node
linkType: hard
"@types/deep-eql@npm:*":
version: 4.0.2
resolution: "@types/deep-eql@npm:4.0.2"
checksum: 10/249a27b0bb22f6aa28461db56afa21ec044fa0e303221a62dff81831b20c8530502175f1a49060f7099e7be06181078548ac47c668de79ff9880241968d43d0c
languageName: node
linkType: hard
"@types/diff-match-patch@npm:^1.0.36":
version: 1.0.36
resolution: "@types/diff-match-patch@npm:1.0.36"
@ -15936,15 +15953,16 @@ __metadata:
languageName: node
linkType: hard
"@vitest/expect@npm:3.1.4":
version: 3.1.4
resolution: "@vitest/expect@npm:3.1.4"
"@vitest/expect@npm:3.2.3":
version: 3.2.3
resolution: "@vitest/expect@npm:3.2.3"
dependencies:
"@vitest/spy": "npm:3.1.4"
"@vitest/utils": "npm:3.1.4"
"@types/chai": "npm:^5.2.2"
"@vitest/spy": "npm:3.2.3"
"@vitest/utils": "npm:3.2.3"
chai: "npm:^5.2.0"
tinyrainbow: "npm:^2.0.0"
checksum: 10/2d438562fd75ee64f0506a785f9825962f765889e63179e6d64cad338ff8fb0466bafaec9e94e6dea814ebf7287209f605ce49e4cf487610d98ccba61fee061b
checksum: 10/c67318892c2441a53fd6386232a3392fd86faf3a17528ce70fa2b6ede7778b9d7e3142b463f722d0fb5516fb671f422549d34e674f4fe8721209101c5b69805d
languageName: node
linkType: hard
@ -15967,22 +15985,22 @@ __metadata:
languageName: node
linkType: hard
"@vitest/mocker@npm:3.1.4":
version: 3.1.4
resolution: "@vitest/mocker@npm:3.1.4"
"@vitest/mocker@npm:3.2.3":
version: 3.2.3
resolution: "@vitest/mocker@npm:3.2.3"
dependencies:
"@vitest/spy": "npm:3.1.4"
"@vitest/spy": "npm:3.2.3"
estree-walker: "npm:^3.0.3"
magic-string: "npm:^0.30.17"
peerDependencies:
msw: ^2.4.9
vite: ^5.0.0 || ^6.0.0
vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0
peerDependenciesMeta:
msw:
optional: true
vite:
optional: true
checksum: 10/1e50441da229ea4999aa686669fda1cc03bcfd93162a42f7660b6e5897b6e6e2e31f54a2028c6d5510fda552ff7c27cef88fecb7efee937df28a670e59c36ca4
checksum: 10/984203df788f9822d9d8ae0a85abc204f08770c63191d1300b6e05172021309b90321fddb5962101c268e66cc9f920982c0ccf768ee67a3d4c5cb44fb27b2934
languageName: node
linkType: hard
@ -16004,12 +16022,12 @@ __metadata:
languageName: node
linkType: hard
"@vitest/pretty-format@npm:3.1.4, @vitest/pretty-format@npm:^3.1.3, @vitest/pretty-format@npm:^3.1.4":
version: 3.1.4
resolution: "@vitest/pretty-format@npm:3.1.4"
"@vitest/pretty-format@npm:3.2.3, @vitest/pretty-format@npm:^3.1.3, @vitest/pretty-format@npm:^3.2.3":
version: 3.2.3
resolution: "@vitest/pretty-format@npm:3.2.3"
dependencies:
tinyrainbow: "npm:^2.0.0"
checksum: 10/d8c831410d2cc755d899f31a5f7298ad336f4cddc3115d7da5174595098144a3282eee89a54fb05c6592d408bf4a86e66fa5636c9304816a6557b833d0f98748
checksum: 10/fd39fa90f5ec486215c962ee05d80c31dc8bff84f4c29c4390a129757ac4cbbae09b4aa669982a7888fea5de1bb2c3532aefe6c13b7d28d45295f00793aea306
languageName: node
linkType: hard
@ -16023,13 +16041,14 @@ __metadata:
languageName: node
linkType: hard
"@vitest/runner@npm:3.1.4":
version: 3.1.4
resolution: "@vitest/runner@npm:3.1.4"
"@vitest/runner@npm:3.2.3":
version: 3.2.3
resolution: "@vitest/runner@npm:3.2.3"
dependencies:
"@vitest/utils": "npm:3.1.4"
"@vitest/utils": "npm:3.2.3"
pathe: "npm:^2.0.3"
checksum: 10/45307642d00f28cbd9f196d55238aeac6d2024de9503a66c120981a0acfa43dcb06a00fbf7f06388f26c8bd5e1ed70fa59514e1644f7ec2f4c770f67666e3c0e
strip-literal: "npm:^3.0.0"
checksum: 10/4c4bdef49c646c47ef91683bf30797d48e2d1c2a615dc1adb730232578b7c4b00642204d2d15b6f73e70ecfda548da9a3c7883b50655d2801db19088f7769860
languageName: node
linkType: hard
@ -16044,14 +16063,14 @@ __metadata:
languageName: node
linkType: hard
"@vitest/snapshot@npm:3.1.4":
version: 3.1.4
resolution: "@vitest/snapshot@npm:3.1.4"
"@vitest/snapshot@npm:3.2.3":
version: 3.2.3
resolution: "@vitest/snapshot@npm:3.2.3"
dependencies:
"@vitest/pretty-format": "npm:3.1.4"
"@vitest/pretty-format": "npm:3.2.3"
magic-string: "npm:^0.30.17"
pathe: "npm:^2.0.3"
checksum: 10/f307f7a7572a76c20287efb474543021751107e41f069c34f9a90be8d9196ead3182ca41fb0a5f2879c753e341727ab6cbbb3a7cbb1fd7551cb110458359b475
checksum: 10/64b085246172d5f1c3c9815062270988757f8f00244a678b81ad00cb7ffbb8df84767a508eac00ee9bf26485b8c4f600d19e3c76618f746270337cd1a7f82136
languageName: node
linkType: hard
@ -16073,12 +16092,12 @@ __metadata:
languageName: node
linkType: hard
"@vitest/spy@npm:3.1.4":
version: 3.1.4
resolution: "@vitest/spy@npm:3.1.4"
"@vitest/spy@npm:3.2.3":
version: 3.2.3
resolution: "@vitest/spy@npm:3.2.3"
dependencies:
tinyspy: "npm:^3.0.2"
checksum: 10/e883766dbe8f07f371cc434e10bf50b66d2a31eab37bb9e12ad93b5a1e7e753543cdf2fbee9c0168c574cb6e9f8001871bc9dee45721cbeb370cabad1b8d08a5
tinyspy: "npm:^4.0.3"
checksum: 10/cff3d764c461f544cec692ff110c7dc0ee74dc5e1b6e228eba0e04b35819faf27c46321f1697f3a69010cdb609a87b7a32e852f0d07da9e510238c92006372c1
languageName: node
linkType: hard
@ -16121,14 +16140,14 @@ __metadata:
languageName: node
linkType: hard
"@vitest/utils@npm:3.1.4":
version: 3.1.4
resolution: "@vitest/utils@npm:3.1.4"
"@vitest/utils@npm:3.2.3":
version: 3.2.3
resolution: "@vitest/utils@npm:3.2.3"
dependencies:
"@vitest/pretty-format": "npm:3.1.4"
"@vitest/pretty-format": "npm:3.2.3"
loupe: "npm:^3.1.3"
tinyrainbow: "npm:^2.0.0"
checksum: 10/221d9d7dfc41e1c16521e4d998e2980b4a731b38172ba103eb70489eaaff149d479108a21a6f79118885ca2c10e51fbcae5a24e00f7459139dbfbcec39171b10
checksum: 10/ac69c88082f2590c6793b600726b25edcb27a483b12a5aae6ce88b8fff64890aa4243ea14786659961be261303dcf312b2676674f8216d57e4f63ddf5a24aa28
languageName: node
linkType: hard
@ -19502,7 +19521,7 @@ __metadata:
languageName: node
linkType: hard
"debug@npm:4, debug@npm:^4, debug@npm:^4.0.0, debug@npm:^4.0.1, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.3, debug@npm:^4.3.4, debug@npm:^4.3.5, debug@npm:^4.3.6, debug@npm:^4.4.0":
"debug@npm:4, debug@npm:^4, debug@npm:^4.0.0, debug@npm:^4.0.1, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.3, debug@npm:^4.3.4, debug@npm:^4.3.5, debug@npm:^4.3.6, debug@npm:^4.4.0, debug@npm:^4.4.1":
version: 4.4.1
resolution: "debug@npm:4.4.1"
dependencies:
@ -21437,15 +21456,15 @@ __metadata:
languageName: node
linkType: hard
"fdir@npm:^6.4.4":
version: 6.4.4
resolution: "fdir@npm:6.4.4"
"fdir@npm:^6.4.4, fdir@npm:^6.4.5":
version: 6.4.6
resolution: "fdir@npm:6.4.6"
peerDependencies:
picomatch: ^3 || ^4
peerDependenciesMeta:
picomatch:
optional: true
checksum: 10/d0000d6b790059b35f4ed19acc8847a66452e0bc68b28766c929ffd523e5ec2083811fc8a545e4a1d4945ce70e887b3a610c145c681073b506143ae3076342ed
checksum: 10/c186ba387e7b75ccf874a098d9bc5fe0af0e9c52fc56f8eac8e80aa4edb65532684bf2bf769894ff90f53bf221d6136692052d31f07a9952807acae6cbe7ee50
languageName: node
linkType: hard
@ -24313,6 +24332,13 @@ __metadata:
languageName: node
linkType: hard
"js-tokens@npm:^9.0.1":
version: 9.0.1
resolution: "js-tokens@npm:9.0.1"
checksum: 10/3288ba73bb2023adf59501979fb4890feb6669cc167b13771b226814fde96a1583de3989249880e3f4d674040d1815685db9a9880db9153307480d39dc760365
languageName: node
linkType: hard
"js-yaml@npm:^3.13.1, js-yaml@npm:^3.14.1":
version: 3.14.1
resolution: "js-yaml@npm:3.14.1"
@ -26975,7 +27001,7 @@ __metadata:
languageName: node
linkType: hard
"nanoid@npm:^3.3.6, nanoid@npm:^3.3.8":
"nanoid@npm:^3.3.11, nanoid@npm:^3.3.6, nanoid@npm:^3.3.8":
version: 3.3.11
resolution: "nanoid@npm:3.3.11"
bin:
@ -28958,14 +28984,14 @@ __metadata:
languageName: node
linkType: hard
"postcss@npm:^8.4.33, postcss@npm:^8.4.38, postcss@npm:^8.4.41, postcss@npm:^8.4.49, postcss@npm:^8.5.3":
version: 8.5.3
resolution: "postcss@npm:8.5.3"
"postcss@npm:^8.4.33, postcss@npm:^8.4.38, postcss@npm:^8.4.41, postcss@npm:^8.4.49, postcss@npm:^8.5.3, postcss@npm:^8.5.4":
version: 8.5.5
resolution: "postcss@npm:8.5.5"
dependencies:
nanoid: "npm:^3.3.8"
nanoid: "npm:^3.3.11"
picocolors: "npm:^1.1.1"
source-map-js: "npm:^1.2.1"
checksum: 10/6d7e21a772e8b05bf102636918654dac097bac013f0dc8346b72ac3604fc16829646f94ea862acccd8f82e910b00e2c11c1f0ea276543565d278c7ca35516a7c
checksum: 10/c80f723c754b656bf7c983e34841fa35fe0c37a13edd27e24de64e7962cfab11ea081b3b1c900838d2dbe576a045fdecad4f17862c488f12735742f525d22cf0
languageName: node
linkType: hard
@ -30420,30 +30446,30 @@ __metadata:
languageName: node
linkType: hard
"rollup@npm:^4.34.9":
version: 4.40.2
resolution: "rollup@npm:4.40.2"
"rollup@npm:^4.34.9, rollup@npm:^4.40.0":
version: 4.43.0
resolution: "rollup@npm:4.43.0"
dependencies:
"@rollup/rollup-android-arm-eabi": "npm:4.40.2"
"@rollup/rollup-android-arm64": "npm:4.40.2"
"@rollup/rollup-darwin-arm64": "npm:4.40.2"
"@rollup/rollup-darwin-x64": "npm:4.40.2"
"@rollup/rollup-freebsd-arm64": "npm:4.40.2"
"@rollup/rollup-freebsd-x64": "npm:4.40.2"
"@rollup/rollup-linux-arm-gnueabihf": "npm:4.40.2"
"@rollup/rollup-linux-arm-musleabihf": "npm:4.40.2"
"@rollup/rollup-linux-arm64-gnu": "npm:4.40.2"
"@rollup/rollup-linux-arm64-musl": "npm:4.40.2"
"@rollup/rollup-linux-loongarch64-gnu": "npm:4.40.2"
"@rollup/rollup-linux-powerpc64le-gnu": "npm:4.40.2"
"@rollup/rollup-linux-riscv64-gnu": "npm:4.40.2"
"@rollup/rollup-linux-riscv64-musl": "npm:4.40.2"
"@rollup/rollup-linux-s390x-gnu": "npm:4.40.2"
"@rollup/rollup-linux-x64-gnu": "npm:4.40.2"
"@rollup/rollup-linux-x64-musl": "npm:4.40.2"
"@rollup/rollup-win32-arm64-msvc": "npm:4.40.2"
"@rollup/rollup-win32-ia32-msvc": "npm:4.40.2"
"@rollup/rollup-win32-x64-msvc": "npm:4.40.2"
"@rollup/rollup-android-arm-eabi": "npm:4.43.0"
"@rollup/rollup-android-arm64": "npm:4.43.0"
"@rollup/rollup-darwin-arm64": "npm:4.43.0"
"@rollup/rollup-darwin-x64": "npm:4.43.0"
"@rollup/rollup-freebsd-arm64": "npm:4.43.0"
"@rollup/rollup-freebsd-x64": "npm:4.43.0"
"@rollup/rollup-linux-arm-gnueabihf": "npm:4.43.0"
"@rollup/rollup-linux-arm-musleabihf": "npm:4.43.0"
"@rollup/rollup-linux-arm64-gnu": "npm:4.43.0"
"@rollup/rollup-linux-arm64-musl": "npm:4.43.0"
"@rollup/rollup-linux-loongarch64-gnu": "npm:4.43.0"
"@rollup/rollup-linux-powerpc64le-gnu": "npm:4.43.0"
"@rollup/rollup-linux-riscv64-gnu": "npm:4.43.0"
"@rollup/rollup-linux-riscv64-musl": "npm:4.43.0"
"@rollup/rollup-linux-s390x-gnu": "npm:4.43.0"
"@rollup/rollup-linux-x64-gnu": "npm:4.43.0"
"@rollup/rollup-linux-x64-musl": "npm:4.43.0"
"@rollup/rollup-win32-arm64-msvc": "npm:4.43.0"
"@rollup/rollup-win32-ia32-msvc": "npm:4.43.0"
"@rollup/rollup-win32-x64-msvc": "npm:4.43.0"
"@types/estree": "npm:1.0.7"
fsevents: "npm:~2.3.2"
dependenciesMeta:
@ -30491,7 +30517,7 @@ __metadata:
optional: true
bin:
rollup: dist/bin/rollup
checksum: 10/ab767c56e37410257864e051fccbdaf448ac7774129bf39295de716af816c49e0247e72749959969efbd892fc64e096880fa269764adf765579100e81abf5e7c
checksum: 10/c7f436880dfd5bd54e9ac579625b5355be58b5437ebb386eb88d709d6bed733a4411673cc80fd64dc5514cd71794544bc83775842108c86ed2b51827e11b33b8
languageName: node
linkType: hard
@ -31973,6 +31999,15 @@ __metadata:
languageName: node
linkType: hard
"strip-literal@npm:^3.0.0":
version: 3.0.0
resolution: "strip-literal@npm:3.0.0"
dependencies:
js-tokens: "npm:^9.0.1"
checksum: 10/da1616f654f3ff481e078597b4565373a5eeed78b83de4a11a1a1b98292a9036f2474e528eff19b6eed93370428ff957a473827057c117495086436725d7efad
languageName: node
linkType: hard
"strip-outer@npm:^1.0.1":
version: 1.0.1
resolution: "strip-outer@npm:1.0.1"
@ -32546,13 +32581,13 @@ __metadata:
languageName: node
linkType: hard
"tinyglobby@npm:^0.2.12, tinyglobby@npm:^0.2.13":
version: 0.2.13
resolution: "tinyglobby@npm:0.2.13"
"tinyglobby@npm:^0.2.12, tinyglobby@npm:^0.2.13, tinyglobby@npm:^0.2.14":
version: 0.2.14
resolution: "tinyglobby@npm:0.2.14"
dependencies:
fdir: "npm:^6.4.4"
picomatch: "npm:^4.0.2"
checksum: 10/b04557ee58ad2be5f2d2cbb4b441476436c92bb45ba2e1fc464d686b793392b305ed0bcb8b877429e9b5036bdd46770c161a08384c0720b6682b7cd6ac80e403
checksum: 10/3d306d319718b7cc9d79fb3f29d8655237aa6a1f280860a217f93417039d0614891aee6fc47c5db315f4fcc6ac8d55eb8e23e2de73b2c51a431b42456d9e5764
languageName: node
linkType: hard
@ -32570,10 +32605,10 @@ __metadata:
languageName: node
linkType: hard
"tinypool@npm:^1.0.2":
version: 1.0.2
resolution: "tinypool@npm:1.0.2"
checksum: 10/6109322f14b3763f65c8fa49fddab72cd3edd96b82dd50e05e63de74867329ff5353bff4377281ec963213d9314f37f4a353e9ee34bbac85fd4c1e4a568d6076
"tinypool@npm:^1.0.2, tinypool@npm:^1.1.0":
version: 1.1.0
resolution: "tinypool@npm:1.1.0"
checksum: 10/2e99e76f01699bb3244463a4b1b473fb9a166473d417b5ce373bbd12ef4626c221100533540d90f6bddbc83149ebf97e7ce052c0d1c5ae1a5066c5690cfee538
languageName: node
linkType: hard
@ -32591,6 +32626,13 @@ __metadata:
languageName: node
linkType: hard
"tinyspy@npm:^4.0.3":
version: 4.0.3
resolution: "tinyspy@npm:4.0.3"
checksum: 10/b6a3ed40dd76a2b3c020250cf1401506b456509d1fb9dba0c7b0e644d258dac722843b85c57ccc36c8687db1e7978cb6adcc43e3b71c475910c085b96d41cb53
languageName: node
linkType: hard
"title-case@npm:^3.0.3":
version: 3.0.3
resolution: "title-case@npm:3.0.3"
@ -33727,18 +33769,18 @@ __metadata:
languageName: node
linkType: hard
"vite-node@npm:3.1.4, vite-node@npm:^3.0.4":
version: 3.1.4
resolution: "vite-node@npm:3.1.4"
"vite-node@npm:3.2.3, vite-node@npm:^3.0.4":
version: 3.2.3
resolution: "vite-node@npm:3.2.3"
dependencies:
cac: "npm:^6.7.14"
debug: "npm:^4.4.0"
debug: "npm:^4.4.1"
es-module-lexer: "npm:^1.7.0"
pathe: "npm:^2.0.3"
vite: "npm:^5.0.0 || ^6.0.0"
vite: "npm:^5.0.0 || ^6.0.0 || ^7.0.0-0"
bin:
vite-node: vite-node.mjs
checksum: 10/e4c198fe9447b4182b95601249a1e8be183380bbd2875034e8ed741a67895b8ad5c6324d6a6db7d60c2b0372f5209ca046604abfc0a70c04bffef00e5a4f6e19
checksum: 10/0dacd6b70cae010dadb560cf38afe33cef956a7cdf99fd099294891ae664b4c8bff7d217d7d85de8a042efcb0ac2d1cd9cea4901e8f48adf4356625c01b0a2aa
languageName: node
linkType: hard
@ -33782,6 +33824,61 @@ __metadata:
languageName: node
linkType: hard
"vite@npm:^5.0.0 || ^6.0.0 || ^7.0.0-0":
version: 7.0.0-beta.1
resolution: "vite@npm:7.0.0-beta.1"
dependencies:
esbuild: "npm:^0.25.0"
fdir: "npm:^6.4.5"
fsevents: "npm:~2.3.3"
picomatch: "npm:^4.0.2"
postcss: "npm:^8.5.4"
rollup: "npm:^4.40.0"
tinyglobby: "npm:^0.2.14"
peerDependencies:
"@types/node": ^20.19.0 || >=22.12.0
jiti: ">=1.21.0"
less: ^4.0.0
lightningcss: ^1.21.0
sass: ^1.70.0
sass-embedded: ^1.70.0
stylus: ">=0.54.8"
sugarss: ^5.0.0
terser: ^5.16.0
tsx: ^4.8.1
yaml: ^2.4.2
dependenciesMeta:
fsevents:
optional: true
peerDependenciesMeta:
"@types/node":
optional: true
jiti:
optional: true
less:
optional: true
lightningcss:
optional: true
sass:
optional: true
sass-embedded:
optional: true
stylus:
optional: true
sugarss:
optional: true
terser:
optional: true
tsx:
optional: true
yaml:
optional: true
bin:
vite: bin/vite.js
checksum: 10/59dc57a531214dfd477147050718e6661f85421adbd47fc4cc22d6e7320fa354f7099c18e0b3c4cfd4e03f32a9999f872909ebd8c35408610920c5c0d17a546d
languageName: node
linkType: hard
"vite@npm:^5.0.0 || ^6.0.0, vite@npm:^6.0.3, vite@npm:^6.1.0":
version: 6.3.5
resolution: "vite@npm:6.3.5"
@ -33891,37 +33988,39 @@ __metadata:
languageName: node
linkType: hard
"vitest@npm:^3.0.6":
version: 3.1.4
resolution: "vitest@npm:3.1.4"
"vitest@npm:^3.0.6, vitest@npm:^3.2.3":
version: 3.2.3
resolution: "vitest@npm:3.2.3"
dependencies:
"@vitest/expect": "npm:3.1.4"
"@vitest/mocker": "npm:3.1.4"
"@vitest/pretty-format": "npm:^3.1.4"
"@vitest/runner": "npm:3.1.4"
"@vitest/snapshot": "npm:3.1.4"
"@vitest/spy": "npm:3.1.4"
"@vitest/utils": "npm:3.1.4"
"@types/chai": "npm:^5.2.2"
"@vitest/expect": "npm:3.2.3"
"@vitest/mocker": "npm:3.2.3"
"@vitest/pretty-format": "npm:^3.2.3"
"@vitest/runner": "npm:3.2.3"
"@vitest/snapshot": "npm:3.2.3"
"@vitest/spy": "npm:3.2.3"
"@vitest/utils": "npm:3.2.3"
chai: "npm:^5.2.0"
debug: "npm:^4.4.0"
debug: "npm:^4.4.1"
expect-type: "npm:^1.2.1"
magic-string: "npm:^0.30.17"
pathe: "npm:^2.0.3"
picomatch: "npm:^4.0.2"
std-env: "npm:^3.9.0"
tinybench: "npm:^2.9.0"
tinyexec: "npm:^0.3.2"
tinyglobby: "npm:^0.2.13"
tinypool: "npm:^1.0.2"
tinyglobby: "npm:^0.2.14"
tinypool: "npm:^1.1.0"
tinyrainbow: "npm:^2.0.0"
vite: "npm:^5.0.0 || ^6.0.0"
vite-node: "npm:3.1.4"
vite: "npm:^5.0.0 || ^6.0.0 || ^7.0.0-0"
vite-node: "npm:3.2.3"
why-is-node-running: "npm:^2.3.0"
peerDependencies:
"@edge-runtime/vm": "*"
"@types/debug": ^4.1.12
"@types/node": ^18.0.0 || ^20.0.0 || >=22.0.0
"@vitest/browser": 3.1.4
"@vitest/ui": 3.1.4
"@vitest/browser": 3.2.3
"@vitest/ui": 3.2.3
happy-dom: "*"
jsdom: "*"
peerDependenciesMeta:
@ -33941,7 +34040,7 @@ __metadata:
optional: true
bin:
vitest: vitest.mjs
checksum: 10/e30f8df59d3e551c9a104dcf1e9937a0b1c3731072bcfe054a17124689852046b5c44bca0316b6ece0b301225f904709e2b990e8122d5bc7d08327d78785d6ac
checksum: 10/7412aaa6f4c5d259b7329a7aba5466b3fd1fa67f4af0ee1ea14474c48f0c5f1b230fba2a5418a6c21df19c9b8268ba0d133f9d7aac553727914fa56664344b4a
languageName: node
linkType: hard