CmuxNext: solid popup surface for menus, popovers and tooltips
Popovers, menus and tooltips were glass at about 92% with a blur, so the text under them showed through. The New Tab folder popover over the Chats list read as text on text. Every overlay that carries text is now one solid, unblurred theme surface. Native and web share the exact color.
One surface token
-
Native:
Palette.popupSurfaceis the theme'sopaqueOverlayFill(lift:).Glass.makeOverlayPanelpinsOverlaySurfaceViewto it. That covers every caller: the palette and its menus, dialogs, hover cards, find and prompt bars, page info, the cookie card and notices, group editors, the quick composer, the restart notice and shortcut-hint chips.- The themed tooltip, the icon picker panel (formerly popover vibrancy), the update sheet (formerly
Glass.makePanel) and the Share cmux dialog use it too. - The omnibar's suggestion card and the field's editing card it joins use it.
- The bookmark bubble and the update card's highlights popover are system
NSPopovers. Their content is now filled with it (NSView.fillWithPopupSurface(themeOf:)). - Overlays without text (drop overlay, dock and feed backdrops) keep this Mac's material. Toasts were made solid in #19759.
-
Light and dark: on a light theme the popup lifts toward white, so a white page gets a white popup set apart by its hairline and shadow, like native light menus. Before, it was a 14% gray box. On a dark theme it lifts toward the text. The lift stops where secondary text would drop below 4.5:1 on a hovered row: at the old 14%, dark themes measured about 3.9:1 there.
-
Web:
--surface-popupindesktop.csstakes the host's new--cmux-popup-surface(WebTheme, the same color asPalette.popupSurface). It is used by:.ui-popupand the page menu;- every acpmux menu and popover;
- the icon picker's pill;
- markdown link cards and the link popover;
- the editor's suggest and hover widgets;
- the home-channels message toolbar and switcher.
None of them set
backdrop-filter. The agent pane's dev previews now loaddesktop.cssfor the token..ui-sheetis a page sheet, not a popup, so it keeps the elevated surface.
Tooltips match the native one
.ui-tooltipand the title tooltip share one rule: the popup surface, primary ink, 5px radius, 4×8 padding, a--cmux-separatorhairline, a subtle shadow, the caption font and a 320px max width.- The shortcut hint is drawn in the secondary ink (
<Tooltip shortcut>, ordata-tooltip-shortcutviatooltipProps). The chat header's Changes, Terminal and Browser buttons, the dictation button and the New Tab tools now pass their keycaps as the hint instead of baking them into the title. - Truncated text: a title tooltip counts as truncated when its element or any descendant clips (
scrollWidth > clientWidth + 1, as in BranchBasePicker rows, where the title is on the row and the label clips). It shows the full text, wrapping, up to the row's width (or 480px for a narrow one). It is at least as wide as the line unless the full text is shorter, and then just the text's width. This istooltipWidth({width, truncated, view, text}).
Model marks
- The "Vercel AI Gateway/Apex" chip looked up the profile's own id, which names no brand, so it drew a placeholder square.
- Marks are now the first known of icon, family and id (
knownMark). A switch draws its target's mark (switching.mark, else that harness's own). - An unknown mark draws nothing: no placeholder, ever. List rows (model picker search and starred rows, Settings > Agents) keep an empty slot so names line up. The rail shows the harness's initial.
Testing
Each round put its failing tests in their own commit before the fix:
-
Round one: tests c4abc7851f7d, fix b10e6983fbbf.
-
Review gaps: tests 11aa6b0f0c57, fix 76afbfef590f.
-
The head ce7c0a8e4c98 merges feat-cmux-next with #19759. RefusalHUD is a toast there, so the refusal-pill change and its test were dropped.
-
Swift, on the fleet (
run-swift-testing-suites.sh Packages/macOS/CmuxNext):- Red at c4abc78:
PopupSurfaceTestsandThemedTooltipTestsfailed (the panel was.liquidGlass, there was no--cmux-popup-surface, and the tooltip fill waselevatedBackground). - Red at 11aa6b0:
PopupSurfaceTestsfailed with light popups darker than the page (white gave#DBDBDB) and secondary text at 3.86 to 4.08:1 on hovered rows.PopupSurfaceCallersTestsfailed with the Share dialog and refusal pill on.liquidGlassand the omnibar card onelevatedBackground. No other suite failed in either run. - Green at ce7c0a8: all 148 suites passed (cmux-ci step e567936ff7d9eb5e775978b7), including
PopupSurfaceTests,PopupSurfaceCallersTestsandThemedTooltipTests.
- Red at c4abc78:
-
Web, locally:
src/ui/titleTooltips.test.ts: red 2 failing (child clipping, text-width min), green 5/5.test/model-picker-mark.test.tsx: red 3 failing (family fallback, switch mark, row slot), green 6/6.test/chat-header-tooltips.test.tsx: red, green.test/popup-surface-dev.test.ts: red, green.CMUX_BROWSER_TESTS=1 bun test test/popup-surface.test.tsin Chromium: red on markdown, editor and home-channels popups at the translucent elevated color, green 3/3. WebKit can't launch on this machine, so the WebKit cases run only in CI's browser lane.bun run checkpasses. Also passing: ui-rules, gallery-coverage, gallery-play, theme-colors, stylesheets, check-layers, model-picker-composition, harnesses-page and the settings harness suites.
-
Swift guards match base: check-concurrency (1 base hit), crash_ratchet (5 base modules), check-theme-scope (16 base hits, none in touched files), check-system-blue, check-no-godfiles (nothing new) and lint-ios-package-conventions (2 base errors).
-
No test covers the two
NSPopovercontent fills (bookmark bubble, update card highlights) or the update sheet; showing them needs a live window. I didn't take a live capture.
Gallery: agent-pane.model-picker has a profile-without-mark variant. Tooltips are on the gallery-coverage allowlist.
Localization: there are no new user-facing strings. Keycaps moved from the title text into the hint, and the Debug Settings help for glass.opaqueOverlayLift changed (English-only).
Changelog
Changed: menus, popovers, hover cards and tooltips are solid theme surfaces, so text underneath no longer shows through. On light themes they are near-white, and a tooltip for truncated text is as wide as its row.
🤖 Generated with Claude Code