{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "number-ticker",
  "title": "Number Ticker",
  "description": "Springs a number up when it enters the viewport.",
  "dependencies": [
    "motion"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "src/components/velora/number-ticker.tsx",
      "content": "\"use client\";\n\nimport { useEffect, useRef } from \"react\";\nimport {\n  useInView,\n  useMotionValue,\n  useReducedMotion,\n  useSpring,\n} from \"motion/react\";\n\nimport { cn } from \"@/lib/utils\";\n\ninterface NumberTickerProps extends React.HTMLAttributes<HTMLSpanElement> {\n  value: number;\n  startValue?: number;\n  /** Seconds to wait after entering the viewport */\n  delay?: number;\n  decimalPlaces?: number;\n  prefix?: string;\n  suffix?: string;\n}\n\nexport function NumberTicker({\n  value,\n  startValue = 0,\n  delay = 0,\n  decimalPlaces = 0,\n  prefix = \"\",\n  suffix = \"\",\n  className,\n  ...props\n}: NumberTickerProps) {\n  const ref = useRef<HTMLSpanElement>(null);\n  const motionValue = useMotionValue(startValue);\n  const springValue = useSpring(motionValue, {\n    damping: 60,\n    stiffness: 100,\n  });\n  const isInView = useInView(ref, { once: true, margin: \"0px 0px -10% 0px\" });\n  const reducedMotion = useReducedMotion();\n\n  const format = (n: number) =>\n    `${prefix}${Intl.NumberFormat(\"en-US\", {\n      minimumFractionDigits: decimalPlaces,\n      maximumFractionDigits: decimalPlaces,\n    }).format(n)}${suffix}`;\n\n  useEffect(() => {\n    if (!isInView) return;\n    if (reducedMotion) {\n      // jump() on the source alone still makes the spring follow it,\n      // so jump the spring too to skip the count-up entirely\n      motionValue.jump(value);\n      springValue.jump(value);\n      return;\n    }\n    const timeout = setTimeout(() => motionValue.set(value), delay * 1000);\n    return () => clearTimeout(timeout);\n  }, [isInView, reducedMotion, motionValue, springValue, value, delay]);\n\n  useEffect(\n    () =>\n      springValue.on(\"change\", (latest) => {\n        if (ref.current) ref.current.textContent = format(latest);\n      }),\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n    [springValue, prefix, suffix, decimalPlaces]\n  );\n\n  return (\n    <span\n      data-slot=\"number-ticker\"\n      className={cn(\"inline-block tabular-nums\", className)}\n      {...props}\n    >\n      <span className=\"sr-only\">{format(value)}</span>\n      <span ref={ref} aria-hidden>\n        {format(startValue)}\n      </span>\n    </span>\n  );\n}\n",
      "type": "registry:ui",
      "target": "components/velora/number-ticker.tsx"
    }
  ],
  "type": "registry:ui"
}