Skip to content

feat(canvas): quick ways past the canvas lock (#1130) - #1167

Open
probertson wants to merge 1 commit into
eneskirca:mainfrom
probertson:feat/canvas-lock-toggle
Open

probertson wants to merge 1 commit into
eneskirca:mainfrom
probertson:feat/canvas-lock-toggle

Conversation

@probertson

@probertson probertson commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Closes #1130.

The canvas lock is most useful left on, but moving the camera meant unlocking, panning and locking again. This adds two quick ways past it, and fixes a leak that made the lock not quite a lock.

1. ⌘+middle-drag pans the canvas, locked or not (Ctrl+middle-drag on Windows/Linux). It works anywhere on the canvas, including over a terminal; holding the modifier is what says "I meant to move the map". Plain middle-drag is unchanged in meaning: it pans when unlocked and does nothing when locked. React Flow's panOnDrag selects mouse buttons only, so this is the canvas's own pointer handler (lib/modifierPan.ts, same shape as the wheel-zoom handler). It cancels the pointerdown in the capture phase, so no mousedown reaches React Flow's drag/zoom or xterm, and swallows the trailing auxclick (Linux middle-click paste).

2. "Toggle canvas lock" shortcut (canvas.toggleLock, Canvas group in Settings → Keyboard Shortcuts). Like every canvas command, it doesn't fire while a terminal has the keyboard.

3. Fix: plain middle-drag leaked past the lock over nodes. React Flow's zoom filter (@xyflow/system createFilter) accepts a middle-button mousedown on a node, edge or selection before it reads panOnDrag, so turning panOnDrag off never stopped a middle-drag that started on a node. In practice:

Where the middle-drag starts (locked) Before After
Node header panned stays
Terminal hover guard (before the terminal takes the keyboard) panned stays
Terminal xterm area stayed (only because the #84 middle-click guard happened to stop the press), panned if middle-click paste is on stays
Empty canvas stayed stays

The commit that defined the lock (c6be32c5) records "locked, middle-drag does not pan" as verified, so this reads as an unnoticed library default rather than intended behavior. While locked, a bubble-phase listener on .react-flow__viewport stops a middle mousedown after the node has seen it, so tmux and the middle-click paste setting behave as before; only React Flow's listener on an ancestor is cut off.

Discoverability: the locked button's tooltip says "⌘+middle-drag still pans", and the ⌘/ shortcuts panel lists the gesture.

Question for review: should "Toggle canvas lock" have a default key? I shipped it unbound. My suggestion would be ⌘⇧K / Ctrl+Shift+K: nothing in the registry or the app menu uses it. ⌘⇧L reads better for "lock" but is the sessions sidebar's. Trackpad-only Mac users have no middle button, so for them the shortcut is the whole feature, which argues for a default.

How it was checked

  • New modifierPan.test.ts: the gesture predicate (⌘ on mac, Ctrl elsewhere, no extra modifiers), pan deltas, capture-phase cancel, auxclick swallowed, plain middle-drag left alone, and the locked guard (node still sees the press, React Flow doesn't; left/right untouched; removed on unlock). Registry test updated. npm run typecheck clean; src/renderer/lib, src/renderer/canvas, shortcuts panel and keybinding suites pass (3,922 tests).
  • In an isolated dev build with real CDP mouse input: the leak reproduced before the fix (locked + plain middle-drag on the hover guard panned) and not after, on the header and hover guard; locked ⌘+middle-drag panned on empty canvas, a header and a terminal; unlocked plain middle-drag still panned. The shortcut (bound to a test chord) toggled the lock both ways, and did nothing with a terminal focused.
  • Manually on macOS with a hardware mouse: works as expected.

Not checked: Windows/Linux Ctrl+middle-drag, and the Server Edition in a real browser. One behavior change to note: on Windows/Linux, a Ctrl+middle press over a terminal now pans instead of being passed to the terminal app.

🤖 Generated with Claude Code

…close the middle-drag leak

Issue eneskirca#1130. Three pieces:

- ⌘+middle-drag (Ctrl off-mac) pans the camera anywhere, locked or not — the explicit "move the
  map" gesture. Its own capture-phase pointer handler (React Flow's panOnDrag selects buttons
  only); cancelling the pointerdown keeps d3, d3-drag and xterm from seeing it.
- "Toggle canvas lock" (canvas.toggleLock) in the keybinding registry, shipped unbound; like
  every canvas command it does not fire while a terminal has the keyboard.
- The lock now really freezes a plain middle-drag: React Flow accepts a middle press on a node,
  edge or selection before reading panOnDrag, so a drag started on a node header or a terminal's
  hover guard panned past the lock. While locked, a bubble-phase listener on the viewport stops
  that press after the node has seen it.

The lock tooltip and the ⌘/ shortcuts panel mention the gesture.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.

Request: a way to quickly toggle the canvas lock off and on

1 participant