[ENG-1546] Relation creation via drag handles (Roam)#923
[ENG-1546] Relation creation via drag handles (Roam)#923trangdoan982 wants to merge 2 commits intomainfrom
Conversation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
This pull request has been ignored for the connected project Preview Branches by Supabase. |
| containerEl.addEventListener("pointermove", onPointerMove); | ||
| containerEl.addEventListener("pointerup", onPointerUp); |
There was a problem hiding this comment.
🔴 Missing pointer capture causes drag state to get permanently stuck when pointer leaves container
The handlePointerDown handler attaches pointermove and pointerup listeners to containerEl (the tldraw container) without calling setPointerCapture. If the user starts dragging a handle and moves the pointer outside the container boundary before releasing, the pointerup event never fires on containerEl, so onPointerUp never executes. This leaves isDragging = true permanently — the SVG drag line stays visible, the handles disappear, and there is no recovery mechanism (no Escape key handler during drag, no fallback timeout). The user must navigate away and back to restore the canvas.
The existing codebase consistently uses setPointerCapture for similar drag interactions: DiscourseToolPanel.tsx:211 calls target.setPointerCapture(e.pointerId), and Clipboard.tsx:772 does the same.
Prompt for agents
The drag handle overlay attaches pointermove/pointerup listeners to the tldraw container element but does not use setPointerCapture. This means if the pointer leaves the container during a drag and is released outside, the pointerup handler never fires, leaving isDragging=true permanently with no recovery path.
To fix this, follow the existing pattern used in DiscourseToolPanel.tsx (line 211) and Clipboard.tsx (line 772):
1. In handlePointerDown (DragHandleOverlay.tsx around line 124), after stopping propagation, call e.currentTarget.setPointerCapture(e.pointerId) (or use the nativeEvent to capture on the handle element).
2. In onPointerUp, call containerEl.releasePointerCapture(upEvent.pointerId) (or the captured element).
3. Alternatively, attach the pointermove/pointerup listeners to window/document instead of containerEl, which would also ensure events are received even when the pointer leaves the container. If using this approach, remember to remove the window listeners in cleanup.
4. As a belt-and-suspenders measure, consider adding a pointercancel handler that resets drag state, and/or a keydown handler for Escape during drag.
The key files involved are DragHandleOverlay.tsx (handlePointerDown callback, lines 119-243) and the existing pattern examples in DiscourseToolPanel.tsx (lines 208-211, 155-159) and Clipboard.tsx (lines 772, 734).
Was this helpful? React with 👍 or 👎 to provide feedback.
Summary
handleCreateRelationsInRoam(supports both stored/reified relations and legacy triple-based approach)Test plan
🤖 Generated with Claude Code