{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "volume-component-shadcnui", "type": "registry:component", "title": "Volume Component", "description": "A smooth, draggable volume slider component with framer-motion animations and shadcn styling.", "registryDependencies": [ "button" ], "dependencies": [ "framer-motion", "react" ], "files": [ { "path": "@uitripled/react-shadcn/src/components/components/sliders/volume-component.tsx", "content": "\"use client\";\n\nimport { cn } from \"@/lib/utils\";\nimport { animate, motion, useMotionValue, useTransform } from \"framer-motion\";\nimport React, { useEffect, useRef, useState } from \"react\";\n\ninterface SliderProps {\n min?: number;\n max?: number;\n step?: number;\n defaultValue?: number;\n onChange?: (value: number) => void;\n className?: string;\n label?: string;\n}\n\nexport function VolumeComponent({\n min = 0,\n max = 100,\n step = 1,\n defaultValue = 0,\n onChange,\n className,\n label = \"Volume\",\n}: SliderProps) {\n const [value, setValue] = useState(defaultValue);\n const [isDragging, setIsDragging] = useState(false);\n const constraintsRef = useRef(null);\n const trackRef = useRef(null);\n\n const x = useMotionValue(0);\n const width = useMotionValue(0);\n\n // Convert value to position\n const valueToPosition = (val: number, trackWidth: number) => {\n const percentage = (val - min) / (max - min);\n return percentage * trackWidth;\n };\n\n // Convert position to value\n const positionToValue = (pos: number, trackWidth: number) => {\n const percentage = pos / trackWidth;\n const rawValue = percentage * (max - min) + min;\n const steppedValue = Math.round(rawValue / step) * step;\n return Math.min(Math.max(steppedValue, min), max);\n };\n\n useEffect(() => {\n if (trackRef.current) {\n const trackWidth = trackRef.current.offsetWidth;\n width.set(trackWidth);\n x.set(valueToPosition(value, trackWidth));\n }\n }, [value, min, max, width, x]);\n\n const handleDrag = (event: any, info: any) => {\n if (trackRef.current) {\n const trackWidth = trackRef.current.offsetWidth;\n const newValue = positionToValue(x.get(), trackWidth);\n if (newValue !== value) {\n setValue(newValue);\n onChange?.(newValue);\n }\n }\n };\n\n const handleTrackClick = (event: React.MouseEvent) => {\n if (trackRef.current) {\n const rect = trackRef.current.getBoundingClientRect();\n const clickX = event.clientX - rect.left;\n const trackWidth = rect.width;\n const newValue = positionToValue(clickX, trackWidth);\n\n setValue(newValue);\n onChange?.(newValue);\n\n animate(x, clickX, {\n type: \"spring\",\n stiffness: 300,\n damping: 30,\n });\n }\n };\n\n const fillWidth = useTransform(x, (latest) => {\n return Math.max(0, latest);\n });\n\n return (\n
\n
\n \n \n {value}\n \n
\n\n \n {/* Track Background */}\n
\n {/* Fill */}\n \n
\n\n {/* Drag Handle */}\n setIsDragging(true)}\n onDragEnd={() => setIsDragging(false)}\n onDrag={handleDrag}\n style={{ x }}\n className=\"absolute top-1/2 -translate-y-1/2 left-0 -ml-3 z-10\"\n >\n \n
\n \n\n {/* Tooltip on Drag */}\n {isDragging && (\n \n {value}\n \n )}\n \n
\n\n
\n {min}\n {max}\n
\n
\n );\n}\n", "type": "registry:component", "target": "components/uitripled/volume-component-shadcnui.tsx" } ] }