From d53e239b7b59ad0d86ef961e19342c80568fe02d Mon Sep 17 00:00:00 2001 From: rahim Date: Mon, 9 Mar 2026 13:14:28 -0700 Subject: [PATCH] fix(html): thumb edge alignment jump (#766) --- packages/core/src/dom/ui/slider.ts | 10 ++++++++++ packages/html/src/ui/slider/slider-element.ts | 1 + .../html/src/ui/time-slider/time-slider-element.ts | 1 + .../html/src/ui/volume-slider/volume-slider-element.ts | 1 + 4 files changed, 13 insertions(+) diff --git a/packages/core/src/dom/ui/slider.ts b/packages/core/src/dom/ui/slider.ts index 01383851..148c7586 100644 --- a/packages/core/src/dom/ui/slider.ts +++ b/packages/core/src/dom/ui/slider.ts @@ -36,6 +36,8 @@ export interface SliderOptions { onValueCommit?: ((percent: number) => void) | undefined; onDragStart?: (() => void) | undefined; onDragEnd?: (() => void) | undefined; + /** Called when the root element resizes (e.g. gains layout inside a popover). */ + onResize?: (() => void) | undefined; } export interface SliderRootProps { @@ -310,6 +312,13 @@ export function createSlider(options: SliderOptions): SliderApi { }; } + let resizeObserver: ResizeObserver | null = null; + + if (options.onResize) { + resizeObserver = new ResizeObserver(() => options.onResize!()); + resizeObserver.observe(options.getElement()); + } + const rootStyle: SliderRootStyle = { touchAction: 'none', userSelect: 'none' }; return { @@ -321,6 +330,7 @@ export function createSlider(options: SliderOptions): SliderApi { destroy() { if (abort.signal.aborted) return; abort.abort(); + resizeObserver?.disconnect(); releaseCapture(); cleanup(); }, diff --git a/packages/html/src/ui/slider/slider-element.ts b/packages/html/src/ui/slider/slider-element.ts index c4c93925..7b909173 100644 --- a/packages/html/src/ui/slider/slider-element.ts +++ b/packages/html/src/ui/slider/slider-element.ts @@ -75,6 +75,7 @@ export class SliderElement extends MediaElement { this.dispatchEvent(new CustomEvent('drag-end', { bubbles: true })); }, adjustPercent: (raw, thumbSize, trackSize) => this.#core.adjustPercentForAlignment(raw, thumbSize, trackSize), + onResize: () => this.requestUpdate(), }); applyElementProps(this, this.#slider.rootProps, { signal }); diff --git a/packages/html/src/ui/time-slider/time-slider-element.ts b/packages/html/src/ui/time-slider/time-slider-element.ts index cef467f7..d75d6247 100644 --- a/packages/html/src/ui/time-slider/time-slider-element.ts +++ b/packages/html/src/ui/time-slider/time-slider-element.ts @@ -80,6 +80,7 @@ export class TimeSliderElement extends MediaElement { this.dispatchEvent(new CustomEvent('drag-end', { bubbles: true })); }, adjustPercent: (raw, thumbSize, trackSize) => this.#core.adjustPercentForAlignment(raw, thumbSize, trackSize), + onResize: () => this.requestUpdate(), }); applyElementProps(this, this.#slider.rootProps, { signal }); diff --git a/packages/html/src/ui/volume-slider/volume-slider-element.ts b/packages/html/src/ui/volume-slider/volume-slider-element.ts index ea6a2954..f21c363d 100644 --- a/packages/html/src/ui/volume-slider/volume-slider-element.ts +++ b/packages/html/src/ui/volume-slider/volume-slider-element.ts @@ -76,6 +76,7 @@ export class VolumeSliderElement extends MediaElement { this.dispatchEvent(new CustomEvent('drag-end', { bubbles: true })); }, adjustPercent: (raw, thumbSize, trackSize) => this.#core.adjustPercentForAlignment(raw, thumbSize, trackSize), + onResize: () => this.requestUpdate(), }); applyElementProps(this, this.#slider.rootProps, { signal });