cmux NEXT webviews: every hover tooltip and hover card is the liquid glass

Merged
TE
15d ago
+206-47

Leo-ask: ask-d547ac77f0

Leo: "WHERE IS THE GLASS EVERYWHERE, all these hover tooltips and hover previews." This makes every web tooltip and hover card use the liquid glass (.ui-glass, ui/glass/glass.css), the surface menus and session hover cards already use. Before this, tooltips had a dense popup-surface frost and link cards had the solid popup surface.

What changed, per surface

  • Base UI tooltip (ui/Tooltip.tsx Tooltip) and the title tooltip on every first-party page (ui/titleTooltips.ts) now carry ui-glass, with the glass rim as the only edge (the border is clear). The glass uses the tooltip frost: the host's --cmux-tooltip-tint, which is the lowest alpha that keeps the text at 4.5:1 over pure black and pure white (TooltipSurface.swift), plus --tooltip-blur. That is set on the tooltip itself, so it holds under plain, Lens and Spectrum glass. They keep the small elevation-1 tooltip shadow. Font, padding, radius, fade and rise are unchanged.
  • Toolbar hints (ui/Toolbar.tsx via AnchoredCard .ui-hint): glass, tooltip shadow.
  • Hover cards (AnchoredCard: the markdown link bubble, link and PR cards, session hover cards): always ui-glass. .ui-tooltip.ui-card.ui-glass keeps elevation 2. A page class's solid fill (desktop.css .ui-card, .md-link-bubble) no longer wins over the glass.
  • Chief Usage chart tooltip (.cu-tooltip): ui-glass with the tooltip frost replaces --page-elevated plus its border.
  • Reduce Transparency is unchanged: the opaque popup surface, no blur (--glass-opaque: var(--surface-popup)).

Enforcement

webviews/scripts/check-glass-never-opaque.ts, which runs in test/glass-never-opaque.test.ts:

  • A CSS rule whose selector names a tooltip or hover card (tooltip, .ui-hint, .ui-card, hover-card, [role=tooltip]) now counts as glass even with backdrop-filter: none, so an opaque fill on it fails.
  • New findSolidTooltipMarkup: a ui-tooltip / ui-title-tooltip class list in the page code without ui-glass fails.
  • Fixture tests show that both checks flag solid tooltips and pass glass ones.

Skipped because of overlap

webviews/src/pages/shared/desktop.css, ui/ui.css and ui/popupSurface.css are in #23066 (lucasr1b), so I did not edit them. desktop.css's solid .ui-card fill is overridden from glass.css instead and is listed in the checker's TOOLTIP_FILL_OVERRIDDEN with that reason. That entry can go once #23066 lands.

Verified (huge-blue)

  • bun test test/glass-never-opaque.test.ts test/glass-one-edge.test.ts src/ui/titleTooltips.test.ts test/chief-usage-page.test.tsx test/subtle-elevation.test.ts: pass.
  • CMUX_BROWSER_TESTS=1 bun test test/tooltip-surface.test.ts test/popup-surface.test.ts: 6 + 26 pass (Chromium). tooltip-surface checks the host's tooltip tint and blur under plain, Lens and Spectrum glass, the clear border plus rim, and elevation 1. It also checks that the text keeps 4.5:1 over pure black and pure white, light and dark, on glass and under Reduce Transparency. Mutation check: if the tooltip's tint override is removed, both of those tests fail.
  • bun x vp check: format, lint and types clean.
  • test/tooltip-rules.test.ts fails the same way on base (6 title= sites in other files), so that failure is not from this PR.

Before / after

Headless Chromium with the real stylesheets (base vs head), tooltips and cards over a busy page. Left column: a tooltip with a shortcut and the title tooltip. Right column: a toolbar hint and a link hover card. Bottom: the Chief Usage chart tooltip. Headless Chromium does not render the backdrop blur in screenshots, so these show the tint and the edge only.

darklight
beforeweb before darkweb before light
afterweb after darkweb after light

Native tooltip: #23970 (TooltipPanel to Glass.makeOverlayPanel).

Agent session: cosmic-gray

🤖 Generated with Claude Code