Preserve focus inside grid editors
This commit is contained in:
@@ -27,6 +27,7 @@ import {
|
|||||||
deviceFieldKeys,
|
deviceFieldKeys,
|
||||||
formatPhaseTypeLabel,
|
formatPhaseTypeLabel,
|
||||||
formatValue,
|
formatValue,
|
||||||
|
isGridEditorControlTarget,
|
||||||
} from "../utils/circuit-grid-model";
|
} from "../utils/circuit-grid-model";
|
||||||
import {
|
import {
|
||||||
buildCircuitDeviceRowInsertSnapshot,
|
buildCircuitDeviceRowInsertSnapshot,
|
||||||
@@ -3398,6 +3399,9 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str
|
|||||||
setCircuitReorderIntent(null);
|
setCircuitReorderIntent(null);
|
||||||
}}
|
}}
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
|
if (isGridEditorControlTarget(event.target)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (cell.editable) {
|
if (cell.editable) {
|
||||||
handleRowSelectionClick(row, column.key, {
|
handleRowSelectionClick(row, column.key, {
|
||||||
ctrlKey: event.ctrlKey,
|
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) {
|
if (cell.editable) {
|
||||||
startEdit({ rowKey: row.rowKey, cellKey: column.key }, "selectExisting");
|
startEdit({ rowKey: row.rowKey, cellKey: column.key }, "selectExisting");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -230,6 +230,18 @@ export function formatPhaseTypeLabel(value: string): string {
|
|||||||
return value;
|
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 {
|
export function parseNumeric(cellKey: CellKey, draft: string): number | undefined {
|
||||||
const trimmed = draft.trim();
|
const trimmed = draft.trim();
|
||||||
if (trimmed === "") {
|
if (trimmed === "") {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {
|
|||||||
buildCircuitEditPatch,
|
buildCircuitEditPatch,
|
||||||
buildDeviceRowEditPatch,
|
buildDeviceRowEditPatch,
|
||||||
formatValue,
|
formatValue,
|
||||||
|
isGridEditorControlTarget,
|
||||||
getBlockSortValue,
|
getBlockSortValue,
|
||||||
getCellKind,
|
getCellKind,
|
||||||
getCircuitValue,
|
getCircuitValue,
|
||||||
@@ -50,6 +51,18 @@ const circuit: CircuitTreeCircuitDto = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
describe("circuit grid model", () => {
|
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", () => {
|
it("keeps the equipment identifier locked as the first column", () => {
|
||||||
assert.equal(allColumns[0].key, "equipmentIdentifier");
|
assert.equal(allColumns[0].key, "equipmentIdentifier");
|
||||||
assert.equal(allColumns[0].locked, true);
|
assert.equal(allColumns[0].locked, true);
|
||||||
|
|||||||
Reference in New Issue
Block a user