Files
buzz/desktop-new
morgmart db12fdb4f7 desktop-new: SegmentedNavigation becomes Tabs, with a surface variant
The old name described one variant's appearance — a segmented control — which is
exactly why a second appearance felt like it needed a second component. `Tabs`
names the behaviour, so both variants sit under it naturally. Base UI's own
export is also `Tabs`, so it is imported as `BaseTabs`; that reads better anyway,
since `BaseTabs.Root` says plainly which layer each part comes from.

`variant="chrome" | "panel"` is the chrome/surface axis DESIGN.md had deferred
until a second component made the case. `IconButton` made it once; this made it
twice, on a real screen. The failure: the chrome container is `glass-2`, which
over a white panel composites to pure white, and its selected pill is `neutral-1`
— also pure white. Container and selection became one colour with only a shadow
between them, and no guard could see it because the component had no way to state
which background it expected. Retinting `--bg-chrome-selected` would only have
moved the collision.

One component with a variant rather than two components, because behaviour,
keyboard model, accessibility, props, and the Base UI parts underneath are
identical — a sibling would duplicate all of it to change how selection is drawn,
and the two would drift exactly as the four hand-assembled chrome surfaces did.
The panel variant still emits `role="tablist"`, correct `aria-selected`, roving
`tabIndex`, and arrow-key navigation, which is the concrete payoff.

Each variant states all three of its states in full rather than inheriting a
colour and overriding part of it. When a shared rule and a variant rule both set
a property, the more specific selector wins regardless of source order, and a
variant rule is always more specific — so the shared `[data-selected]` rule lost
and the selected tab silently rendered as unselected. Hover carries
`:not([data-selected])` because hover and selected genuinely overlap: a cursor
can sit on the selected tab, and DESIGN.md § State says a selected item in a
toggle group is not interactive. Those two selectors score identical specificity,
so without the exclusion only source order would keep it right. This follows
Chrome's modern CSS guidance: use `:not()` to say a state is irrelevant, never to
defend one rule from another.

`WorkspaceSurface` is renamed to `Panel` in the same change, since both touch the
same rules in components.css.

Signed-off-by: Morgan Martin <morganmartin@squareup.com>
Signed-off-by: morgmart <98432065+morgmart@users.noreply.github.com>
2026-09-07 16:00:28 -07:00
..