fix(cmux-next): sidebar rows drop hover controls when hover clears during a reload
A sidebar workspace row could keep its x, more button and chevron after the pointer left it, so it looked hovered with nothing over it. It happens whenever hover clears during a list reload (any model change, including a workspace switch) or a scroll.
The cause is #21316 ("perf: defer hover layout during sidebar applies"). It made WorkspaceRowView.hoverChanged() skip needsLayout = true while suppressHoverEffects or hoverFollowsScroll is set. The row only shows or hides those controls in layout(), and SidebarListView.apply clears hover through updateHover() inside that suppression window, so the row never laid out again. The fill cleared (it repaints through needsDisplay), but the controls stayed. #21543 fixed rows that leave the list, not rows that stay.
The row now always asks for layout on a hover change; AppKit folds that into the next pass. The synchronous layoutSubtreeIfNeeded() and title marquee stay suppressed during scrolls and applies, which was the hitch #21316 was after.
Test
WorkspaceRowHoverMotionTests.hoverClearedDuringAReloadHidesTheRowsControls hovers a row, reloads the list with no pointer over it, lays the row out and expects the x hidden. It is committed before the fix (4603042146), so the first commit should be red on that test and the head green. Not run locally: the CmuxNext test target needs GhosttyKit, which this checkout doesn't build; CI is the evidence.
Changelog
- Fixed: Sidebar rows no longer keep their close and menu buttons after the pointer leaves during a list update or scroll.
🤖 Generated with Claude Code
Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
Fixes sidebar workspace rows keeping their close and menu buttons visible after the pointer leaves during a list reload or scroll.
- The row now always requests a layout pass on hover changes; the synchronous layout and title marquee remain deferred during scrolls and list applies, preserving the earlier performance fix.
- Adds a test covering a reload clearing hover with no pointer over the list.