🦄 One callback per frame, when you needed one per gesture

A draggable window had a callback for "the position changed". Sounds like enough. It isn't, and it took someone else's release notes to make me see why.

Mantine core shipped onResizeStart and onResizeEnd on its own floating window, and reading that against my API made the gap obvious: my Window reported that it moved, on every single frame, and never that a gesture had begun or finished. Every consumer who wanted to save a layout was debouncing by hand.

adds the four missing edges: onDragStart, onDragEnd, onResizeStart, onResizeEnd.

The demo in the docs counts both kinds of write side by side while you drag. Driving one drag and one resize in Chrome, I measured 20 continuous calls against 2 lifecycle calls — and that was with scripted pointer moves, so a real hand on a real mouse fires far more. That ratio is the whole argument, and it is why "save on change" quietly means "write to storage on every frame" unless someone hands you an edge to hook.

What the edges buy you: persist once when the user lets go; pause a chart, an iframe or a video while a drag is running and resume after; show a snap guide only during the gesture; record one undo entry per gesture instead of one per pixel.

One thing that was harder than the API sketch suggested. The global mouseup listener ended both gestures at once, so a naive implementation emitted an onDragEnd every time you merely resized — an end with no start, which is exactly the bug that leaves a consumer's paused chart paused forever. Each hook now checks its own in-flight state. I only trust the test that covers it because I deleted the guard and watched it fail: Expected 0, Received 1. A test you have never seen fail is a decoration.

Same reflex for the feature itself: jsdom said it worked, so I drove a real drag in Chrome with real pointer events before believing it.

If you build draggable panels or a windowed layout, I would like to know which of the four you actually reach for — my guess is onDragEnd does most of the work and the two start callbacks matter only when there is something expensive to pause. Curious whether that holds outside my own head.

Docs and live demo:

npm:

GitHub:

7 views

Add a comment

Replies

Be the first to comment