fix(gestures): end drag/press from capture phase so child stopPropagation can't trap the gesture#3731
fix(gestures): end drag/press from capture phase so child stopPropagation can't trap the gesture#3731mattgperry wants to merge 1 commit into
Conversation
A descendant calling event.stopPropagation() in its own pointerup handler prevented the PanSession's window-level pointerup listener from firing, so the drag gesture never ended and the element kept following the cursor. Attach the gesture-ending pointer listeners in the capture phase so descendant stopPropagation() can no longer break gesture cleanup, and pass listener options through to removeEventListener so capture-phase listeners are removed correctly. The press gesture's end listeners are moved to the capture phase too, which keeps the drag-suppresses-tap ordering intact and makes press robust to the same issue. Fixes #2794 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Greptile SummaryThis PR fixes a bug where a child element calling
Confidence Score: 5/5Safe to merge — the change is surgical and well-tested, touching only the event-listener registration phase without altering any gesture logic. All three code changes are internally consistent: No files require special attention. Important Files Changed
Sequence DiagramsequenceDiagram
participant Child
participant Window (capture)
participant Window (bubble)
Note over Child,Window (bubble): Before fix — child stopPropagation breaks drag end
Child->>Window (bubble): pointerup bubbles up
Child--xWindow (bubble): stopPropagation() blocks window handler
Note over Window (bubble): handlePointerUp never runs → drag leaks
Note over Child,Window (bubble): After fix — capture phase fires before child handlers
Window (capture)->>Window (capture): handlePointerUp (capture) fires first
Note over Window (capture): Drag/press gesture ends correctly
Child->>Child: onPointerUp fires → stopPropagation()
Note over Child: Nothing left to block
Reviews (1): Last reviewed commit: "fix(gestures): end drag/press gestures f..." | Re-trigger Greptile |
Summary
Fixes #2794.
When a child of a
dragelement callsevent.stopPropagation()inside its ownonPointerUphandler, the drag gesture never ended — the element kept following the cursor until the next pointer interaction.Cause
PanSessionattaches itspointermove/pointerup/pointercancellisteners towindowin the bubble phase. A descendant callingstopPropagation()onpointerupstops the event before it reacheswindow, sohandlePointerUpnever runs, the session is never torn down, andpointermovekeeps dragging the element.Fix
PanSession: attach the gesture pointer listeners in the capture phase, so descendantstopPropagation()can no longer prevent the gesture from ending.addDomEvent: pass the listeneroptionstoremoveEventListener, otherwise capture-phase listeners are never removed (capture flag must match) and would leak.pressgesture: move its end (pointerup/pointercancel) listeners to the capture phase as well. This keeps the existing "a drag suppresses the tap" ordering intact (press still observesisDragActive()before the drag releases its lock) and makes the press/tap gesture robust to the samestopPropagationproblem (the issue's repro literally stops propagation onpointerup).The fix is internal only — no public API changes.
Test plan
dragelement whose child callsstopPropagation()inonPointerUp— assertsonDragEndfires. Verified it fails against the unfixed code and passes with the fix.yarn buildsucceeds.yarn test— full suite green (798 passed, 7 pre-existing skips).🤖 Generated with Claude Code