fix(html): slider interaction and edge alignment broken (#721)

This commit is contained in:
rahim
2026-03-04 21:13:37 -08:00
committed by GitHub
parent 7548a8e4a1
commit ff12296355
13 changed files with 126 additions and 25 deletions
+3 -17
View File
@@ -72,6 +72,7 @@ export function useSlider<State extends SliderState = SliderState>(
getStepPercent: () => optionsRef.current.getStepPercent(),
getLargeStepPercent: () => optionsRef.current.getLargeStepPercent(),
commitThrottle: optionsRef.current.commitThrottle,
adjustPercent: optionsRef.current.adjustPercent,
onValueChange: (percent) => optionsRef.current.onValueChange?.(percent),
onValueCommit: (percent) => optionsRef.current.onValueCommit?.(percent),
onDragStart: () => optionsRef.current.onDragStart?.(),
@@ -98,23 +99,8 @@ export function useSlider<State extends SliderState = SliderState>(
}
}, [state.thumbAlignment]);
// Adjust CSS var percents for edge thumb alignment when DOM elements are available.
const rootEl = rootElementRef.current;
const thumbEl = thumbElementRef.current;
let cssState = state;
if (state.thumbAlignment === 'edge' && rootEl && thumbEl && options.adjustPercent) {
const isHorizontal = state.orientation === 'horizontal';
const thumbSize = isHorizontal ? thumbEl.offsetWidth : thumbEl.offsetHeight;
const trackSize = isHorizontal ? rootEl.offsetWidth : rootEl.offsetHeight;
cssState = {
...state,
fillPercent: options.adjustPercent(state.fillPercent, thumbSize, trackSize),
pointerPercent: options.adjustPercent(state.pointerPercent, thumbSize, trackSize),
};
}
const cssVars = options.getCSSVars(cssState);
// Adjust CSS var percents for edge thumb alignment using live DOM measurements.
const cssVars = options.getCSSVars(slider.adjustForAlignment(state));
// Ref callbacks for root and thumb elements.
const rootRef = useCallback((element: HTMLElement | null) => {
@@ -36,6 +36,7 @@ const { mockSliderApi } = vi.hoisted(() => ({
onFocus: vi.fn(),
onBlur: vi.fn(),
},
adjustForAlignment: <S,>(state: S): S => state,
destroy: vi.fn(),
}),
}));
@@ -27,6 +27,7 @@ const { mockSliderApi, mockThumbnailApi } = vi.hoisted(() => ({
onFocus: vi.fn(),
onBlur: vi.fn(),
},
adjustForAlignment: <S,>(state: S): S => state,
destroy: vi.fn(),
}),
mockThumbnailApi: () => ({
@@ -10,7 +10,11 @@ import { SliderTrack } from '../slider-track';
import { SliderValue } from '../slider-value';
const { mockSliderApi } = vi.hoisted(() => ({
mockSliderApi: () => ({
mockSliderApi: (options?: {
getElement?: () => HTMLElement;
getThumbElement?: () => HTMLElement | null;
adjustPercent?: (raw: number, thumb: number, track: number) => number;
}) => ({
input: {
current: {
pointerPercent: 0,
@@ -31,6 +35,22 @@ const { mockSliderApi } = vi.hoisted(() => ({
onFocus: vi.fn(),
onBlur: vi.fn(),
},
adjustForAlignment<
S extends { thumbAlignment?: string; orientation?: string; fillPercent: number; pointerPercent: number },
>(state: S): S {
if (!options?.adjustPercent || state.thumbAlignment !== 'edge') return state;
const thumbEl = options.getThumbElement?.();
if (!thumbEl) return state;
const rootEl = options.getElement!();
const isHorizontal = state.orientation === 'horizontal';
const thumbSize = isHorizontal ? thumbEl.offsetWidth : thumbEl.offsetHeight;
const trackSize = isHorizontal ? rootEl.offsetWidth : rootEl.offsetHeight;
return {
...state,
fillPercent: options.adjustPercent(state.fillPercent, thumbSize, trackSize),
pointerPercent: options.adjustPercent(state.pointerPercent, thumbSize, trackSize),
};
},
destroy: vi.fn(),
}),
}));
@@ -34,6 +34,7 @@ const { mockSliderApi, mockTimeState, mockBufferState } = vi.hoisted(() => ({
onFocus: vi.fn(),
onBlur: vi.fn(),
},
adjustForAlignment: <S,>(state: S): S => state,
destroy: vi.fn(),
}),
mockTimeState: {
@@ -33,6 +33,7 @@ const { mockSliderApi, mockVolumeState } = vi.hoisted(() => ({
onFocus: vi.fn(),
onBlur: vi.fn(),
},
adjustForAlignment: <S,>(state: S): S => state,
destroy: vi.fn(),
}),
mockVolumeState: {