● Zion Boggan
repos/Drophawk/frontend/components/shared/CountUp.tsx
zionboggan.com ↗
36 lines · tsx
History for this file →
1
"use client";
2
 
3
import { useEffect, useRef, useState } from "react";
4
import { useReducedMotion } from "framer-motion";
5
import { formatCompact } from "@/lib/utils";
6
 
7
export function CountUp({ value, compact = true }: { value: number; compact?: boolean }) {
8
  const reduce = useReducedMotion();
9
  const [display, setDisplay] = useState(reduce ? value : 0);
10
  const fromRef = useRef(0);
11
  const raf = useRef<number | null>(null);
12
 
13
  useEffect(() => {
14
    if (reduce) {
15
      setDisplay(value);
16
      return;
17
    }
18
    const from = fromRef.current;
19
    const start = performance.now();
20
    const dur = 650;
21
    const tick = (now: number) => {
22
      const t = Math.min(1, (now - start) / dur);
23
      const eased = 1 - Math.pow(1 - t, 3);
24
      setDisplay(Math.round(from + (value - from) * eased));
25
      if (t < 1) raf.current = requestAnimationFrame(tick);
26
      else fromRef.current = value;
27
    };
28
    raf.current = requestAnimationFrame(tick);
29
    return () => {
30
      if (raf.current) cancelAnimationFrame(raf.current);
31
      fromRef.current = value;
32
    };
33
  }, [value, reduce]);
34
 
35
  return <span className="tabular">{compact ? formatCompact(display) : display.toLocaleString()}</span>;
36
}