[scroll area] End thumb drag when the primary button is no longer held - #5374
Conversation
commit: |
Bundle size
PerformanceTotal duration: 1,245.23 ms -90.20 ms(-6.8%) | Renders: 78 (+0) | Paint: 1,970.27 ms -135.69 ms(-6.4%) No significant changes — details Check out the code infra dashboard for more information about this PR. |
✅ Deploy Preview for base-ui ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
655d2d3 to
61ef255
Compare
|
@claude review |
PR reviewThe fix is sound and well-tested: the Bugs (2)1. 🟡 Buttonless move from a different pointer hard-cancels an active dragLocation: if (event.buttons % 2 === 0) {
handlePointerUp(event);
return;
}The guard never compares The base code also mishandled this input, but as a transient jump the next real move corrected — the guard converts it into an un-self-correcting cancellation. Failure scenario: On a touchscreen laptop, the user touch-drags the vertical thumb while the mouse cursor gets nudged across it (or a hovering pen passes over it during a mouse drag) — the drag dies mid-gesture. Fix: Record the dragging 2. ℹ️ Synthetic release skips the thumb's immediate
|
Fixes #5371
Dragging the thumb latches an internal drag flag that only a
pointerup/pointercancelreaching the thumb or scrollbar clears. When pointer capture is lost mid-drag, the release is delivered to whatever element is under the cursor instead, so the flag survives the gesture and the next buttonless hover over the thumb drags it along with the cursor (the drag's scroll-snap disable also leaks).handlePointerMovenow treats a move without the primary button held as the missed release and runs the fullpointerupcleanup. This mirrors the existing defense inuseSwipeDismiss, which ends the gesture onbuttons: 0moves with the same "the gesture is over even if no pointerup reached us" reasoning, and the equivalent guard inSliderControl; nothing in the codebase relies onlostpointercapturefor this.buttons % 2follows thehasPrimaryMouseButtonidiom sinceno-bitwiseis enforced.The regression test is Chromium-only because the drag math reads logical properties through
getComputedStyle, which jsdom reports as empty strings. Existing rawfireEvent.pointerMovedrag simulations now passbuttons: 1, matching real held-button moves.