Skip to content

fix(visx-drag): reset drag state on pointercancel - #2030

Open
ankit1324 wants to merge 1 commit into
airbnb:masterfrom
ankit1324:fix/drag-pointercancel
Open

fix(visx-drag): reset drag state on pointercancel#2030
ankit1324 wants to merge 1 commit into
airbnb:masterfrom
ankit1324:fix/drag-pointercancel

Conversation

@ankit1324

Copy link
Copy Markdown

Closes #2029

Problem

useDrag exposes only dragStart/dragMove/dragEnd, wired to onPointerDown/onPointerMove/onPointerUp. Per the Pointer Events spec the browser fires pointercancel instead of pointerup when it can no longer generate events for an in-progress pointer — most commonly on touch, when the browser's own gesture arbitration decides the drag is really a page scroll.

When that happens dragEnd never runs, so isDragging stays true and dx/dy stay stale until the user starts and completes a whole new drag. No onDragEnd fires either, so consumers holding their own "currently dragging" state stay stuck too.

Changes

  • useDrag: new dragCancel handler that ends the drag, plus an optional onDragCancel callback. When onDragCancel isn't provided it falls back to onDragEnd, so existing consumers keep getting an end-of-drag signal and nothing changes for them.
  • Drag: wires onPointerCancel on the captureDragArea rect.
  • visx-brush: BaseBrush, BrushSelection, BrushHandle and BrushCorner each bind dragEnd to onPointerUp on their own elements, so they were left in the same stuck state that the issue calls out for BaseBrush. Each now also binds dragCancel to onPointerCancel, and BrushOverlay gained the matching prop (it spreads onto Bar, so no other change was needed).

This mirrors the fix @vueuse/core made for the identical gap in useDraggable (vueuse/vueuse#5550), referenced in the issue.

Tests

Two new cases in packages/visx-drag/test/useDrag.test.tsx:

  • a cancelled drag resets isDragging (the reported bug);
  • onDragCancel is invoked on cancel, and consumers that only pass onDragEnd still get called.

Both are genuine regression tests — with the cancel path removed they fail with expected true to be false (the stuck isDragging) and expected "vi.fn()" to be called 1 times, but got 0 times.

yarn vitest run packages/visx-drag packages/visx-brush → 6 files, 15 tests passing. yarn build (babel + tsc --build) clean, and lint on both packages is back to the repo's pre-existing baseline.

useDrag only exposed dragStart/dragMove/dragEnd, wired to pointerdown/
pointermove/pointerup. The browser fires pointercancel instead of
pointerup when it takes over an in-progress gesture, most commonly on
touch when scroll arbitration wins, so dragEnd never ran: isDragging
stayed true and dx/dy stayed stale until a whole new drag completed.

Add a dragCancel handler that ends the drag, wire it to onPointerCancel
in Drag's capture rect, and add an optional onDragCancel callback that
falls back to onDragEnd so existing consumers still get an end-of-drag
signal. Wire the same handler through visx-brush, whose overlay,
selection, handles and corners each bind dragEnd to pointerup and were
left in the same stuck state.

Closes airbnb#2029
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.

useDrag/Drag: isDragging never resets on pointercancel, only pointerup (affects BaseBrush too)

1 participant