oficina / docs Public

fix(chrome): the formatting bar measures what fits, instead of guessing

An independent review (GPT-5.1-Codex) said the breakpoint answered the
wrong question, and a width sweep in Chromium said how wrong. The bar's
height by viewport, with the 30rem media query in place:

    320px  28px   one row       (the media query)
    390px  28px   one row       (the media query)
    430px  28px   one row       (the media query)
    481px  122px  FOUR rows
    560px  92px   three rows
    660px  60px   two rows
    900px  60px   two rows
   1000px  28px   one row

So "that formatting rail shouldn't wrap" was fixed on phones and left
broken across five hundred pixels of tablet and small window. A
breakpoint asks "is this a phone" and the question is "do these controls
fit", which has a different answer at 481px and at 999px — and a
different one again in a locale where "Body text" is two words longer.
Raising the breakpoint to 1000px instead would hide all three selects on
a 900px window with room for every one of them.

fixtures/toolbar-overflow.mjs measures instead. It moves whole groups,
always a suffix of them, so the rule between groups stays correct in
both places with no special case and DOM order still matches visual
order for the roving tabindex (SC 2.4.3). A ResizeObserver on [docs-bar]
re-runs it — not matchMedia, which would put a breakpoint back, and not
window resize, which misses a scrollbar appearing or a zoom step.

Two things this got wrong before the screenshots agreed with it. The
measuring state lifted the 11rem cap off the three comboboxes, on the
theory that an uncapped control measures its true width — backwards: an
<input>'s content width is BELOW that cap, so the selects group measured
511px, rendered 532, and 760px came out two rows deep. And the guard
against the observer seeing its own writes compared widths, which threw
away the notification that arrives when the webfonts swap in at an
unchanged width. So the arithmetic is a starting guess now and the loop
after it re-measures the real arrangement until the bar actually fits,
which is the only kind of fit that survives a font or a locale.

Also from the same review: the bar's single tab stop could be left on a
control the resize had just hidden — ensureReachable ran on editor
updates only, so it took an edit to recover and someone who resized
without typing never got one. It runs after every relayout now.

And the clipped brand link is display: none. Below 800px the app name
was hidden with the 1px clip [rst-skip] uses; [rst-skip] can, because it
un-clips on :focus-visible, and this did not — a keyboard user tabbing
the bar landed on a control one pixel square with nothing to reveal it
(SC 2.4.7). The nav copy carries the same href with the same words, so
nothing is lost by it leaving the tab order.

Verified in Chromium at 23 widths from 320 to 1280: the bar is exactly
one row at every one of them, no horizontal scroll at any, and the split
fills in as room appears (1 group to 5, the "..." gone at 940). One
visible tab stop with the panel open, closed, and after resizing across
a boundary in both directions; Escape closes and lands focus on the
summary from the summary and from inside the panel; a tap inside the
panel leaves it open and a tap on the page closes it.
scripts/browser-drive.sh 44/44, fixtures 97/97, go test ./internal/docs
ok.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014jpLiN9xwBrZ5dJw92aYmF
Paul pushed by paul@keymail.dev f1477e69d00fd8ee52ff19c7ed65728ec3a87f9d parent 54f71bb
4 files changed, +401 −217
  • fixtures/toolbar-overflow.mjs +199 −0
  • fixtures/toolbar.mjs +42 −0
  • internal/docs/static/{editor.7654cd96fc66de38.js => editor.9c485342eb5aee46.js} +13 −13
  • internal/docs/views/show.html +147 −204

CI passed — run details

fixtures/toolbar-overflow.mjs

Loading diff…

fixtures/toolbar.mjs

Loading diff…

internal/docs/static/{editor.7654cd96fc66de38.js => editor.9c485342eb5aee46.js}

Loading diff…

internal/docs/views/show.html

Loading diff…