fix(grid): improve condition suggestion keyboard behavior

This commit is contained in:
zipg authored and GitHub committed 2026-07-31 18:37:12 +08:00
1 parent f2bc72fcae
commit e1052333c1
3 files changed
+45 -7

No files matched your search

@@ -123,6 +123,26 @@ describe("DataGridConditionEditor quote completion", () => {
expect(input.selectionEnd).toBe(20);
});
it("starts without an active suggestion and selects the first item on ArrowDown", async () => {
const { value, input } = mountEditor("orderBy", "", { columns: ["name", "namespace"] });
input.focus();
input.value = "na";
input.setSelectionRange(2, 2);
input.dispatchEvent(new Event("input", { bubbles: true }));
await vi.waitFor(() => expect(document.querySelectorAll('[role="option"]')).toHaveLength(2));
expect(document.querySelector('[role="option"][aria-selected="true"]')).toBeNull();
expect(value.value).toBe("na");
input.dispatchEvent(new KeyboardEvent("keydown", { key: "ArrowDown", bubbles: true, cancelable: true }));
await nextTick();
expect(document.querySelector('[role="option"][aria-selected="true"]')?.textContent).toContain("name");
input.dispatchEvent(new KeyboardEvent("keydown", { key: "Enter", bubbles: true, cancelable: true }));
await nextTick();
expect(value.value).toBe("name");
});
it("keeps expanded input first-line indent and wraps long tokens", () => {
const source = readFileSync(resolve(process.cwd(), "apps/desktop/src/components/grid/DataGridConditionEditor.vue"), "utf8");
const expandedInputCss = source.match(/\.data-grid-topbar-condition-input--expanded\s*\{(?<body>[\s\S]*?)\n\}/)?.groups?.body;
@@ -34,6 +34,8 @@ describe("useDataGridConditionEditor", () => {
await nextTick();
await vi.waitFor(() => expect(editor.suggestions.value.map((item) => item.value)).toEqual(["customer_id", "customer_name"]));
expect(editor.navigate(1)).toBe(true);
expect(editor.highlightedIndex.value).toBe(0);
expect(editor.navigate(1)).toBe(true);
expect(editor.highlightedIndex.value).toBe(1);
expect(editor.navigate(1)).toBe(true);
expect(editor.highlightedIndex.value).toBe(1);
@@ -381,18 +383,34 @@ describe("useDataGridConditionEditor", () => {
it("maps Enter, Tab, arrows, and Escape without applying stale selections", async () => {
const value = ref("");
const editor = useDataGridConditionEditor({ kind: "orderBy", value, columns: ["name"], historyScope: {} });
const editor = useDataGridConditionEditor({ kind: "orderBy", value, columns: ["name", "namespace"], historyScope: {} });
value.value = "na";
await nextTick();
await vi.waitFor(() => expect(editor.suggestions.value).toHaveLength(1));
await vi.waitFor(() => expect(editor.suggestions.value).toHaveLength(2));
expect(editor.highlightedIndex.value).toBe(-1);
const initialEnter = keyboardEvent("Enter");
expect(editor.handleKeydown(initialEnter)).toBe("apply");
expect(initialEnter.preventDefault).toHaveBeenCalledOnce();
expect(value.value).toBe("na");
const down = keyboardEvent("ArrowDown");
expect(editor.handleKeydown(down)).toBe("navigate");
expect(down.preventDefault).toHaveBeenCalledOnce();
const tab = keyboardEvent("Tab");
expect(editor.handleKeydown(tab)).toBe("accept");
expect(editor.highlightedIndex.value).toBe(0);
const navigatedEnter = keyboardEvent("Enter");
expect(editor.handleKeydown(navigatedEnter)).toBe("accept");
expect(value.value).toBe("name");
const tabValue = ref("");
const tabEditor = useDataGridConditionEditor({ kind: "orderBy", value: tabValue, columns: ["name"], historyScope: {} });
tabValue.value = "na";
await nextTick();
await vi.waitFor(() => expect(tabEditor.suggestions.value).toHaveLength(1));
const tab = keyboardEvent("Tab");
expect(tabEditor.handleKeydown(tab)).toBe("accept");
expect(tabValue.value).toBe("name");
const enter = keyboardEvent("Enter");
expect(editor.handleKeydown(enter)).toBe("apply");
editor.openHistory();
@@ -264,7 +264,7 @@ export function useDataGridConditionEditor(options: UseDataGridConditionEditorOp
const limit = options.suggestionLimit ?? 8;
suggestions.value = values ? [...new Set(values)].slice(0, limit).map((suggestion) => ({ value: suggestion, kind: "column" })) : defaultSuggestions(target).slice(0, limit);
replacementRange.value = { from: target.from, to: target.to };
highlightedIndex.value = suggestions.value.length > 0 ? 0 : -1;
highlightedIndex.value = -1;
} catch (error) {
if (!controller.signal.aborted && requestId === suggestionRequestId) {
suggestions.value = [];
@@ -310,7 +310,7 @@ export function useDataGridConditionEditor(options: UseDataGridConditionEditorOp
const history = forgetDataGridConditionHistory(options.kind, toValue(options.historyScope), value);
const query = options.value.value.trim().toLowerCase();
suggestions.value = history.filter((item) => !query || item.toLowerCase().includes(query)).map((item) => ({ value: item, kind: "history" }));
highlightedIndex.value = suggestions.value.length > 0 ? Math.min(Math.max(highlightedIndex.value, 0), suggestions.value.length - 1) : -1;
highlightedIndex.value = suggestions.value.length > 0 && highlightedIndex.value >= 0 ? Math.min(highlightedIndex.value, suggestions.value.length - 1) : -1;
historyOpen.value = true;
}
@@ -328,7 +328,7 @@ export function useDataGridConditionEditor(options: UseDataGridConditionEditorOp
return true;
}
function accept(index = highlightedIndex.value) {
function accept(index = highlightedIndex.value >= 0 ? highlightedIndex.value : 0) {
const suggestion = suggestions.value[index];
if (!suggestion) return false;
let caret: number;