Skip to content

fix(board): show the hand cursor when panning with Space under any tool - #170

Merged
oesni merged 2 commits into
gosuda:mainfrom
scofe97:fix/board-space-cursor
Oct 22, 2026
Merged

oesni merged 2 commits into
gosuda:mainfrom
scofe97:fix/board-space-cursor

Conversation

@scofe97

@scofe97 scofe97 commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Problem

Holding Space and dragging pans the board with any tool, but the hand cursor only showed with the select and hand tools. .layer-dynamic.space and .layer-dynamic[data-tool=pen] have the same specificity, and the tool cursor rules came later in app.css, so crosshair or cell won. With the select tool over a resize or rotate handle, SelectTool.hover() sets an inline cursor, which beats any stylesheet rule.

Change

  • app.css: the Space (grab) and panning (grabbing) rules now come after the tool cursor rules.
  • app.js: Space keydown clears the inline cursor of .layer-dynamic.
  • tools/select.js: hover() does not set a handle cursor while Space is held.
  • testdata/cursor.test.mjs: tests for the select hover guard, for Space keydown clearing an inline handle cursor without a hover, and for the Space and panning rules being the last .layer-dynamic cursor rules in app.css. All three fail on main. Importing app.js starts the board, so the keydown test compiles App.key from the source.

The spec (board.md rule 8, board-TECH.md Pan row) defines Space+drag panning but not its cursor, so no spec change.

Verification

  • go test -count=1 ./internal/board/... passes; TestWebClient ran with Node 22.
  • On a local dev host serving these files, Chrome with synthetic key and pointer events, computed cursor of .layer-dynamic:
Tool Before Space held Space-drag Released
select default grab grabbing default
hand grab grab grabbing grab
sticky, text, shape, connector, pen, frame crosshair grab grabbing crosshair
eraser cell grab grabbing cell

Over a selected sticky's resize handle: nwse-resize, then grab with Space, then nwse-resize again after release and a pointer move. The image tool was skipped because it returns to select at once. Real keyboard and mouse input was not used.

Known limits

  • After Space is released over a select handle, the cursor is the default until the pointer moves.
  • setTool does not clear an inline cursor, and middle-button pan over a select handle keeps the handle cursor. Both predate this change.

Review

Design, implementation and testing were each reviewed by claude-sonnet-5-5 in fresh sessions (author claude-opus-5-5), with snapshots bound by the devreview helper. All verdicts were approve or accept with nonblocking follow-ups, and the approvals were carried to the rebased commit. The keydown test (01e8a92) was added after the bot review; claude-sonnet-5-5 accepted it and carried the implementation approval to that commit. The full task report with verbatim verdicts is local only.

The Space and panning cursor rules had the same specificity as the tool
cursor rules and came before them, so crosshair or cell won with the
sticky, text, shape, frame, connector, pen and eraser tools. Move them
after the tool rules. The select tool sets its handle cursor inline, so
Space now clears it and select's hover does not set it while Space is held.
@scofe97
scofe97 marked this pull request as ready for review October 21, 2026 15:33
@oesni

oesni commented Oct 22, 2026

Copy link
Copy Markdown
Collaborator

@gormes-agent review

@gormes-agent

gormes-agent Bot commented Oct 22, 2026

Copy link
Copy Markdown
Contributor

Review

No blocking code defects found in the four-file diff at 3c83a58c2e92541b480a3a1a7118889eab6aaecd against b8ffb4cd9125922b112ead1477973542ec2ede29.

The CSS ordering gives Space precedence over tool cursors and panning precedence over Space. Clearing the existing inline cursor on keydown handles a stationary pointer over a selection handle; the hover guard prevents subsequent pointer movement from reinstating it while Space is held.

Nonblocking test follow-up

internal/board/web/app.js:712 is not covered by the committed regression tests. Removing only d.style.cursor = '' would leave both new tests passing while bringing back the stationary-pointer/resize-handle bug until the pointer moves. Add a keydown regression starting with an inline handle cursor and assert it clears immediately, without a hover event. This is a coverage suggestion, not an observed defect in the current implementation.

Independently checked

  • node --test internal/board/web/testdata/*.test.mjs: 96 passed, 0 failed, 0 skipped, Node v26.11.1.
  • Both new cursor tests fail against the base commit when copied into a disposable base worktree, and pass at the reviewed head.
  • An isolated DOM-stub probe of the actual App.key method verified immediate inline-cursor clearing, Space state/class and preventDefault; additional SelectTool.hover calls verified suppression across resize/rotation/connector handles and restoration on a later hover after release.
  • git diff --check: passed. Reviewed checkout remained clean and at the same SHA after checks.

Limits

No browser computed-style or real keyboard/mouse validation was performed in this review. Go is not installed in this environment, so I did not independently repeat go test -count=1 ./internal/board/.... The earlier stage verdicts and rebase carry-forward evidence described in the PR are local-only and were not available to verify; this code review does not certify completion of those historical workflow gates. The documented release-until-pointer-move behavior and pre-existing middle-button/tool-switch inline-cursor issues are not treated as regressions introduced here.

No source changes or merge actions were made.

@oesni oesni left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

approve
Thanks for your first contribution :)
Could you take a look at the comments?

Removing the inline cursor reset in App.key left both cursor tests passing. The new test compiles App.key from app.js, because importing app.js starts the board, and checks that Space clears a handle cursor without a hover.
@scofe97

scofe97 commented Oct 22, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the review. Added 01e8a92: a regression test that starts with an inline handle cursor, sends a Space keydown without a hover, and checks that the cursor clears at once. Removing only d.style.cursor = '' now fails it. Importing app.js starts the board, so the test compiles App.key from the source.

@oesni
oesni merged commit a831c45 into gosuda:main Oct 22, 2026
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants