Spaces:
Sleeping
Sleeping
File size: 1,042 Bytes
4b445f6 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | "use client";
import { useEffect, useRef, useState } from "react";
interface AnimatedCounterProps {
value: number;
suffix?: string;
duration?: number;
className?: string;
}
export function AnimatedCounter({
value,
suffix = "",
duration = 1200,
className,
}: AnimatedCounterProps) {
const [display, setDisplay] = useState(0);
const ref = useRef<HTMLSpanElement>(null);
const hasAnimated = useRef(false);
useEffect(() => {
if (hasAnimated.current) return;
hasAnimated.current = true;
const start = performance.now();
function tick(now: number) {
const elapsed = now - start;
const progress = Math.min(elapsed / duration, 1);
// ease-out expo
const ease = progress === 1 ? 1 : 1 - Math.pow(2, -10 * progress);
setDisplay(Math.round(ease * value));
if (progress < 1) requestAnimationFrame(tick);
}
requestAnimationFrame(tick);
}, [value, duration]);
return (
<span ref={ref} className={className}>
{display}
{suffix}
</span>
);
}
|