Files
Joseph c5741d5230 fix(devtools): handle pointercancel when dragging the indicator (#98506)
Fixes #98468

## Claude explanation of the fix

`useDrag` listened for `pointermove` and `pointerup`, but never
`pointercancel`.

When a user agent cancels a gesture — a browser or system gesture takes
over, a second finger arrives — it fires `pointercancel` and no
`pointerup`, implicitly releasing pointer capture as it does. So
`cancel()` never ran: the state machine stayed `{ state: 'drag' }` and
`cleanup.current` was never invoked, leaving the
`pointermove`/`pointerup` listeners on `window`.

The next `pointerup` anywhere on the page then hit those orphaned
listeners, reached `cancel()` with the state still `'drag'`, and called
`releasePointerCapture()` on a pointer that no longer existed — the
reported `NotFoundError`. Each cancelled drag also leaked another
listener pair.

This registers `pointercancel` alongside `pointerup` and removes it in
the same cleanup, so the machine unwinds when a gesture is cancelled;
and it releases pointer capture only when `hasPointerCapture()` says it
is still held, which is preferable to `try/catch` swallowing genuine
faults too.

Note `touch-action: none` (#97723) removed the common touch trigger, but
not the defect: on canary a forced `touchCancel` still throws.


https://github.com/user-attachments/assets/45a9524d-9ffa-40b6-b59a-5af9d947f8c7

## Fixed version


https://github.com/user-attachments/assets/b5ada68c-7442-42ef-a256-bacc512fbeca

## Browser checks

- [x] Chrome, as describe by the bug report
- [x] FF works fine pre and post fix (with and without the pointer
simulation)
- [x] iOS safari simulator, before the fix, I can't see an error, but,
the drag gets frozen, with this fix it works correctly


https://github.com/user-attachments/assets/bcfdc786-bada-4462-b530-299523fdca6d

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-11 16:01:14 +02:00
..