Skip to content

fix(overlay): open overlays above later rows and at their real position - #296

Merged
pathscale merged 5 commits into
masterfrom
fix/overlay-first-position
Sep 25, 2026
Merged

pathscale merged 5 commits into
masterfrom
fix/overlay-first-position

Conversation

@pathscale

@pathscale pathscale commented Sep 25, 2026 •

Copy link
Copy Markdown
Owner

Two overlay bugs, found on crates.vip's admin page (a role Select in each table row).

1. The open list painted under the next row

ui-overlay-host gives Select and Dropdown isolation: isolate, so a pointer can reach an overlay that hangs outside its root. The same stacking context confines the overlay's z-index: 80 to its host, and the host paints at z-index: auto in tree order, so the next positioned .table__row covered the open options.

Fix (overlayHost.css): .ui-overlay-host:has([data-open="true"]) { z-index: 80; }. The host takes the overlay's layer only while something inside it is open. Isolation stays.

2. The list opened at the screen's edge for a frame (and stayed there in chuzz)

createOverlayPosition measured the overlay before its width limits landed (they arrive through the style signal after the first update). Select's CSS floor is min-width: max(100%, 14rem) on a fixed box, so the first measurement was viewport-wide and the left clamp pinned the list to the edge. A desktop browser fixed it a frame later through the ResizeObserver, which read as a blink on the left. chuzz's ResizeObserver never fires, so the list stayed at the edge.

Fix (overlayPosition.ts): write the same max-width / min-width onto the element before measuring, so the first position is the final one. The write is skipped for an overlay stand-in without a style (the tests measure with one); an unguarded throw there halted reactivity for the whole test run.

Measured

A Select in a table row, the popover's first written position:

Engine Trigger x Before After
chuzz-headless 696 left 88, never corrected left 696
desktop browser, 1400px wide 765 left 8, corrected next frame left 765.38

With both fixes, the topmost element over the next row at the bottom of the open list is an option.

Checks run locally

  • bun test --conditions=browser: 321 pass, 0 fail (master: the same 321).
  • bunx tsc --noEmit, bun run build, bun run check:api, bun run smoke, bun run check:package: pass.
  • bun run lint: fails on master with the same 134 pre-existing errors; nothing new in the two changed files.

Separate chuzz bugs, not fixed here

  • ResizeObserver is defined but its callback never fires.
  • window.innerWidth reports 1440 while the page lays out at 1344.

Hard-coded local paths

docs/reviews/2026-07-27-ai-smell-deadcode-tests-docs.md named a scratchpad file by its full /private/tmp/... path, and docs/reviews/2026-07-27-theming-css-build-perf.md ran git -C /Users/revenge/code/UI. The first is described instead; the second runs in the current checkout.

meh added 2 commits September 25, 2026 08:29
ui-overlay-host isolates every Select and Dropdown so a pointer can reach
an overlay that hangs outside its root. The isolation also confines the
overlay's z-index to its host, which paints at z-index auto in tree order,
so a later positioned sibling of an ancestor covered the open list. A
Select in a table row is where it shipped: the next .table__row paints
over the options and they cannot be pressed. While anything inside the host
is open, the host takes the overlay's layer.
The width limits reached the element through the style signal only after
the first update had measured it, so the overlay was measured at its
unconstrained width. For Select, whose CSS floor is max(100%, 14rem) on a
fixed box, that is the whole viewport, and the left clamp pinned the list
to the screen edge. A desktop browser moved it into place a frame later
through the ResizeObserver, which read as a blink on the left; chuzz, whose
observer does not fire, left it there. The same limits are now written onto
the element before it is measured, so the first position is the final one.

Measured on a Select in a table row: chuzz-headless placed the list at
left 88 under a trigger at 696 and now at 696; the desktop browser's first
write was left 8 under a trigger at 765 and is now 765.38.
meh added 3 commits September 25, 2026 13:37
The host action was pinned to a chuzz revision from before headless
releases existed, so every run compiled that source against the current
registry. Its unlocked dependencies moved on (tokio features,
blitz-control-protocol 0.5.3) and it stopped compiling, turning every PR
red in the host step. The pin now names chuzz master, whose action
downloads the verified chuzz-headless 0.1.39 release.
One named a session scratchpad file under /private/tmp by its full path,
the other ran git -C against /Users/revenge/code/UI. Neither path exists
anywhere but the machine the review ran on. The scratch file is described
instead, and the git command runs in the checkout it is read from.
0.1.40 reports the live viewport size and fires ResizeObserver, and pulls
ps-blitz 0.4.12 with MutationObserver, so the QA host behaves like the
browser it stands in for on overlays and observers.
@pathscale
pathscale merged commit 0d36c9d into master Sep 25, 2026
1 check passed
@pathscale
pathscale deleted the fix/overlay-first-position branch September 25, 2026 08:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant