{"slug":"animated-number","name":"Animated Number","description":"Spring-driven count-up triggered when in view.","category":"motion","source_url":"https://beui.saura3h.xyz/r/animated-number/raw","detail_url":"https://beui.saura3h.xyz/r/animated-number","raw_url":"https://beui.saura3h.xyz/r/animated-number/raw","page_url":"https://beui.saura3h.xyz/components/motion/animated-number","dependencies":["motion","react"],"internal":["@/components/motion/animated-number","@/lib/utils"],"files":[{"path":"components/motion/animated-number.tsx","type":"component","content":"\"use client\";\n\nimport { animate, useInView } from \"motion/react\";\nimport { useEffect, useRef, useState } from \"react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface AnimatedNumberProps {\n  value: number;\n  duration?: number;\n  format?: (n: number) => string;\n  className?: string;\n  startOnView?: boolean;\n}\n\nexport function AnimatedNumber({\n  value,\n  duration = 1.2,\n  format = (n) => Math.round(n).toLocaleString(),\n  className,\n  startOnView = true,\n}: AnimatedNumberProps) {\n  const ref = useRef<HTMLSpanElement>(null);\n  const inView = useInView(ref, { once: true, amount: 0.6 });\n  const [display, setDisplay] = useState(0);\n  const fromRef = useRef(0);\n\n  useEffect(() => {\n    if (startOnView && !inView) return;\n    const controls = animate(fromRef.current, value, {\n      duration,\n      ease: [0.16, 1, 0.3, 1],\n      onUpdate: (v) => setDisplay(v),\n    });\n    fromRef.current = value;\n    return () => controls.stop();\n  }, [value, duration, inView, startOnView]);\n\n  return (\n    <span ref={ref} className={cn(\"tabular-nums\", className)}>\n      {format(display)}\n    </span>\n  );\n}\n"},{"path":"components/previews/motion/animated-number.preview.tsx","type":"preview","content":"\"use client\";\n\nimport { AnimatedNumber } from \"@/components/motion/animated-number\";\n\nexport function AnimatedNumberPreview() {\n  return (\n    <div className=\"flex flex-col items-center gap-3\">\n      <p className=\"text-xs text-(--color-fg-muted)\">Monthly recurring revenue</p>\n      <div className=\"text-4xl font-semibold tracking-tight text-(--color-fg) tabular-nums\">\n        <AnimatedNumber value={129480} format={(n) => `$${Math.round(n).toLocaleString()}`} />\n      </div>\n      <p className=\"text-xs text-(--color-success)\">+12.4% vs last month</p>\n    </div>\n  );\n}\n"},{"path":"lib/utils.ts","type":"util","content":"import { clsx, type ClassValue } from \"clsx\"\nimport { twMerge } from \"tailwind-merge\"\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs))\n}\n"}]}