"use client" import { forwardRef, useCallback, useEffect, useImperativeHandle, useState, } from "react" import { animate, AnimationPlaybackControls, motion, useMotionValue, useTransform, ValueAnimationTransition, } from "motion/react" import { cn } from "@/lib/utils" interface NumberTickerProps { from: number // Starting value of the animation target: number // End value of the animation transition?: ValueAnimationTransition // Animation configuration, refer to motion docs for more details className?: string // additionl CSS classes for styling onStart?: () => void // Callback function when animation starts onComplete?: () => void // Callback function when animation completes autoStart?: boolean // Whether to start the animation automatically } // Ref interface to allow external control of the animation export interface NumberTickerRef { startAnimation: () => void } const NumberTicker = forwardRef( ( { from = 0, target = 100, transition = { duration: 3, type: "tween", ease: "easeInOut", }, className, onStart, onComplete, autoStart = true, ...props }, ref ) => { const count = useMotionValue(from) const rounded = useTransform(count, (latest) => Math.round(latest)) const [controls, setControls] = useState( null ) // Function to start the animation const startAnimation = useCallback(() => { if (controls) controls.stop() onStart?.() count.set(from) const newControls = animate(count, target, { ...transition, onComplete: () => { onComplete?.() }, }) setControls(newControls) }, []) // Expose the startAnimation function via ref useImperativeHandle(ref, () => ({ startAnimation, })) useEffect(() => { if (autoStart) { startAnimation() } return () => controls?.stop() }, [autoStart]) return ( {rounded} ) } ) NumberTicker.displayName = "NumberTicker" export default NumberTicker // Usage example: // To start the animation from outside the component: // 1. Create a ref: // const tickerRef = useRef(null); // 2. Pass the ref to the NumberTicker component: // // 3. Call the startAnimation function: // tickerRef.current?.startAnimation();