"use client"; import { useEffect, useRef, useState } from "react"; /** Animates from 0 to `value` when scrolled into view. */ export function CountUp({ value, prefix = "", suffix = "", decimals = 0, duration = 1400, }: { value: number; prefix?: string; suffix?: string; decimals?: number; duration?: number; }) { const ref = useRef(null); const [display, setDisplay] = useState(0); useEffect(() => { const el = ref.current; if (!el) return; const io = new IntersectionObserver( (entries) => { if (!entries[0].isIntersecting) return; io.disconnect(); const start = performance.now(); const tick = (now: number) => { const p = Math.min((now - start) / duration, 1); const eased = 1 - Math.pow(1 - p, 3); // ease-out cubic setDisplay(value * eased); if (p < 1) requestAnimationFrame(tick); }; requestAnimationFrame(tick); }, { threshold: 0.4 } ); io.observe(el); return () => io.disconnect(); }, [value, duration]); return ( {prefix} {display.toLocaleString("en-US", { maximumFractionDigits: decimals, minimumFractionDigits: decimals })} {suffix} ); }