Contain circuit editor scrolling

This commit is contained in:
2026-07-22 22:44:49 +02:00
parent c991f493da
commit d0b8239085
3 changed files with 32 additions and 7 deletions
@@ -281,6 +281,13 @@ Tasks:
- review sensible default columns and responsive behavior for typical browser widths - review sensible default columns and responsive behavior for typical browser widths
- redesign column filtering with clearer controls, active-filter indicators and an easy reset action - redesign column filtering with clearer controls, active-filter indicators and an easy reset action
Implemented layout foundation:
- table scrolling is contained inside the editor so sticky headers remain visible
- the toolbar remains reachable while the page scrolls
- programmatic grid focus preserves the viewport during undo/redo reloads
- wide tables no longer expand the surrounding browser layout
Acceptance criteria: Acceptance criteria:
- users retain column context anywhere in a long list - users retain column context anywhere in a long list
+16 -2
View File
@@ -44,12 +44,19 @@ body {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 0.75rem; gap: 0.75rem;
min-width: 0;
} }
.editor-toolbar { .editor-toolbar {
display: flex; display: flex;
flex-wrap: wrap;
gap: 0.5rem; gap: 0.5rem;
position: relative; position: sticky;
top: 0;
z-index: 12;
padding: 0.35rem 0;
background: #fff;
box-shadow: 0 1px 0 rgba(196, 205, 220, 0.8);
} }
.editor-toolbar button { .editor-toolbar button {
@@ -137,13 +144,20 @@ body {
overflow: auto; overflow: auto;
border: 1px solid #d9dee8; border: 1px solid #d9dee8;
background: #fff; background: #fff;
width: 100%;
max-width: 100%;
min-width: 0;
max-height: max(28rem, calc(100vh - 12rem));
scrollbar-gutter: stable;
} }
.tree-editor-layout { .tree-editor-layout {
display: grid; display: grid;
grid-template-columns: 320px 1fr; grid-template-columns: minmax(240px, 320px) minmax(0, 1fr);
gap: 0.75rem; gap: 0.75rem;
min-height: 560px; min-height: 560px;
min-width: 0;
align-items: start;
} }
.project-device-sidebar { .project-device-sidebar {
@@ -482,7 +482,7 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str
setAnchorRowKey(null); setAnchorRowKey(null);
} }
setSelectedCell({ rowKey: row.rowKey, cellKey }); setSelectedCell({ rowKey: row.rowKey, cellKey });
requestAnimationFrame(() => containerRef.current?.focus()); focusGridWithoutScroll();
} }
// Captures semantic identity for post-reload focus restoration. // Captures semantic identity for post-reload focus restoration.
@@ -556,7 +556,7 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str
} }
await loadTree({ showLoading: false }); await loadTree({ showLoading: false });
if (!intent) { if (!intent) {
requestAnimationFrame(() => containerRef.current?.focus()); focusGridWithoutScroll();
} }
} }
@@ -779,7 +779,7 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str
if (resolved) { if (resolved) {
setSelectedCell(resolved); setSelectedCell(resolved);
} }
requestAnimationFrame(() => containerRef.current?.focus()); focusGridWithoutScroll();
}, [data, editableCells, visibleRows]); }, [data, editableCells, visibleRows]);
// Restores multi-selected device rows after operations that rebuild row keys. // Restores multi-selected device rows after operations that rebuild row keys.
@@ -870,6 +870,10 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str
return row?.cells.find((cell) => cell.cellKey === cellKey); return row?.cells.find((cell) => cell.cellKey === cellKey);
} }
function focusGridWithoutScroll() {
requestAnimationFrame(() => containerRef.current?.focus({ preventScroll: true }));
}
// Opens edit session for selected cell. // Opens edit session for selected cell.
// Enter/F2/double-click use selectExisting; type-to-edit uses replaceWithTypedChar. // Enter/F2/double-click use selectExisting; type-to-edit uses replaceWithTypedChar.
function startEdit(cell: SelectedCell, mode: StartEditMode, typedChar?: string) { function startEdit(cell: SelectedCell, mode: StartEditMode, typedChar?: string) {
@@ -1169,7 +1173,7 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str
} }
setEditingCell(null); setEditingCell(null);
setSelectedCell({ rowKey: editingCell.rowKey, cellKey: editingCell.cellKey }); setSelectedCell({ rowKey: editingCell.rowKey, cellKey: editingCell.cellKey });
requestAnimationFrame(() => containerRef.current?.focus()); focusGridWithoutScroll();
} }
async function handleAddReserveCircuit(sectionId: string, afterCircuitId?: string) { async function handleAddReserveCircuit(sectionId: string, afterCircuitId?: string) {
@@ -3164,7 +3168,7 @@ export function CircuitTreeEditor(props: { projectId: string; circuitListId: str
const active = document.activeElement as HTMLElement | null; const active = document.activeElement as HTMLElement | null;
if (!active || !containerRef.current?.contains(active)) { if (!active || !containerRef.current?.contains(active)) {
setEditingCell(null); setEditingCell(null);
requestAnimationFrame(() => containerRef.current?.focus()); focusGridWithoutScroll();
} }
}); });
}} }}