Components
npx shadcn@latest add https://21st.dev/r/originui/sliderLoading preview...
"use client";
import { useSliderWithInput } from "@/components/hooks/use-slider-with-input";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Slider } from "@/components/ui/slider";
import { RotateCcw } from "lucide-react";
import React, { useRef } from "react";
function Component() {
const resetFunctionsRef = useRef<(() => void)[]>([]);
const resetAll = () => {
resetFunctionsRef.current.forEach((resetFn) => resetFn());
};
const registerResetFunction = (resetFn: () => void, index: number) => {
resetFunctionsRef.current[index] = resetFn;
};
return (
<div className="space-y-4 min-w-[300px]">
<legend className="text-sm font-medium text-foreground">Object position</legend>
<div className="space-y-2">
<SliderWithInput
minValue={-10}
maxValue={10}
initialValue={[-2]}
defaultValue={[0]}
label="X"
onRegisterReset={(resetFn) => registerResetFunction(resetFn, 0)}
/>
<SliderWithInput
minValue={-10}
maxValue={10}
initialValue={[4]}
defaultValue={[0]}
label="Y"
onRegisterReset={(resetFn) => registerResetFunction(resetFn, 1)}
/>
<SliderWithInput
minValue={-10}
maxValue={10}
initialValue={[2]}
defaultValue={[0]}
label="Z"
onRegisterReset={(resetFn) => registerResetFunction(resetFn, 2)}
/>
</div>
<Button className="w-full" variant="outline" onClick={resetAll}>
<RotateCcw className="-ms-1 me-2 opacity-60" size={16} strokeWidth={2} aria-hidden="true" />
Reset
</Button>
</div>
);
}
function SliderWithInput({
minValue,
maxValue,
initialValue,
defaultValue,
label,
onRegisterReset,
}: {
minValue: number;
maxValue: number;
initialValue: number[];
defaultValue: number[];
label: string;
onRegisterReset: (resetFn: () => void) => void;
}) {
const {
sliderValue,
inputValues,
validateAndUpdateValue,
handleInputChange,
handleSliderChange,
resetToDefault,
} = useSliderWithInput({ minValue, maxValue, initialValue, defaultValue });
React.useEffect(() => {
onRegisterReset(resetToDefault);
}, [onRegisterReset, resetToDefault]);
return (
<div className="flex items-center gap-2">
<Label className="text-xs text-muted-foreground">{label}</Label>
<Slider
className="grow [&>:last-child>span]:rounded"
value={sliderValue}
onValueChange={handleSliderChange}
min={minValue}
max={maxValue}
aria-label={label}
/>
<Input
className="h-8 w-12 px-2 py-1"
type="text"
inputMode="decimal"
value={inputValues[0]}
onChange={(e) => handleInputChange(e, 0)}
onBlur={() => validateAndUpdateValue(inputValues[0], 0)}
onKeyDown={(e) => {
if (e.key === "Enter") {
validateAndUpdateValue(inputValues[0], 0);
}
}}
aria-label="Enter value"
/>
</div>
);
}
export { Component };
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...