"use client"; import { useEffect, useRef, useState } from "react"; import { useInView, useReducedMotion } from "framer-motion"; interface CounterValueProps { value: number; className?: string; duration?: number; prefix?: string; suffix?: string; once?: boolean; amount?: number; } export function CounterValue({ value, className = "", duration = 1200, prefix = "", suffix = "", once = true, amount = 0.45, }: Readonly) { const shouldReduceMotion = useReducedMotion(); const ref = useRef(null); const isInView = useInView(ref, { once, amount }); const [displayValue, setDisplayValue] = useState(0); useEffect(() => { if (!isInView) return; if (shouldReduceMotion) { setDisplayValue(value); return; } const start = performance.now(); let rafId = 0; const frame = (now: number) => { const elapsed = now - start; const progress = Math.min(elapsed / duration, 1); const eased = 1 - Math.pow(1 - progress, 3); setDisplayValue(Math.round(value * eased)); if (progress < 1) { rafId = requestAnimationFrame(frame); } }; rafId = requestAnimationFrame(frame); return () => cancelAnimationFrame(rafId); }, [isInView, value, duration, shouldReduceMotion]); return ( {prefix} {displayValue} {suffix} ); }