{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "adaptive-slider",
  "type": "registry:component",
  "title": "Adaptive Slider",
  "description": "A smooth, color-shifting slider with caloric value tracking.",
  "dependencies": [
    "motion"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "components/watermelon/adaptive-slider.tsx",
      "type": "registry:component",
      "content": "'use client';\n\nimport { useState, useMemo, type FC, type ChangeEvent } from 'react';\nimport { AnimatePresence, motion } from 'motion/react';\nimport { cn } from '@/lib/utils';\n\ninterface AdaptiveSliderProps {\n  value?: number;\n  min?: number;\n  max?: number;\n  step?: number;\n  defaultValue?: number;\n  onChange?: (value: number) => void;\n}\n\ninterface ColorSettings {\n  text: string;\n  gradient: string;\n  thumbBorder: string;\n}\n\nconst DEFAULT_MIN = 50;\nconst DEFAULT_MAX = 350;\nconst DEFAULT_STEP = 25;\nconst DEFAULT_VALUE = 200;\n\nconst getColorSettings = (\n  value: number,\n  min: number,\n  max: number,\n): ColorSettings => {\n  const percentage = (value - min) / (max - min);\n\n  if (percentage < 0.5) {\n    return {\n      text: '#10B981',\n      gradient: 'linear-gradient(to right, #FEB101, #FE7C09)',\n      thumbBorder: '#10B981',\n    };\n  } else if (percentage < 0.7) {\n    return {\n      text: '#FE55B7',\n      gradient: 'linear-gradient(to right, #FE55B74D, #FE55B7)',\n      thumbBorder: '#F97316',\n    };\n  } else {\n    return {\n      text: '#D946EF',\n      gradient: 'linear-gradient(to right, #DAB0FE, #4946FF)',\n      thumbBorder: '#D946EF',\n    };\n  }\n};\n\nexport const AdaptiveSlider: FC<AdaptiveSliderProps> = ({\n  value,\n  min = DEFAULT_MIN,\n  max = DEFAULT_MAX,\n  step = DEFAULT_STEP,\n  defaultValue = DEFAULT_VALUE,\n  onChange,\n}) => {\n  const [internalValue, setInternalValue] = useState<number>(defaultValue);\n\n  const calories = value ?? internalValue;\n\n  const colorSettings = useMemo(\n    () => getColorSettings(calories, min, max),\n    [calories, min, max],\n  );\n\n  const percentage = ((calories - min) / (max - min)) * 100;\n\n  const dots = useMemo(\n    () =>\n      Array.from({ length: 6 }).map((_, i) => (\n        <div\n          key={i}\n          className=\"z-30 h-1.5 w-1.5 rounded-full bg-[#C4B9FA] transition-colors dark:bg-neutral-600\"\n          style={{ opacity: 0.8 }}\n        />\n      )),\n    [],\n  );\n\n  const handleSliderChange = (e: ChangeEvent<HTMLInputElement>) => {\n    const val = Number(e.target.value);\n    setInternalValue(val);\n    onChange?.(val);\n  };\n\n  return (\n    <motion.div className=\"flex h-[60vh] w-xs flex-col items-center justify-center rounded-[36px] bg-[#FEFEFE] p-6 shadow-2xl shadow-black/5 transition-colors select-none sm:w-sm sm:p-12 dark:bg-neutral-900 dark:shadow-none\">\n      <span className=\"mb-2 text-xl font-bold text-[#878787] sm:text-2xl dark:text-neutral-500\">\n        Calories\n      </span>\n\n      <div className=\"mb-8 flex items-baseline gap-2\">\n        <AnimatedText\n          value={calories.toString()}\n          className=\"overflow-hidden text-5xl font-extrabold tracking-tight sm:text-6xl\"\n        />\n        <motion.span\n          layout\n          className=\"text-4xl font-extrabold text-[#010101] transition-colors sm:text-5xl dark:text-neutral-100\"\n        >\n          kCal\n        </motion.span>\n      </div>\n\n      <div className=\"group relative flex h-13 w-full items-center overflow-hidden rounded-full bg-[#f1f3f5] transition-colors dark:bg-neutral-800\">\n        <div className=\"pointer-events-none absolute inset-0 flex items-center justify-between px-4 transition-colors sm:px-8\">\n          {dots}\n        </div>\n\n        <motion.div\n          className=\"pointer-events-none absolute top-0 left-0 h-full rounded-full\"\n          animate={{\n            width: `calc((${percentage} / 100) * (100% - 52px) + 52px)`,\n            background: colorSettings.gradient,\n          }}\n          transition={{ type: 'spring', stiffness: 300, damping: 30 }}\n        />\n\n        <input\n          title=\"range\"\n          type=\"range\"\n          min={min}\n          max={max}\n          step={step}\n          value={calories}\n          onChange={handleSliderChange}\n          className=\"absolute inset-0 z-50 h-13 w-full cursor-pointer opacity-0\"\n        />\n\n        <motion.div\n          className=\"pointer-events-none absolute top-0 z-40 flex size-13 items-center justify-center rounded-full border-none\"\n          animate={{\n            left: `calc((${percentage} / 100) * (100% - 52px))`,\n          }}\n          transition={{ type: 'spring', stiffness: 300, damping: 30 }}\n        >\n          <div className=\"size-10 rounded-full bg-white shadow-[inset_0_2px_4px_rgba(0,0,0,0.06)]\" />\n        </motion.div>\n      </div>\n    </motion.div>\n  );\n};\n\nconst AnimatedText = ({\n  value,\n  className,\n}: {\n  value: string;\n  className?: string;\n}) => {\n  return (\n    <div\n      className={cn(\n        'flex text-lg tracking-tight will-change-transform',\n        className,\n      )}\n    >\n      <AnimatePresence mode=\"popLayout\" initial={false}>\n        {value.split('').map((char, index) => {\n          const displayChar = char === ' ' ? '\\u00A0' : char;\n\n          return (\n            <motion.span\n              key={char + index}\n              initial={{ opacity: 1, y: 0, scale: 1 }}\n              animate={{\n                opacity: 1,\n                y: 0,\n                scale: 1,\n                transition: {\n                  type: 'spring',\n                  stiffness: 200,\n                  damping: 20,\n                  // delay: 0.03 * index,\n                },\n              }}\n              exit={{ opacity: 0, y: 0, scale: 1, transition: { duration: 0 } }}\n            >\n              {displayChar}\n            </motion.span>\n          );\n        })}\n      </AnimatePresence>\n    </div>\n  );\n};\n"
    }
  ]
}
