"use client"; import * as React from "react"; import * as SliderPrimitive from "@radix-ui/react-slider"; import { Input } from "./input"; import { cn } from "@/src/utils/tailwind"; export interface SliderProps extends React.ComponentPropsWithoutRef { showInput?: boolean; displayAsPercentage?: boolean; decimalPlaces?: number; onValueChange?: (value: number[]) => void; } const Slider = React.forwardRef< React.ElementRef, SliderProps >( ( { className, showInput, displayAsPercentage, decimalPlaces = 2, ...props }, ref, ) => { const [inputValue, setInputValue] = React.useState(""); // Calculate display value based on the first slider value React.useEffect(() => { if (props.value && props.value.length > 0) { const value = props.value[0]; if (value === undefined || value === null) return; if (displayAsPercentage) { setInputValue((value * 100).toFixed(decimalPlaces)); } else { setInputValue(value.toString()); } } }, [props.value, displayAsPercentage, decimalPlaces]); const handleInputChange = (e: React.ChangeEvent) => { const newValue = e.target.value; setInputValue(newValue); }; const handleInputBlur = () => { let newVal = parseFloat(inputValue); if (isNaN(newVal)) { // Reset to current value if invalid input if (props.value && props.value.length > 0) { const value = props.value[0]; if (value === undefined || value === null) return; if (displayAsPercentage) { setInputValue((value * 100).toFixed(decimalPlaces)); } else { setInputValue(value.toString()); } } return; } // Convert percentage input back to decimal for the slider if (displayAsPercentage) { newVal = newVal / 100; } // Clamp value to min/max const min = props.min ?? 0; const max = props.max ?? 100; newVal = Math.max(min, Math.min(max, newVal)); // Update slider value if (props.onValueChange) { props.onValueChange([newVal]); } }; const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === "Enter") { e.preventDefault(); handleInputBlur(); } }; const initialValue = Array.isArray(props.value) ? props.value : [props.min ?? 0, props.max ?? 100]; return (
{initialValue.map((_, index) => ( ))} {showInput && (
{displayAsPercentage && ( % )}
)}
); }, ); Slider.displayName = SliderPrimitive.Root.displayName; export { Slider };