{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "countdown",
  "type": "registry:component",
  "title": "Countdown",
  "author": "Toby Belhome",
  "description": "A countdown is a component that displays the remaining time until a specific event or deadline.",
  "dependencies": [
    "motion",
    "react-use-measure"
  ],
  "registryDependencies": [
    "http://localhost:3000/r/countdown.json"
  ],
  "files": [
    {
      "path": "examples/motion/components/countdown/01/countdown.tsx",
      "content": "\"use client\";\n\nimport { useEffect, useId } from \"react\";\nimport { MotionValue, motion, useSpring, useTransform, motionValue } from \"motion/react\";\nimport useMeasure from \"react-use-measure\";\n\nconst TRANSITION = {\n  type: \"spring\" as const,\n  stiffness: 280,\n  damping: 18,\n  mass: 0.3\n};\n\n// examples içinde motionlar eklenti olarak burada kalsın\n// ama örnekler yani page.tsx dosyaları buradan çıktsın\n\nfunction Digit({ value, place }: { value: number; place: number }) {\n  const valueRoundedToPlace = Math.floor(value / place) % 10;\n  const initial = motionValue(valueRoundedToPlace);\n  const animatedValue = useSpring(initial, TRANSITION);\n\n  useEffect(() => {\n    animatedValue.set(valueRoundedToPlace);\n  }, [animatedValue, valueRoundedToPlace]);\n\n  return (\n    <div className=\"relative inline-block w-[1ch] overflow-x-visible overflow-y-clip leading-none tabular-nums\">\n      <div className=\"invisible\">0</div>\n      {Array.from({ length: 10 }, (_, i) => (\n        <Number key={i} mv={animatedValue} number={i} />\n      ))}\n    </div>\n  );\n}\n\nfunction Number({ mv, number }: { mv: MotionValue<number>; number: number }) {\n  const uniqueId = useId();\n  const [ref, bounds] = useMeasure();\n\n  const y = useTransform(mv, (latest) => {\n    if (!bounds.height) return 0;\n    const placeValue = latest % 10;\n    const offset = (10 + number - placeValue) % 10;\n    let memo = offset * bounds.height;\n\n    if (offset > 5) {\n      memo -= 10 * bounds.height;\n    }\n\n    return memo;\n  });\n\n  if (!bounds.height) {\n    return (\n      <span ref={ref} className=\"invisible absolute\">\n        {number}\n      </span>\n    );\n  }\n\n  return (\n    <motion.span\n      style={{ y }}\n      layoutId={`${uniqueId}-${number}`}\n      className=\"absolute inset-0 flex items-center justify-center\"\n      transition={TRANSITION}\n      ref={ref}>\n      {number}\n    </motion.span>\n  );\n}\n\ntype SlidingNumberProps = {\n  value: number;\n  padStart?: boolean;\n  decimalSeparator?: string;\n};\n\nexport function Countdown({ value, padStart = false, decimalSeparator = \".\" }: SlidingNumberProps) {\n  const absValue = Math.abs(value);\n  const [integerPart, decimalPart] = absValue.toString().split(\".\");\n  const integerValue = parseInt(integerPart, 10);\n  const paddedInteger = padStart && integerValue < 10 ? `0${integerPart}` : integerPart;\n  const integerDigits = paddedInteger.split(\"\");\n  const integerPlaces = integerDigits.map((_, i) => Math.pow(10, integerDigits.length - i - 1));\n\n  return (\n    <div className=\"flex items-center\">\n      {value < 0 && \"-\"}\n      {integerDigits.map((_, index) => (\n        <Digit\n          key={`pos-${integerPlaces[index]}`}\n          value={integerValue}\n          place={integerPlaces[index]}\n        />\n      ))}\n      {decimalPart && (\n        <>\n          <span>{decimalSeparator}</span>\n          {decimalPart.split(\"\").map((_, index) => (\n            <Digit\n              key={`decimal-${index}`}\n              value={parseInt(decimalPart, 10)}\n              place={Math.pow(10, decimalPart.length - index - 1)}\n            />\n          ))}\n        </>\n      )}\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/countdown/countdown.tsx"
    },
    {
      "path": "examples/motion/components/countdown/01/page.tsx",
      "content": "\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { Countdown } from \"./countdown\";\n\nexport default function CountdownExample() {\n  const targetDate = new Date();\n  targetDate.setDate(targetDate.getDate() + 1);\n\n  const calculateTimeLeft = () => {\n    const difference = +targetDate - +new Date();\n    if (difference <= 0) return { hours: 0, minutes: 0, seconds: 0 };\n\n    return {\n      hours: Math.floor((difference / (1000 * 60 * 60)) % 24),\n      minutes: Math.floor((difference / 1000 / 60) % 60),\n      seconds: Math.floor((difference / 1000) % 60)\n    };\n  };\n\n  const [timeLeft, setTimeLeft] = useState(calculateTimeLeft());\n\n  useEffect(() => {\n    const timer = setInterval(() => {\n      const newTimeLeft = calculateTimeLeft();\n      setTimeLeft(newTimeLeft);\n\n      if (newTimeLeft.hours === 0 && newTimeLeft.minutes === 0 && newTimeLeft.seconds === 0) {\n        clearInterval(timer);\n      }\n    }, 1000);\n\n    return () => clearInterval(timer);\n  }, []);\n\n  return (\n    <div className=\"flex items-center gap-0.5 text-xl font-semibold\">\n      <Countdown value={timeLeft.hours} padStart={true} />\n      <span className=\"text-zinc-500\">:</span>\n      <Countdown value={timeLeft.minutes} padStart={true} />\n      <span className=\"text-zinc-500\">:</span>\n      <Countdown value={timeLeft.seconds} padStart={true} />\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/countdown/countdown-example.tsx"
    }
  ],
  "meta": {
    "isPro": false
  }
}