From 7c0fd73f7d9375f109f9c25d3fb36cfc0ac93b2b Mon Sep 17 00:00:00 2001 From: t8y2 <1156263951@qq.com> Date: Sat, 11 Jul 2026 23:05:50 +0800 Subject: [PATCH] fix(grid): keep select all inside cell details --- .../__tests__/useCellDetailEditor.spec.ts | 21 +++++++++++++++++++ .../src/composables/useCellDetailEditor.ts | 8 +++++++ .../src/lib/dataGrid/cellDetailSelection.ts | 9 ++++++++ 3 files changed, 38 insertions(+) create mode 100644 apps/desktop/src/composables/__tests__/useCellDetailEditor.spec.ts create mode 100644 apps/desktop/src/lib/dataGrid/cellDetailSelection.ts diff --git a/apps/desktop/src/composables/__tests__/useCellDetailEditor.spec.ts b/apps/desktop/src/composables/__tests__/useCellDetailEditor.spec.ts new file mode 100644 index 000000000..b0b1329d0 --- /dev/null +++ b/apps/desktop/src/composables/__tests__/useCellDetailEditor.spec.ts @@ -0,0 +1,21 @@ +import { describe, expect, it, vi } from "vitest"; +import { EditorState } from "@codemirror/state"; +import { selectAllCellDetailText } from "@/lib/dataGrid/cellDetailSelection"; + +describe("selectAllCellDetailText", () => { + it("selects the entire cell detail document", () => { + const state = EditorState.create({ doc: '{"name":"收入合同"}' }); + const dispatch = vi.fn(); + + expect(selectAllCellDetailText({ state, dispatch } as any)).toBe(true); + expect(dispatch).toHaveBeenCalledWith({ selection: { anchor: 0, head: state.doc.length } }); + }); + + it("handles empty cell values", () => { + const state = EditorState.create({ doc: "" }); + const dispatch = vi.fn(); + + selectAllCellDetailText({ state, dispatch } as any); + expect(dispatch).toHaveBeenCalledWith({ selection: { anchor: 0, head: 0 } }); + }); +}); diff --git a/apps/desktop/src/composables/useCellDetailEditor.ts b/apps/desktop/src/composables/useCellDetailEditor.ts index a63ae1c5b..6d116bedb 100644 --- a/apps/desktop/src/composables/useCellDetailEditor.ts +++ b/apps/desktop/src/composables/useCellDetailEditor.ts @@ -15,6 +15,7 @@ import i18n from "@/i18n"; import EditorSearchPanel from "@/components/editor/EditorSearchPanel.vue"; import type { EditorTheme } from "@/stores/settingsStore"; import type { AppThemeAppearance, AppThemePalette } from "@/lib/app/appTheme"; +import { selectAllCellDetailText } from "@/lib/dataGrid/cellDetailSelection"; export interface UseCellDetailEditorOptions { onChange?: (value: string) => void; @@ -198,6 +199,10 @@ export function useCellDetailEditor(options: UseCellDetailEditorOptions): UseCel themeComp.of(theme), fontThemeComp.of(fontTheme), keymap.of([ + { + key: "Mod-a", + run: selectAllCellDetailText, + }, { key: "Escape", run: () => { @@ -227,6 +232,9 @@ export function useCellDetailEditor(options: UseCellDetailEditorOptions): UseCel }), EditorState.readOnly.of(!!options.readOnly), EditorView.editable.of(!options.readOnly), + // Read-only CodeMirror content is not editable or focusable by default. + // Keep it keyboard-focusable so selection shortcuts stay inside the detail value. + EditorView.contentAttributes.of(options.readOnly ? { tabindex: "0" } : {}), ], }); diff --git a/apps/desktop/src/lib/dataGrid/cellDetailSelection.ts b/apps/desktop/src/lib/dataGrid/cellDetailSelection.ts new file mode 100644 index 000000000..cb40b2c18 --- /dev/null +++ b/apps/desktop/src/lib/dataGrid/cellDetailSelection.ts @@ -0,0 +1,9 @@ +interface CellDetailSelectionEditor { + state: { doc: { length: number } }; + dispatch(spec: { selection: { anchor: number; head: number } }): void; +} + +export function selectAllCellDetailText(editor: CellDetailSelectionEditor): boolean { + editor.dispatch({ selection: { anchor: 0, head: editor.state.doc.length } }); + return true; +}