diff --git a/src/frontend/components/circuit-tree-editor.tsx b/src/frontend/components/circuit-tree-editor.tsx index 685f0d7..84e72fa 100644 --- a/src/frontend/components/circuit-tree-editor.tsx +++ b/src/frontend/components/circuit-tree-editor.tsx @@ -27,6 +27,7 @@ import { deviceFieldKeys, formatPhaseTypeLabel, formatValue, + isGridEditorControlTarget, } from "../utils/circuit-grid-model"; import { buildCircuitDeviceRowInsertSnapshot, @@ -3398,6 +3399,9 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str setCircuitReorderIntent(null); }} onClick={(event) => { + if (isGridEditorControlTarget(event.target)) { + return; + } if (cell.editable) { handleRowSelectionClick(row, column.key, { ctrlKey: event.ctrlKey, @@ -3406,7 +3410,10 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str }); } }} - onDoubleClick={() => { + onDoubleClick={(event) => { + if (isGridEditorControlTarget(event.target)) { + return; + } if (cell.editable) { startEdit({ rowKey: row.rowKey, cellKey: column.key }, "selectExisting"); } diff --git a/src/frontend/utils/circuit-grid-model.ts b/src/frontend/utils/circuit-grid-model.ts index d138ed2..573b84d 100644 --- a/src/frontend/utils/circuit-grid-model.ts +++ b/src/frontend/utils/circuit-grid-model.ts @@ -230,6 +230,18 @@ export function formatPhaseTypeLabel(value: string): string { return value; } +export function isGridEditorControlTarget(target: unknown): boolean { + if ( + target === null || + typeof target !== "object" || + !("closest" in target) || + typeof target.closest !== "function" + ) { + return false; + } + return Boolean(target.closest("input, select, textarea")); +} + export function parseNumeric(cellKey: CellKey, draft: string): number | undefined { const trimmed = draft.trim(); if (trimmed === "") { diff --git a/tests/circuit-grid-model.test.ts b/tests/circuit-grid-model.test.ts index 8bff53a..bce47ed 100644 --- a/tests/circuit-grid-model.test.ts +++ b/tests/circuit-grid-model.test.ts @@ -5,6 +5,7 @@ import { buildCircuitEditPatch, buildDeviceRowEditPatch, formatValue, + isGridEditorControlTarget, getBlockSortValue, getCellKind, getCircuitValue, @@ -50,6 +51,18 @@ const circuit: CircuitTreeCircuitDto = { }; describe("circuit grid model", () => { + it("does not route clicks from active editor controls back to the grid cell", () => { + const inputTarget = { + closest: (selector: string) => + selector === "input, select, textarea" ? {} : null, + }; + const cellTarget = { closest: () => null }; + + assert.equal(isGridEditorControlTarget(inputTarget), true); + assert.equal(isGridEditorControlTarget(cellTarget), false); + assert.equal(isGridEditorControlTarget(null), false); + }); + it("keeps the equipment identifier locked as the first column", () => { assert.equal(allColumns[0].key, "equipmentIdentifier"); assert.equal(allColumns[0].locked, true);