"use client"; import { useEffect, useRef, useState } from "react"; import { useInView } from "framer-motion"; import { cn } from "@/lib/utils"; interface AnimatedNumberProps { value: number; suffix?: string; prefix?: string; duration?: number; className?: string; } export function AnimatedNumber({ value, suffix = "", prefix = "", duration = 1800, className, }: AnimatedNumberProps) { const [count, setCount] = useState(0); const ref = useRef(null); const isInView = useInView(ref, { once: true, margin: "-80px" }); useEffect(() => { if (!isInView) return; let rafId: number; let startTime: number | null = null; const step = (ts: number) => { if (!startTime) startTime = ts; const progress = Math.min((ts - startTime) / duration, 1); // Ease-out cubic const eased = 1 - Math.pow(1 - progress, 3); setCount(Math.round(eased * value)); if (progress < 1) rafId = requestAnimationFrame(step); }; rafId = requestAnimationFrame(step); return () => cancelAnimationFrame(rafId); }, [isInView, value, duration]); return ( {prefix}{count}{suffix} ); }