Repository navigation
cmux-next sidebar: hover follows the pointer, row pills stop short of the edge, the row card stands off its row - #22733
Conversation
…f the edge, the row card stands off its row (failing) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rt of the edge, the row card stands off its row Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
cmux status (one comment, edited in place; each line is updated by the job that owns it) Review App of this head (app.zip, kept 1 day)
Not verified: macOS jobs did not run: compile and app tests were skipped on CI passes on Written by Tour of |
|
Bead |
|
|
|
Shipped in:
|
|
Shipped in:
|
…from #22733 #22733 (Leo 2026-10-20) ends every sidebar row SidebarStyle.rowTrailingTrim (Metrics.space4, 8 pt) short of the list's right inset, so the pill never runs to the sidebar's edge. SidebarRowGutterTests still required the pill to end at the inset and at the divider's right edge, so it has been red on feat-cmux-next since then. The content insets inside the pill stay equal; only the pill's right edge moves in by the trim. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15c01-a42d-7970-a4a7-2f0ac203c940&host=cosmic-gray
…from #22733 (#23304) #22733 (Leo 2026-10-20) ends every sidebar row SidebarStyle.rowTrailingTrim (Metrics.space4, 8 pt) short of the list's right inset, so the pill never runs to the sidebar's edge. SidebarRowGutterTests still required the pill to end at the inset and at the divider's right edge, so it has been red on feat-cmux-next since then. The content insets inside the pill stay equal; only the pill's right edge moves in by the trim. Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15c01-a42d-7970-a4a7-2f0ac203c940&host=cosmic-gray Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…#23478) * test(next sidebar): pinned rows end at the group header's trimmed edge (failing) SidebarPinnedRowWidthTests still wanted the group header to end at the list's right inset; since #22733 every list row ends rowTrailingTrim short of it, as SidebarRowGutterTests learned in #23304. The pinned Home and App Store pills must end at the same place, and do not yet: they run 8 pt past the header at every density and width. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d18-aabc-7850-af29-f0655b1d2a1a&host=cosmic-gray * fix(next sidebar): pinned rows in the list take the row trim #22733 ends every list row SidebarStyle.rowTrailingTrim short of the right inset, but a block row (the pinned Home and App Store) lays out its own items across the full row, so their pills ran 8 pt past the group header and the workspace rows. SidebarRegionMetrics gets a trailingTrim (0 by default), which the list's blocks set to the row trim; a block's list rows end that much short. The fixed bands outside the list keep their full width. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a15d18-aabc-7850-af29-f0655b1d2a1a&host=cosmic-gray --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
… a top-right dog-ear (#23783) * test(cmux-next sidebar): a workspace row runs full length and its hover action is a top-right dog-ear (failing) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16040-fd0b-7dd0-9487-1a3a198d9f5c&host=cosmic-gray * fix(cmux-next sidebar): workspace rows run full length; the hover close or menu is a top-right dog-ear Rows end at the list's inset again (rowTrailingTrim 0, taking back #22733's trim). The x and the more button no longer sit in rounded boxes at the end of the title: one dog-ear folds over the row's top-right corner (the close, or the menu on a row that cannot close), takes clicks only on its fold, follows the row's corner radius and draws translucent theme fills. The title keeps its full width on hover; the unread badge and keycap keep their slots. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16040-fd0b-7dd0-9487-1a3a198d9f5c&host=cosmic-gray * fix(cmux-next sidebar): an expanded row's hover pin clears the unread badge and the dog-ear Review follow-ups: the pin's slot is taken after the badge or keycap slot and ends before the dog-ear's square, so it never covers the badge (which now stays on hover) and a click on it never lands on the fold. The dog-ear is a little larger (controlSize + space1) so its glyph reads at compact size, its tinted glyph is cached per color, and two stale doc comments are updated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16040-fd0b-7dd0-9487-1a3a198d9f5c&host=cosmic-gray * cmux NEXT sidebar: the dog-ear fires only on its fold and yields to the row's end controls Codex review of #23783 (xhigh) found two ways the dog-ear closed a workspace the user did not mean to close: - NSButton tracked the press over the dog-ear's whole square, so a press on the fold dragged below the crease and released there still closed. The dog-ear now tracks the press itself: a release fires only on the fold after a press that began on it, and the fold unlights while the pointer is off it. - On a 24 pt row the tabs chevron, the session tree's fold or the audio button at the row's end sits partly under the dog-ear's square, and the dog-ear hit-tested first, so a click on the chevron's corner closed the workspace. The row now hit-tests the dog-ear last and draws those controls over the fold, so what shows on top is what a click presses. Tests: aPressDraggedOffTheFoldDoesNotClose, aControlUnderTheDogEarKeepsItsClicksAndDrawsOverIt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16040-fd0b-7dd0-9487-1a3a198d9f5c&host=cosmic-gray * cmux NEXT sidebar: a dog-ear disabled mid-press does not fire; no unprobed super calls Codex re-review of #23783 at 8819d4b: a press held while the dog-ear was disabled still fired on release. The release now fires only on an enabled dog-ear, and always clears the press. The crash-class selector rule flagged super.mouseDragged and super.mouseUp on NSButton (no probe in objc-selector-table.json). The dog-ear only reaches them with no press of its own, and then NSButton's tracking loop already took the drag and the release, so it ignores them instead of calling super. Test: aPressDraggedOffTheFoldDoesNotClose covers a press disabled mid-click and the click after it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16040-fd0b-7dd0-9487-1a3a198d9f5c&host=cosmic-gray * cmux NEXT sidebar: the row's hover fill leaves the close's corner out, no dog-ear fold Leo on the dog-ear: "i wanted the hoverable area to just... not have it on the top right corner. a smaller top right corner not higlighitng bc the button itself chopped off that top right." The close (or the Home row's menu) no longer draws a folded triangle. It sits in a small square on the row's top-right corner that the row's hover or selection fill leaves out, so the highlight reads as the row with its corner chopped off by the button. The x keeps its place. The fill is a shape layer under the row's content while the corner is cut (no mask on the row), and goes back to the backing layer otherwise. Debug Settings `sidebar.closeNotch` keeps the gallery's versions: snug rounded cut (default), snug square cut, a rounded cut the size of the old dog-ear, and the snug cut with a hairline. WorkspaceRowCloseNotchGalleryTests renders them all, light and dark, on the fleet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16040-fd0b-7dd0-9487-1a3a198d9f5c&host=cosmic-gray * cmux NEXT sidebar: the row's corner close is a VoiceOver button at the snug cut's size Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16040-fd0b-7dd0-9487-1a3a198d9f5c&host=cosmic-gray * cmux NEXT sidebar: the corner close takes exactly the drawn cut, follows a look change and a still pointer Codex review of 90fc220 (BLOCK): - The rounded cut's fillets reach past the close's square, and a click there selected the row. The close's frame now covers the whole cut (SidebarCloseNotch.cutFrame) and it takes exactly the points the row's drawn fill leaves out (cutContains), in every sidebar.closeNotch look. - sidebar.closeNotch was read only in layout, so shown rows kept the old cut. SidebarTunablesWatch observes it with the other row tunables and configure hands it to the row, which lays out again on a change. - Shown under a pointer that does not move, the close got no enter event and its x stayed dim. It reads the pointer when it unhides. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16040-fd0b-7dd0-9487-1a3a198d9f5c&host=cosmic-gray * cmux NEXT sidebar: the corner close fires only on a release in the drawn cut; the gallery draws each look Codex review of c80b62d (BLOCK): - Only the first hit test checked the cut; NSButton's own tracking fired on a release anywhere in the frame, which reaches onto the row's fill past a rounded cut. The close tracks the press itself: it fires only on a release in the cut after a press there. - The gallery set each look and drew rows in the same turn, before the tunables watch dropped its cached values, so every look could draw the snug cut. It refreshes the watch after each set and requires each row to carry the look it is drawing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16040-fd0b-7dd0-9487-1a3a198d9f5c&host=cosmic-gray --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* test(cmux-next sidebar): a workspace row runs full length and its hover action is a top-right dog-ear (failing) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16040-fd0b-7dd0-9487-1a3a198d9f5c&host=cosmic-gray * fix(cmux-next sidebar): workspace rows run full length; the hover close or menu is a top-right dog-ear Rows end at the list's inset again (rowTrailingTrim 0, taking back #22733's trim). The x and the more button no longer sit in rounded boxes at the end of the title: one dog-ear folds over the row's top-right corner (the close, or the menu on a row that cannot close), takes clicks only on its fold, follows the row's corner radius and draws translucent theme fills. The title keeps its full width on hover; the unread badge and keycap keep their slots. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16040-fd0b-7dd0-9487-1a3a198d9f5c&host=cosmic-gray * fix(cmux-next sidebar): an expanded row's hover pin clears the unread badge and the dog-ear Review follow-ups: the pin's slot is taken after the badge or keycap slot and ends before the dog-ear's square, so it never covers the badge (which now stays on hover) and a click on it never lands on the fold. The dog-ear is a little larger (controlSize + space1) so its glyph reads at compact size, its tinted glyph is cached per color, and two stale doc comments are updated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16040-fd0b-7dd0-9487-1a3a198d9f5c&host=cosmic-gray * cmux NEXT sidebar: the dog-ear fires only on its fold and yields to the row's end controls Codex review of #23783 (xhigh) found two ways the dog-ear closed a workspace the user did not mean to close: - NSButton tracked the press over the dog-ear's whole square, so a press on the fold dragged below the crease and released there still closed. The dog-ear now tracks the press itself: a release fires only on the fold after a press that began on it, and the fold unlights while the pointer is off it. - On a 24 pt row the tabs chevron, the session tree's fold or the audio button at the row's end sits partly under the dog-ear's square, and the dog-ear hit-tested first, so a click on the chevron's corner closed the workspace. The row now hit-tests the dog-ear last and draws those controls over the fold, so what shows on top is what a click presses. Tests: aPressDraggedOffTheFoldDoesNotClose, aControlUnderTheDogEarKeepsItsClicksAndDrawsOverIt. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16040-fd0b-7dd0-9487-1a3a198d9f5c&host=cosmic-gray * cmux NEXT sidebar: a dog-ear disabled mid-press does not fire; no unprobed super calls Codex re-review of #23783 at 8819d4b: a press held while the dog-ear was disabled still fired on release. The release now fires only on an enabled dog-ear, and always clears the press. The crash-class selector rule flagged super.mouseDragged and super.mouseUp on NSButton (no probe in objc-selector-table.json). The dog-ear only reaches them with no press of its own, and then NSButton's tracking loop already took the drag and the release, so it ignores them instead of calling super. Test: aPressDraggedOffTheFoldDoesNotClose covers a press disabled mid-click and the click after it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16040-fd0b-7dd0-9487-1a3a198d9f5c&host=cosmic-gray * cmux NEXT sidebar: the row's hover fill leaves the close's corner out, no dog-ear fold Leo on the dog-ear: "i wanted the hoverable area to just... not have it on the top right corner. a smaller top right corner not higlighitng bc the button itself chopped off that top right." The close (or the Home row's menu) no longer draws a folded triangle. It sits in a small square on the row's top-right corner that the row's hover or selection fill leaves out, so the highlight reads as the row with its corner chopped off by the button. The x keeps its place. The fill is a shape layer under the row's content while the corner is cut (no mask on the row), and goes back to the backing layer otherwise. Debug Settings `sidebar.closeNotch` keeps the gallery's versions: snug rounded cut (default), snug square cut, a rounded cut the size of the old dog-ear, and the snug cut with a hairline. WorkspaceRowCloseNotchGalleryTests renders them all, light and dark, on the fleet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16040-fd0b-7dd0-9487-1a3a198d9f5c&host=cosmic-gray * cmux NEXT sidebar: the row's corner close is a VoiceOver button at the snug cut's size Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16040-fd0b-7dd0-9487-1a3a198d9f5c&host=cosmic-gray * cmux NEXT sidebar: the corner close takes exactly the drawn cut, follows a look change and a still pointer Codex review of 90fc220 (BLOCK): - The rounded cut's fillets reach past the close's square, and a click there selected the row. The close's frame now covers the whole cut (SidebarCloseNotch.cutFrame) and it takes exactly the points the row's drawn fill leaves out (cutContains), in every sidebar.closeNotch look. - sidebar.closeNotch was read only in layout, so shown rows kept the old cut. SidebarTunablesWatch observes it with the other row tunables and configure hands it to the row, which lays out again on a change. - Shown under a pointer that does not move, the close got no enter event and its x stayed dim. It reads the pointer when it unhides. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16040-fd0b-7dd0-9487-1a3a198d9f5c&host=cosmic-gray * cmux NEXT sidebar: the corner close fires only on a release in the drawn cut; the gallery draws each look Codex review of c80b62d (BLOCK): - Only the first hit test checked the cut; NSButton's own tracking fired on a release anywhere in the frame, which reaches onto the row's fill past a rounded cut. The close tracks the press itself: it fires only on a release in the cut after a press there. - The gallery set each look and drew rows in the same turn, before the tunables watch dropped its cached values, so every look could draw the snug cut. It refreshes the watch after each set and requires each row to carry the look it is drawing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Agent-Session: https://cmux.com/deeplink/agent?harness=claude&session=01a16040-fd0b-7dd0-9487-1a3a198d9f5c&host=cosmic-gray * docs: add ergonomic cmux-next preview workflow Agent-Session: https://cmux.com/deeplink/agent?harness=codex&session=01a1675a-0d00-7500-aa2e-61664f715df3&host=cosmic-gray * cmux NEXT: make close-notch preview artifacts reviewable Agent-Session: https://cmux.com/deeplink/agent?harness=codex&session=01a16759-6434-7f61-9180-62dc0965c7b2&host=cosmic-gray * cmux NEXT: add ergonomic preview wrapper Agent-Session: https://cmux.com/deeplink/agent?harness=codex&session=01a16758-4b24-7c41-b817-18aff1fb02a5&host=cosmic-gray * docs: align preview wrapper contract Agent-Session: https://cmux.com/deeplink/agent?harness=codex&session=01a16747-6774-7840-9abc-3147d6b51232&host=cosmic-gray * test(next): cover Home dog-ear VoiceOver label Agent-Session: https://cmux.com/deeplink/agent?harness=codex&session=01a166c1-b197-7073-8526-9f5eba16f64f&host=cosmic-gray * docs: clarify hosted close-notch preview command Agent-Session: https://cmux.com/deeplink/agent?harness=codex&session=01a16747-6774-7840-9abc-3147d6b51232&host=cosmic-gray * fix: serialize preview process startup Agent-Session: https://cmux.com/deeplink/agent?harness=codex&session=01a16747-6774-7840-9abc-3147d6b51232&host=cosmic-gray * fix(next): make browser previews use real checkout state Agent-Session: https://cmux.com/deeplink/agent?harness=codex&session=01a16746-f280-7d72-9922-f6c3c758ca81&host=cosmic-gray * fix: route gallery entries through hash links Agent-Session: https://cmux.com/deeplink/agent?harness=codex&session=01a16747-6774-7840-9abc-3147d6b51232&host=cosmic-gray * docs: scope native preview recipe claims Agent-Session: https://cmux.com/deeplink/agent?harness=codex&session=01a16747-6774-7840-9abc-3147d6b51232&host=cosmic-gray * test(next): reject galleries from another preview process Agent-Session: https://cmux.com/deeplink/agent?harness=codex&session=01a166c1-b197-7073-8526-9f5eba16f64f&host=cosmic-gray * fix(next): use only the managed preview gallery URL Agent-Session: https://cmux.com/deeplink/agent?harness=codex&session=01a166c1-b197-7073-8526-9f5eba16f64f&host=cosmic-gray * fix(next): publish gallery metadata before preview readiness Agent-Session: https://cmux.com/deeplink/agent?harness=codex&session=01a166c1-b197-7073-8526-9f5eba16f64f&host=cosmic-gray * test(next): run preview wrapper contract in CI Agent-Session: https://cmux.com/deeplink/agent?harness=codex&session=01a166c1-b197-7073-8526-9f5eba16f64f&host=cosmic-gray * test(next): reject foreign preview index readiness Agent-Session: https://cmux.com/deeplink/agent?harness=codex&session=01a166c1-b197-7073-8526-9f5eba16f64f&host=cosmic-gray * fix(next): authenticate preview index readiness Agent-Session: https://cmux.com/deeplink/agent?harness=codex&session=01a166c1-b197-7073-8526-9f5eba16f64f&host=cosmic-gray * fix(next): avoid curl pipefail on preview ownership check Agent-Session: https://cmux.com/deeplink/agent?harness=codex&session=01a166f4-abed-7bc3-922b-15af1bc7b48e&host=cosmic-gray --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Takes back #22294: Leo 2026-10-20 asked that the hover follow the pointer at once, one row at a time; #22294's rule kept the old row hovered on the next row's fill, which felt trapped. The corner and gap rules from rest stay.
Leo, 2026-10-20: moving the pointer between sidebar workspace rows felt trapped.
Was
Now
hoverOut, which is 0 by default.SidebarStyle.rowTrailingTrim(Metrics.space4) short of the right inset, Chrome-style. Headers get the same trim, so the trailing column stays aligned..besideRow,.beside) sitHoverCardEscapeGeometry.rowGap(10 pt) off their row. The strip between row and card keeps the card only while the pointer is heading into it (safe triangle), so moving down past the row lets it go. Tab cards still touch their tab (Lawrence 2026-10-19).Tests
SidebarRowHoverFollowTests(hover follows the pointer; rows end short of the edge)SidebarHoverCardEscapeTests.theCardStandsOffItsRowSidebarHoverCardEscapeTests.movingDownPastTheRowsRightEndDismissesTheCardSidebarRowHoverInsetTests,WorkspaceRowHoverMotionTests,HoverCardEscapeGeometryTests,HoverCardFlushTests.Observed / Not run
Not built or run locally: Mac builds run on CI only. Local git on the build Mac was stuck in disk wait, so both commits were made through the GitHub API, and the local pre-push gate didn't run. CI is the first compile.
Changelog
Fixed: sidebar hover follows the pointer between rows, row highlights stop short of the edge, and a row's hover card no longer catches the pointer.
Agent session: cosmic-gray
🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need.Summary by cubic
Fixes sidebar hover in cmux-next so a pointer moving between workspace rows hands the hover to the row under it, instead of leaving the previous row lit and trapping the pointer.
Metrics.space4short of the sidebar's right edge, Chrome-style; headers get the same trim.Written for commit 52986bb. Summary will update on new commits.