Let the slider keep the drag the browser wanted to take

Dragging the brightness slider on the wall panel set the handle and
published nothing; tapping a point on the track worked. The control is a
native range input laid transparent over the drawn track, and only the
release publishes — but the input never said the drag was its own. On a
touch panel a sideways swipe is a pan, or a back-navigation, so the
browser took the pointer over mid-drag and ended it in `pointercancel`.
The value had followed the finger and was never sent.

`touch-action: none`, as the colour disk beside it has always had. The
release also answers `pointercancel` and `lostpointercapture` now, which
covers a mouse let go outside the input and leaves no way for a draft to
sit there unpublished.

Two checks: a drag across the track reaches the engine, and the input
still owns its gesture. The second fails against a build without the
CSS, which is what makes it worth having.
This commit is contained in:
2026-08-26 13:32:22 +02:00
parent cea4c1b7d0
commit 8073a72ad7
3 changed files with 158 additions and 0 deletions
@@ -203,6 +203,13 @@ export function useSliderDrag({
onChange: (event: React.ChangeEvent<HTMLInputElement>) =>
setDraft(Number(event.target.value)),
onPointerUp: release,
// A drag can end without a `pointerup` on this element: the browser can
// claim the gesture and cancel the pointer, and a mouse released outside
// the input reports the release elsewhere. Either way the draft would sit
// there unpublished, showing a value nobody was ever sent. `release`
// ignores a second call, so overlapping ends are free.
onPointerCancel: release,
onLostPointerCapture: release,
onKeyUp: release,
onBlur: release,
},
@@ -250,6 +250,13 @@
background: none;
opacity: 0;
cursor: pointer;
/* The drag is the control, so the browser may not read it as a gesture of
its own. Without this a sideways swipe on a touch panel is a pan — or a
back-navigation — and the browser takes the pointer over mid-drag, which
ends the drag in `pointercancel` rather than `pointerup`. The value
followed the finger and was never published. Same reason `.dui-disc`
has it. */
touch-action: none;
}
.dui-slider[data-orientation="vertical"] .dui-slider-input {