fix(hig): show the resize cursor over SwiftUI-hosted split dividers#1908
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7f858f1c96
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| ? .columnResize(directions: [.left, .right]) | ||
| : .rowResize(directions: [.up, .down]) |
There was a problem hiding this comment.
Avoid SDK-only cursor APIs in Xcode 15 builds
When building with the documented Xcode 15/macOS 14 SDK, NSCursor.columnResize(directions:) and rowResize(directions:) are not declared, and the #available(macOS 15.0, *) runtime check does not prevent the compiler from resolving those symbols. Since README/CONTRIBUTING still advertise Xcode 15+ support, this makes the app fail to compile for a supported build environment; use the existing resizeLeftRight/resizeUpDown APIs or hide the newer symbols behind an SDK-safe shim.
Useful? React with 👍 / 👎.
Fixes #1905.
Problem
The split divider on the Users and Roles tab drags to resize but never changes the pointer to the resize cursor, so it does not look draggable.
AppKit's automatic divider cursor rides on the classic cursor-rects system, which does not fire once an
NSSplitViewis mounted inside anNSHostingController. Every tab-content split is hosted that way, several SwiftUI layers deep underMainSplitViewController.detailHosting. The window's own sidebar and inspector dividers show the cursor only becauseMainSplitViewControlleris the window'scontentViewControllerdirectly, with no SwiftUI host in between. Dragging still works because divider hit-testing is independent of cursor rects.#1872fixed a different layer (holding priority andfittingSizeso the divider could move at all) and never touched cursors, so it left this in place. The same bug affected four SwiftUI-hosted splits, not just Users and Roles.Fix
A shared component that every hosted split routes through, rather than a one-off patch:
ResizeCursorSplitView: NSSplitViewadds a key-window tracking area over a padded divider hit zone and sets the resize cursor inmouseMoved, the same hand-rolled approachSortableHeaderViewalready uses for column resize. It picksNSCursor.columnResize/rowResizeon macOS 15+ and falls back toresizeLeftRight/resizeUpDownon macOS 14.ResizeCursorSplitViewController: NSSplitViewControllerinstalls that split view inloadView().CollapsingSplitViewController(Users and Roles list/detail, the privilege editor, and Structure triggers),ServerDashboardSplitView, andQuerySplitViewnow use it.Divider hit-testing is a pure
SplitDividerCursorGeometryhelper so it is unit-tested without a live window.MainSplitViewController(native, already correct) is untouched. A new invariant in CLAUDE.md records why a hosted split needs the explicit cursor.Testing
swiftlint lint --strict: clean on the changed files.SplitDividerCursorGeometryTestscovering vertical and horizontal dividers, three-pane splits, collapsed panes, and point hit-testing. A live cursor-image assertion is not possible in headless CI, so the pure geometry is the tested boundary.https://claude.ai/code/session_01A5xT92pokfSFFYVjBgfnJP