diff --git a/studio/frontend/src/components/ui/slider.tsx b/studio/frontend/src/components/ui/slider.tsx index 4a235e674d..5d75b88e6d 100644 --- a/studio/frontend/src/components/ui/slider.tsx +++ b/studio/frontend/src/components/ui/slider.tsx @@ -1,57 +1,94 @@ -import { Slider as SliderPrimitive } from "radix-ui"; -import * as React from "react"; - -import { cn } from "@/lib/utils"; - -function Slider({ - className, - defaultValue, - value, - min = 0, - max = 100, - ...props -}: React.ComponentProps) { - const _values = React.useMemo( - () => - Array.isArray(value) - ? value - : Array.isArray(defaultValue) - ? defaultValue - : [min, max], - [value, defaultValue, min, max], - ); - - return ( - - - - - {Array.from({ length: _values.length }, (_, index) => ( - - ))} - - ); -} - -export { Slider }; +import { Slider as SliderPrimitive } from "radix-ui"; +import * as React from "react"; + +import { cn } from "@/lib/utils"; + +function Slider({ + className, + defaultValue, + value, + min = 0, + max = 100, + orientation = "horizontal", + onValueChange, + ...props +}: React.ComponentProps) { + const isControlled = Array.isArray(value); + const [uncontrolledValues, setUncontrolledValues] = + React.useState(() => + Array.isArray(defaultValue) ? defaultValue : [min, max], + ); + + const values = isControlled ? value : uncontrolledValues; + const handleValueChange = React.useCallback( + (nextValues: number[]) => { + if (!isControlled) { + setUncontrolledValues(nextValues); + } + onValueChange?.(nextValues); + }, + [isControlled, onValueChange], + ); + + // For single-thumb horizontal sliders, render the fill bar as a sibling of + // the track (outside its overflow-hidden container) so it can align flush + // with the thumb center without being clipped. The Range inside the track + // is hidden in this case to avoid double-painting. + const isSingleThumbHorizontal = + values.length === 1 && orientation === "horizontal"; + const fillPercent = isSingleThumbHorizontal + ? Math.min( + 100, + Math.max( + 0, + max === min ? 0 : (((values[0] ?? min) - min) / (max - min)) * 100, + ), + ) + : null; + + return ( + + + + + {isSingleThumbHorizontal && ( +
+ )} + {Array.from({ length: values.length }, (_, index) => ( + + ))} + + ); +} + +export { Slider };