diff --git a/packages/react/src/slider/control/SliderControl.test.tsx b/packages/react/src/slider/control/SliderControl.test.tsx index 1541e8648b..aac7cb0ac6 100644 --- a/packages/react/src/slider/control/SliderControl.test.tsx +++ b/packages/react/src/slider/control/SliderControl.test.tsx @@ -6,7 +6,7 @@ import { NOOP } from '../../utils/noop'; const testRootContext: SliderRootContext = { active: -1, - handleInputChange: NOOP, + commitValue: NOOP, dragging: false, disabled: false, getFingerState: () => ({ @@ -15,7 +15,7 @@ const testRootContext: SliderRootContext = { percentageValues: [0], thumbIndex: 0, }), - setValue: NOOP, + handleInputChange: NOOP, largeStep: 10, lastChangedValueRef: { current: null }, thumbMap: new Map(), @@ -23,7 +23,6 @@ const testRootContext: SliderRootContext = { min: 0, minStepsBetweenValues: 0, name: '', - onValueCommitted: NOOP, orientation: 'horizontal', state: { activeThumbIndex: -1, @@ -47,6 +46,7 @@ const testRootContext: SliderRootContext = { setDragging: NOOP, setPercentageValues: NOOP, setThumbMap: NOOP, + setValue: NOOP, step: 1, tabIndex: null, thumbRefs: { current: [] }, diff --git a/packages/react/src/slider/control/SliderControl.tsx b/packages/react/src/slider/control/SliderControl.tsx index 924072a8ba..88c37f50e4 100644 --- a/packages/react/src/slider/control/SliderControl.tsx +++ b/packages/react/src/slider/control/SliderControl.tsx @@ -21,12 +21,12 @@ const SliderControl = React.forwardRef(function SliderControl( const { render: renderProp, className, ...otherProps } = props; const { + commitValue, disabled, dragging, getFingerState, lastChangedValueRef, minStepsBetweenValues, - onValueCommitted, percentageValues, registerSliderControl, setActive, @@ -38,12 +38,12 @@ const SliderControl = React.forwardRef(function SliderControl( } = useSliderRootContext(); const { getRootProps } = useSliderControl({ + commitValue, disabled, dragging, getFingerState, lastChangedValueRef, minStepsBetweenValues, - onValueCommitted, percentageValues, registerSliderControl, rootRef: forwardedRef, diff --git a/packages/react/src/slider/control/useSliderControl.ts b/packages/react/src/slider/control/useSliderControl.ts index a2b38bbe6a..fe4939adfc 100644 --- a/packages/react/src/slider/control/useSliderControl.ts +++ b/packages/react/src/slider/control/useSliderControl.ts @@ -51,7 +51,7 @@ export function useSliderControl( getFingerState, lastChangedValueRef, minStepsBetweenValues, - onValueCommitted, + commitValue, percentageValues, registerSliderControl, rootRef: externalRef, @@ -128,11 +128,9 @@ export function useSliderControl( setActive(-1); commitValidation(lastChangedValueRef.current ?? finger.value); - - onValueCommitted(lastChangedValueRef.current ?? finger.value, nativeEvent); + commitValue(lastChangedValueRef.current ?? finger.value, nativeEvent); touchIdRef.current = null; - // eslint-disable-next-line @typescript-eslint/no-use-before-define stopListening(); }); @@ -280,7 +278,7 @@ export namespace useSliderControl { | 'getFingerState' | 'lastChangedValueRef' | 'minStepsBetweenValues' - | 'onValueCommitted' + | 'commitValue' | 'percentageValues' | 'registerSliderControl' | 'setActive' diff --git a/packages/react/src/slider/indicator/SliderIndicator.test.tsx b/packages/react/src/slider/indicator/SliderIndicator.test.tsx index b526120ccf..1e6dd8781e 100644 --- a/packages/react/src/slider/indicator/SliderIndicator.test.tsx +++ b/packages/react/src/slider/indicator/SliderIndicator.test.tsx @@ -6,7 +6,7 @@ import { NOOP } from '../../utils/noop'; const testRootContext: SliderRootContext = { active: -1, - handleInputChange: NOOP, + commitValue: NOOP, dragging: false, disabled: false, getFingerState: () => ({ @@ -15,7 +15,7 @@ const testRootContext: SliderRootContext = { percentageValues: [0], thumbIndex: 0, }), - setValue: NOOP, + handleInputChange: NOOP, largeStep: 10, lastChangedValueRef: { current: null }, thumbMap: new Map(), @@ -23,7 +23,6 @@ const testRootContext: SliderRootContext = { min: 0, minStepsBetweenValues: 0, name: '', - onValueCommitted: NOOP, orientation: 'horizontal', state: { activeThumbIndex: -1, @@ -47,6 +46,7 @@ const testRootContext: SliderRootContext = { setDragging: NOOP, setPercentageValues: NOOP, setThumbMap: NOOP, + setValue: NOOP, step: 1, tabIndex: null, thumbRefs: { current: [] }, diff --git a/packages/react/src/slider/root/useSliderRoot.ts b/packages/react/src/slider/root/useSliderRoot.ts index e667f9f939..4bcdb6e744 100644 --- a/packages/react/src/slider/root/useSliderRoot.ts +++ b/packages/react/src/slider/root/useSliderRoot.ts @@ -5,6 +5,7 @@ import { areArraysEqual } from '../../utils/areArraysEqual'; import { clamp } from '../../utils/clamp'; import { mergeReactProps } from '../../utils/mergeReactProps'; import { ownerDocument } from '../../utils/owner'; +import type { GenericHTMLProps } from '../../utils/types'; import { useControlled } from '../../utils/useControlled'; import { useEnhancedEffect } from '../../utils/useEnhancedEffect'; import { useEventCallback } from '../../utils/useEventCallback'; @@ -233,8 +234,22 @@ export function useSliderRoot(parameters: useSliderRoot.Parameters): useSliderRo }, ); + // for pointer drag only + const commitValue = useEventCallback((value: number | readonly number[], event: Event) => { + if (Array.isArray(value)) { + const newPercentageValues = []; + for (let i = 0; i < value.length; i += 1) { + newPercentageValues.push(valueToPercent(value[i], min, max)); + } + } else if (typeof value === 'number') { + setPercentageValues([valueToPercent(value, min, max)]); + } + onValueCommitted(value, event); + }); + const handleRootRef = useForkRef(rootRef, sliderRef); + // for keypresses only const handleInputChange = useEventCallback( (valueInput: number, index: number, event: React.KeyboardEvent | React.ChangeEvent) => { const newValue = getSliderValue(valueInput, index, min, max, range, values); @@ -375,12 +390,13 @@ export function useSliderRoot(parameters: useSliderRoot.Parameters): useSliderRo return React.useMemo( () => ({ - getRootProps, 'aria-labelledby': ariaLabelledby, active, + commitValue, disabled, dragging, getFingerState, + getRootProps, handleInputChange, largeStep, lastChangedValueRef, @@ -404,12 +420,13 @@ export function useSliderRoot(parameters: useSliderRoot.Parameters): useSliderRo values, }), [ - getRootProps, active, ariaLabelledby, + commitValue, disabled, dragging, getFingerState, + getRootProps, handleInputChange, largeStep, lastChangedValueRef, @@ -535,19 +552,15 @@ export namespace useSliderRoot { } export interface ReturnValue { - getRootProps: ( - externalProps?: React.ComponentPropsWithRef<'div'>, - ) => React.ComponentPropsWithRef<'div'>; /** * The index of the active thumb. */ active: number; 'aria-labelledby'?: string; - handleInputChange: ( - valueInput: number, - index: number, - event: React.KeyboardEvent | React.ChangeEvent, - ) => void; + /** + * Callback fired when drag ends and invokes onValueCommitted. + */ + commitValue: (newValue: number | readonly number[], event: Event) => void; dragging: boolean; disabled: boolean; getFingerState: ( @@ -555,14 +568,11 @@ export namespace useSliderRoot { shouldCaptureThumbIndex?: boolean, offset?: number, ) => FingerState | null; - /** - * Callback to invoke change handlers after internal value state is updated. - */ - setValue: ( - newValue: number | number[], - newPercentageValues: readonly number[], - activeThumb: number, - event: Event, + getRootProps: (externalProps?: GenericHTMLProps) => GenericHTMLProps; + handleInputChange: ( + valueInput: number, + index: number, + event: React.KeyboardEvent | React.ChangeEvent, ) => void; /** * The large step value of the slider when incrementing or decrementing while the shift key is held, @@ -584,23 +594,31 @@ export namespace useSliderRoot { */ minStepsBetweenValues: number; name: string; - onValueCommitted: (value: number | readonly number[], event: Event) => void; /** * The component orientation. * @default 'horizontal' */ orientation: Orientation; - registerSliderControl: (element: HTMLElement | null) => void; /** * The value(s) of the slider as percentages */ percentageValues: readonly number[]; + registerSliderControl: (element: HTMLElement | null) => void; setActive: React.Dispatch>; setDragging: React.Dispatch>; setPercentageValues: React.Dispatch>; setThumbMap: React.Dispatch< React.SetStateAction | null>> >; + /** + * Callback fired when dragging and invokes onValueChange. + */ + setValue: ( + newValue: number | number[], + newPercentageValues: readonly number[], + activeThumb: number, + event: Event, + ) => void; /** * The step increment of the slider when incrementing or decrementing. It will snap * to multiples of this value. Decimal values are supported. diff --git a/packages/react/src/slider/thumb/SliderThumb.test.tsx b/packages/react/src/slider/thumb/SliderThumb.test.tsx index ee524d2e5f..ae40617d53 100644 --- a/packages/react/src/slider/thumb/SliderThumb.test.tsx +++ b/packages/react/src/slider/thumb/SliderThumb.test.tsx @@ -35,7 +35,7 @@ function createTouches(touches: Touches) { const testRootContext: SliderRootContext = { active: -1, - handleInputChange: NOOP, + commitValue: NOOP, dragging: false, disabled: false, getFingerState: () => ({ @@ -44,7 +44,7 @@ const testRootContext: SliderRootContext = { percentageValues: [0], thumbIndex: 0, }), - setValue: NOOP, + handleInputChange: NOOP, largeStep: 10, lastChangedValueRef: { current: null }, thumbMap: new Map(), @@ -52,7 +52,6 @@ const testRootContext: SliderRootContext = { min: 0, minStepsBetweenValues: 0, name: '', - onValueCommitted: NOOP, orientation: 'horizontal', state: { activeThumbIndex: -1, @@ -76,6 +75,7 @@ const testRootContext: SliderRootContext = { setDragging: NOOP, setPercentageValues: NOOP, setThumbMap: NOOP, + setValue: NOOP, step: 1, tabIndex: null, thumbRefs: { current: [] }, diff --git a/packages/react/src/slider/track/SliderTrack.test.tsx b/packages/react/src/slider/track/SliderTrack.test.tsx index 19be29b312..c7e2d5db5e 100644 --- a/packages/react/src/slider/track/SliderTrack.test.tsx +++ b/packages/react/src/slider/track/SliderTrack.test.tsx @@ -6,7 +6,7 @@ import { NOOP } from '../../utils/noop'; const testRootContext: SliderRootContext = { active: -1, - handleInputChange: NOOP, + commitValue: NOOP, dragging: false, disabled: false, getFingerState: () => ({ @@ -15,7 +15,7 @@ const testRootContext: SliderRootContext = { percentageValues: [0], thumbIndex: 0, }), - setValue: NOOP, + handleInputChange: NOOP, largeStep: 10, lastChangedValueRef: { current: null }, thumbMap: new Map(), @@ -23,7 +23,6 @@ const testRootContext: SliderRootContext = { min: 0, minStepsBetweenValues: 0, name: '', - onValueCommitted: NOOP, orientation: 'horizontal', state: { activeThumbIndex: -1, @@ -47,6 +46,7 @@ const testRootContext: SliderRootContext = { setDragging: NOOP, setPercentageValues: NOOP, setThumbMap: NOOP, + setValue: NOOP, step: 1, tabIndex: null, thumbRefs: { current: [] }, diff --git a/packages/react/src/slider/value/SliderValue.test.tsx b/packages/react/src/slider/value/SliderValue.test.tsx index dcce0fc724..30fe947bc1 100644 --- a/packages/react/src/slider/value/SliderValue.test.tsx +++ b/packages/react/src/slider/value/SliderValue.test.tsx @@ -8,7 +8,7 @@ import { NOOP } from '../../utils/noop'; const testRootContext: SliderRootContext = { active: -1, - handleInputChange: NOOP, + commitValue: NOOP, dragging: false, disabled: false, getFingerState: () => ({ @@ -17,7 +17,7 @@ const testRootContext: SliderRootContext = { percentageValues: [0], thumbIndex: 0, }), - setValue: NOOP, + handleInputChange: NOOP, largeStep: 10, lastChangedValueRef: { current: null }, thumbMap: new Map(), @@ -25,7 +25,6 @@ const testRootContext: SliderRootContext = { min: 0, minStepsBetweenValues: 0, name: '', - onValueCommitted: NOOP, orientation: 'horizontal', state: { activeThumbIndex: -1, @@ -49,6 +48,7 @@ const testRootContext: SliderRootContext = { setDragging: NOOP, setPercentageValues: NOOP, setThumbMap: NOOP, + setValue: NOOP, step: 1, tabIndex: null, thumbRefs: { current: [] },