{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "basic-number-ticker", "title": "Basic Number Ticker", "description": "An animated number ticker component with customizable start, target, transitions, and callbacks.", "dependencies": [ "framer-motion" ], "registryDependencies": [], "files": [ { "path": "registry/spark-ui/basic-number-ticker.tsx", "content": "\"use client\"\n\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useState,\n} from \"react\"\nimport {\n animate,\n AnimationPlaybackControls,\n motion,\n useMotionValue,\n useTransform,\n ValueAnimationTransition,\n} from \"framer-motion\"\n\nimport { cn } from \"@/lib/utils\"\n\nexport interface NumberTickerProps {\n from: number // Starting value of the animation\n target: number // End value of the animation\n transition?: ValueAnimationTransition // Animation configuration, refer to motion docs for more details\n className?: string // additional CSS classes for styling\n onStart?: () => void // Callback function when animation starts\n onComplete?: () => void // Callback function when animation completes\n autoStart?: boolean // Whether to start the animation automatically\n}\n\n// Ref interface to allow external control of the animation\nexport interface NumberTickerRef {\n startAnimation: () => void\n}\n\nconst NumberTicker = forwardRef(\n (\n {\n from = 0,\n target = 100,\n transition = {\n duration: 3,\n type: \"tween\",\n ease: \"easeInOut\",\n },\n className,\n onStart,\n onComplete,\n autoStart = true,\n ...props\n },\n ref\n ) => {\n const count = useMotionValue(from)\n const rounded = useTransform(count, (latest) => Math.round(latest))\n const [controls, setControls] = useState(\n null\n )\n\n // Function to start the animation\n const startAnimation = useCallback(() => {\n if (controls) controls.stop()\n onStart?.()\n\n count.set(from)\n\n const newControls = animate(count, target, {\n ...transition,\n onComplete: () => {\n onComplete?.()\n },\n })\n setControls(newControls)\n }, [controls, count, from, target, transition, onStart, onComplete])\n\n // Expose the startAnimation function via ref\n useImperativeHandle(ref, () => ({\n startAnimation,\n }))\n\n useEffect(() => {\n if (autoStart) {\n startAnimation()\n }\n return () => controls?.stop()\n }, [autoStart])\n\n return (\n \n {rounded}\n \n )\n }\n)\n\nNumberTicker.displayName = \"NumberTicker\"\n\nexport default NumberTicker\n", "type": "registry:component" } ], "type": "registry:component" }