From 8b38903f0583e80ba6b56f83afb145046bd9933f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Gr=C3=A9lard?= Date: Tue, 12 Mar 2024 11:13:46 +0000 Subject: [PATCH] [Slider] Add ability to name each thumb for more flexibility (#2766) Fixes #2454 --- .yarn/versions/b20a66e3.yml | 5 +++ packages/react/slider/src/Slider.stories.tsx | 30 ++++++++++++++++-- packages/react/slider/src/Slider.tsx | 32 +++++++++++--------- 3 files changed, 51 insertions(+), 16 deletions(-) create mode 100644 .yarn/versions/b20a66e3.yml diff --git a/.yarn/versions/b20a66e3.yml b/.yarn/versions/b20a66e3.yml new file mode 100644 index 0000000000..a1a6a4eede --- /dev/null +++ b/.yarn/versions/b20a66e3.yml @@ -0,0 +1,5 @@ +releases: + "@radix-ui/react-slider": minor + +declined: + - primitives diff --git a/packages/react/slider/src/Slider.stories.tsx b/packages/react/slider/src/Slider.stories.tsx index 66b3d0e24f..529bcc78fe 100644 --- a/packages/react/slider/src/Slider.stories.tsx +++ b/packages/react/slider/src/Slider.stories.tsx @@ -262,10 +262,20 @@ export const SmallSteps = () => { }; export const WithinForm = () => { - const [data, setData] = React.useState({ single: [0], multiple: [10, 15, 20, 80] }); + const [data, setData] = React.useState({ + single: [0], + multiple: [10, 15, 20, 80], + price: { + min: 30, + max: 70, + }, + }); return (
event.preventDefault()} + onSubmit={(event) => { + event.preventDefault(); + console.log(serialize(event.currentTarget, { hash: true })); + }} onChange={(event) => { const formData = serialize(event.currentTarget, { hash: true }); setData(formData as any); @@ -296,6 +306,22 @@ export const WithinForm = () => { + +
+
+ +
+ Multiple values (with named thumbs): {JSON.stringify(data.price)} + + + + + + + +
+ + ); }; diff --git a/packages/react/slider/src/Slider.tsx b/packages/react/slider/src/Slider.tsx index 62751cf11f..69bab3511f 100644 --- a/packages/react/slider/src/Slider.tsx +++ b/packages/react/slider/src/Slider.tsx @@ -41,6 +41,7 @@ const [createSliderContext, createSliderScope] = createContextScope(SLIDER_NAME, ]); type SliderContextValue = { + name?: string; disabled?: boolean; min: number; max: number; @@ -90,13 +91,9 @@ const Slider = React.forwardRef( inverted = false, ...sliderProps } = props; - const [slider, setSlider] = React.useState(null); - const composedRefs = useComposedRefs(forwardedRef, (node) => setSlider(node)); const thumbRefs = React.useRef(new Set()); const valueIndexToChangeRef = React.useRef(0); const isHorizontal = orientation === 'horizontal'; - // We set this to true by default so that events bubble to forms without JS (SSR) - const isFormControl = slider ? Boolean(slider.closest('form')) : true; const SliderOrientation = isHorizontal ? SliderHorizontal : SliderVertical; const [values = [], setValues] = useControllableState({ @@ -147,6 +144,7 @@ const Slider = React.forwardRef( return ( ( aria-disabled={disabled} data-disabled={disabled ? '' : undefined} {...sliderProps} - ref={composedRefs} + ref={forwardedRef} onPointerDown={composeEventHandlers(sliderProps.onPointerDown, () => { if (!disabled) valuesBeforeSlideStartRef.current = values; })} @@ -189,14 +187,6 @@ const Slider = React.forwardRef( /> - {isFormControl && - values.map((value, index) => ( - 1 ? '[]' : '') : undefined} - value={value} - /> - ))} ); } @@ -556,15 +546,18 @@ const SliderThumb = React.forwardRef( type SliderThumbImplElement = React.ElementRef; interface SliderThumbImplProps extends PrimitiveSpanProps { index: number; + name?: string; } const SliderThumbImpl = React.forwardRef( (props: ScopedProps, forwardedRef) => { - const { __scopeSlider, index, ...thumbProps } = props; + const { __scopeSlider, index, name, ...thumbProps } = props; const context = useSliderContext(THUMB_NAME, __scopeSlider); const orientation = useSliderOrientationContext(THUMB_NAME, __scopeSlider); const [thumb, setThumb] = React.useState(null); const composedRefs = useComposedRefs(forwardedRef, (node) => setThumb(node)); + // We set this to true by default so that events bubble to forms without JS (SSR) + const isFormControl = thumb ? Boolean(thumb.closest('form')) : true; const size = useSize(thumb); // We cast because index could be `-1` which would return undefined const value = context.values[index] as number | undefined; @@ -618,6 +611,17 @@ const SliderThumbImpl = React.forwardRef + + {isFormControl && ( + 1 ? '[]' : '') : undefined) + } + value={value} + /> + )} ); }