Files
Gabriel Vidal 439f2bf3a6 fix(ui): make HoldEditable's drag survive on touch, and hold work with a mouse
Two bugs, reproduced in a real browser before fixing.

**The drag died on the first hand-over (touch).** Reordering the list live
meant React moved the pressed wrapper node — losing the pointer capture — and
re-rendered whichever item now occupied a position-dependent slot; the navbar's
raised centre tab is a structurally different <a>, so the very anchor the finger
went down on got unmounted. A browser cancels the touch whose target left the
document, so the drag was cancelled and the order snapped back. Traced with a
MutationObserver alongside the pointer events: reorder → lostpointercapture →
anchor remount → pointercancel.

The DOM order is now frozen for the whole drag and the rearrangement is
expressed purely as transforms, computed from slot geometry measured once at
pickup; only the drop commits a real reorder, after the pointer is gone. The
held item's invisible in-slot copy also keeps rendering with its pre-pickup
props so its node is never replaced. Nothing in the DOM moves, so nothing can
cancel the gesture.

That also removes the FLIP bookkeeping wholesale: with the geometry fixed, no
re-measuring, no settle timers and no animation lock, and a fast drag can no
longer outrun the shuffle. The layout model reflows from each item's own size
and the original gaps, so a list of unequal items (an expanded shortcut card
among collapsed ones) lands correctly.

**Hold-to-pick-up never fired with a mouse.** Any travel over 10px during the
1.4s cancelled the hold — but a hand resting on a mouse drifts well past that,
so on desktop the pickup essentially never happened. Travel now only cancels
for touch and pen, where it means "I'm scrolling"; a mouse can't scroll with the
button held. The pickup uses the pointer's current position rather than where it
went down, so the item doesn't jump out from under a drifted cursor.

Also: the slot hand-over threshold sits just short of the midpoint, so aiming at
the middle of the item you want reliably takes that slot instead of being a coin
flip that left the item one short.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-08 23:31:01 +02:00
..