sidebar: a hover control stays lit while its menu is open, and lights alone
Leo, 2026-10-26: "If it's a toggle, if it's something like that, then you keep it on when you click the context menu, when you click the top, the drop-down, the popover, whatever the f***ing. We say we keep it."
Leo, 2026-10-27: "why are you giving it the entire row when it's only this small little section? Just don't do that. Don't ever do that."
What changed (from the sw-sidebar audit)
- Workspace rows. The ⋮, ✕ and chevron followed
isHoveredonly, so they disappeared once the pointer moved onto the row's open ⋮ menu.SidebarRowMenu.shownow setsWorkspaceRowView.showsMenufor the synchronouspopUpand clears it in adefer. While that flag is set, the hover controls stay shown (revealsHoverControls), andOverflowButton.showsMenukeeps the ⋮ pressed (lit). The row's fill does not change. - Sidebar item rows (workspace tiles and pinned rows). The tile's ⋮ menu now holds its controls (
SidebarRegionViewsetsshowsMenuaroundpopUp) and lights only its ⋮.fillno longer turnsshowsMenuintoselectedwhen the hover controls are showing. The profile control is the one case where the whole pill is the control, so it keeps its pill fill while its menu is open. - Group headers. While the group editor is open, its trigger ⋮ stays lit (
moreButton.showsMenu = isEditing). The bar no longer takes the hover step forisEditing: hover and drop-target still paint it, the open editor does not. OverflowButton.showsMenuis new and false by default. Its mouse-down and hide handlers now return to the held state instead of always clearing the press.
No positions, sizes or slots change (#27561 owns the trailing geometry). No Chief code is touched. Overlap: #27586 adds the same showsHoverActions || showsMenu line for item rows. This PR also stops the whole-pill fill, so whichever lands second has a one-line conflict.
Risk
Small. The change is to state: which controls are revealed, and which button is lit while a menu is open. Menus still open on the click with no fade-in.
Tests
SidebarMenuHeldControlsTests has one test per row kind. With the menu or editor open and isHovered false, it checks that the trigger is shown and lit and that the row's fill is not the hover or selected whole-row fill. It also checks that everything clears after the menu closes, and that the profile control keeps its pill fill. Results from the fleet at head and base are below.
Fleet results (package-test-lane.sh, gui-session-v1), at dc86dbd vs its base 1cae45c:
SidebarMenuHeldControlsTests(new): 4/4 pass.- Pass at head: SidebarRowMenuNoFocusTests, GroupHeaderHoverRevealTests, GroupHeaderTrailingTests, SidebarMenuAnchorTests, SidebarOverflowGlyphTests, SidebarProfileChipTests, SidebarEditModeTests, WorkspaceRowHoverMotionTests, SidebarTrailingSlotTests, SidebarTrailingColumnTests, PaneMoreOverflowButtonTests, SidebarTabGroupControlsTests.
TabBarRestingControlsTests.thePaneTypeChooserFadesWithThePlus()fails identically at head and base (lines 55 and 58,chooser.alphaValue → 0.0 == 1.0; no crash). It is a base red.- Head 1d2770e only adds a base update (delta review SHIP).
cmux-next fast gatespassed: https://github.com/manaflow-ai/cmux/actions/runs/41030139450
Captures
Not attached: the fleet could not capture this state. cmux-ci capture --state tour:object-menu-workspace ran at base and head five times. Slot leases take window stills only. The --whole-host and --display-scale 2 runs got cmux15, which has no route that can capture the display ("no CuaSshScreenCapture.app; screencapture: could not create image from display"). On cmux-mac-mini, copying the output back timed out over ssh, and cmux21-24 are reserved. The open menu is what has to be shown, and only a display shot can show it. The final-state window stills look the same before and after, as expected, because the menu has closed by then.
Agent session: agent session
🤖 Generated with Claude Code