Skip to content

refactor(ui): named layers and one side-panel shell (#512) - #1398

Merged
Juliusolsson05 merged 5 commits into
mainfrom
fix/floating-surface-layers
Sep 27, 2026
Merged

Juliusolsson05 merged 5 commits into
mainfrom
fix/floating-surface-layers

Conversation

@Juliusolsson05

@Juliusolsson05 Juliusolsson05 commented Sep 27, 2026 •

Copy link
Copy Markdown
Owner

Refs #512.

Plan: docs/plans/2026-09-27-floating-surface-layers.md.

Problem

#512's modal and toast halves landed earlier (shared Radix dialog.tsx, shared dropdown-menu.tsx, one toast). What was left:

  • No named layer scale. The stacking bands were real but written as magic numbers in about ten files, each with its own "why above X" comment:

    • pane overlays z-40/50;
    • pane dialog z-[60..62];
    • dialog z-[1100];
    • menu z-[1150];
    • toast z-[1200];
    • debug z-[10000].

    Registry and App comments still described an old "everything z-50, DOM order breaks ties" model.

  • No side-panel shell. Nine docked panels copied one class string, and it had drifted. The five debug headers drew a bare "×" with no accessible name.

  • RemotePanel was registered as a side panel while rendering a centred Dialog.

What merges

  • ui/layers.ts: one table of named layers, as literal Tailwind classes. Every banded z value moves onto it, and PANE_DIALOG_LAYERS becomes a view of it. The class strings are unchanged, so there is no visual change. The stale layering comments in registry.tsx, App.tsx and surfaces/types.ts are corrected to what actually decides stacking: the named layer, then OPEN order within the dialog layer (each Radix Dialog portals into <body> when it opens), with registry and render order breaking only same-commit ties (review b).
  • components/ui/side-panel.tsx <SidePanel>: a named aside landmark. Each panel keeps its own width.
    • Uses it: Git, Worktrees, Agent Status, the debug panels and the rendering inspector.
    • DebugPanelHeader: the debug panels share one red header and gain named closes.
  • RemotePanel moves to modalSurfaces, appended per the registry contract.

Sequencing (steering q95)

W1's #1394 edits useKeybinds.ts, and owner keyboard work is in flight. This PR does not touch useKeybinds.ts or its tests.

The dismiss stack moved out (review b). A first version shipped an unwired ui/dismissStack.ts, and review showed its wiring contract could not work:

  • a document capture-phase Escape listener runs before the inner handlers that implement two-phase dismissal (PathInput suggestions, palette sub-modes);
  • passive-effect registration order is not visual stacking order for a parent and child that mount together.

It returns, redesigned, with the useKeybinds.ts wiring on a fresh origin/main after #1394 merges.

Not in this PR (why Refs, not Fixes)

  • The dismiss stack and its useKeybinds wiring (above).
  • The three remaining hand-rolled anchored popovers (CommandSortControl, PathInput suggestions, ExplorerPane context menu). Each has a documented reason a menu primitive does not fit: the palette input keeps focus, the path field is a combobox, and the explorer menu is anchored at the pointer. A shared popover primitive shaped around one of them would fit only that caller.

Tests

  • ui/layers.test.ts: every layer is a literal z class; the bands are strictly ordered (pane layers < dialog < menu < toast < debug); and each keeps the exact class the sites used before (review a).
  • components/ui/side-panel.renderer.test.tsx:
    • the shell is a named complementary landmark that renders its content and keeps its width and column layout (review b);
    • a border-colour override replaces the default instead of stacking with it;
    • the debug close has an accessible name.
  • Gates: npx tsc -b is clean on 42798c67, and the affected renderer areas pass (82 files, 512 tests). An earlier full-renderer run on 77734732 passed 467 of 469 files; the 2 failures were the known local-only app-state/store tests, which also fail on origin/main and pass in CI.

🤖 Generated with Claude Code

Juliusolsson05 and others added 3 commits September 27, 2026 03:07
…smiss stack (#512)

States the q95 sequencing: no useKeybinds.ts edits until #1394 merges.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e modals, unwired dismiss stack (#512)

- ui/layers.ts: every magic stacking band (pane overlay/takeover, pane dialog,
  in-surface popover, dialog, menu, toast, debug) is a named literal class;
  PANE_DIALOG_LAYERS is a view of it. Stale z-50 comments corrected.
- components/ui/side-panel.tsx: the docked panel shell for Git, Worktrees,
  Agent Status and the six debug panels; DebugPanelHeader gives the debug
  closes an accessible name.
- RemotePanel renders a Dialog, so it is registered with the modals.
- ui/dismissStack.ts: topmost-only Escape + anySurfaceOpen(), shipped
  unwired; useKeybinds.ts is untouched until #1394 merges (q95).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s, pin shell and layer values (#1398 review)

The dismiss stack's wiring contract was wrong (a capture-phase Escape pre-empts
two-phase inner handlers; effect order is not stacking order for nested
mounts). It returns with the useKeybinds wiring after #1394. Stacking between
dialogs is by open order, not registry order; the comments now say so. The
SidePanel test pins children and layout, and the layer test pins exact values.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Juliusolsson05 Juliusolsson05 changed the title refactor(ui): named layers, one side-panel shell, unwired dismiss stack (#512) refactor(ui): named layers and one side-panel shell (#512) Sep 27, 2026
Juliusolsson05 and others added 2 commits September 27, 2026 04:06
… a render band only (#1398 review b round 2)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tions accurately (#1398 review b round 3)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Juliusolsson05 Juliusolsson05 added the type:ux UI/UX polish or consistency label Sep 27, 2026
@Juliusolsson05

Copy link
Copy Markdown
Owner Author

Review disposition (head 0ec09c13). a: MERGE-READY. b: FIX-BEFORE-MERGE in rounds 1–3, all fixed, then manager-verified by B6 at the cap (manager-verify-b.md; the change since 42798c67 is comments only). c: MERGE-READY.

Fixed

  • b1: the unwired dismiss stack's wiring contract was wrong (a capture-phase Escape pre-empts two-phase inner handlers; effect registration order is not stacking order). It was removed from this PR and returns, redesigned, with the useKeybinds wiring after fix(keybinds): palette and ⌘W work in an extension modal before its iframe has focus #1394.
  • b1–b3, comments: stacking comments claimed that registry/array order decides paint order. All of them now say what is true: the named layer, then open order within LAYERS.dialog (Radix portals into <body> when a dialog opens), with array order only breaking same-commit ties. SurfaceEntry.layer is documented as a render band, not a paint band.
  • b1, tests: the SidePanel test pins rendered children and layout classes.
  • a, tests: the LAYERS table is pinned to the exact classes used before the migration.

Declined (c, minors: coverage gaps, not defects)

  • The shared dialog content's use of LAYERS.dialog and RemotePanel's registry entry have no test. The values and the entry are correct and reviewed. Adding tests now would restart CI for coverage alone; they fit the dismiss-stack follow-up, which rewrites this area.

Residuals (why this PR says Refs #512): the dismiss stack plus its useKeybinds wiring (after #1394), and the three hand-rolled anchored popovers, each with a documented reason a menu primitive does not fit.

🤖 Generated with Claude Code

@Juliusolsson05
Juliusolsson05 merged commit 7b43931 into main Sep 27, 2026
2 checks passed
Juliusolsson05 added a commit that referenced this pull request Sep 27, 2026
@Juliusolsson05
Juliusolsson05 deleted the fix/floating-surface-layers branch September 27, 2026 13:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type:ux UI/UX polish or consistency

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant