{
  "$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<HTMLDivElement>(null);\n  const trackRef = useRef<HTMLDivElement>(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<HTMLDivElement>) => {\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    <div className={cn(\"w-full max-w-md p-6\", className)}>\n      <div className=\"flex justify-between items-center mb-4\">\n        <label className=\"text-sm font-medium text-foreground/80\">\n          {label}\n        </label>\n        <span className=\"text-sm font-mono text-muted-foreground bg-muted px-2 py-1 rounded-md\">\n          {value}\n        </span>\n      </div>\n\n      <div\n        className=\"relative h-6 flex items-center cursor-pointer group\"\n        ref={trackRef}\n        onClick={handleTrackClick}\n      >\n        {/* Track Background */}\n        <div className=\"absolute w-full h-2 bg-secondary rounded-full overflow-hidden\">\n          {/* Fill */}\n          <motion.div\n            className=\"h-full bg-primary\"\n            style={{ width: fillWidth }}\n          />\n        </div>\n\n        {/* Drag Handle */}\n        <motion.div\n          drag=\"x\"\n          dragConstraints={trackRef}\n          dragElastic={0}\n          dragMomentum={false}\n          onDragStart={() => 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          <motion.div\n            className={cn(\n              \"w-6 h-6 rounded-full bg-background border-2 border-primary shadow-lg flex items-center justify-center transition-colors\",\n              isDragging\n                ? \"scale-110 border-primary\"\n                : \"group-hover:border-primary/80\"\n            )}\n            whileHover={{ scale: 1.1 }}\n            whileTap={{ scale: 0.95 }}\n          >\n            <div className=\"w-2 h-2 rounded-full bg-primary\" />\n          </motion.div>\n\n          {/* Tooltip on Drag */}\n          {isDragging && (\n            <motion.div\n              initial={{ opacity: 0, y: 10 }}\n              animate={{ opacity: 1, y: -30 }}\n              exit={{ opacity: 0, y: 10 }}\n              className=\"absolute left-1/2 -translate-x-1/2 bg-popover text-popover-foreground text-xs px-2 py-1 rounded shadow-md border border-border\"\n            >\n              {value}\n            </motion.div>\n          )}\n        </motion.div>\n      </div>\n\n      <div className=\"flex justify-between mt-2 text-xs text-muted-foreground\">\n        <span>{min}</span>\n        <span>{max}</span>\n      </div>\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/uitripled/volume-component-shadcnui.tsx"
    }
  ]
}