"use client"; import { useRef } from "react"; import { motion, useInView, useReducedMotion } from "motion/react"; type CounterFlowProps = { /** Final number. Change it later and only the digits that differ roll. */ value: number; /** Text before the number, like "$". */ prefix?: string; /** Text after the number, like "%" or "+". */ suffix?: string; /** Digits after the point. */ decimals?: number; /** Number format, like "en-IN" for lakh commas. */ locale?: string; /** Seconds each digit rolls. */ duration?: number; /** Wrapper look (text size, colour). */ className?: string; }; const DIGITS = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; function Digit({ digit, delay, duration }: { digit: number; delay: number; duration: number }) { const reduce = useReducedMotion(); return ( {DIGITS.map((d) => ( {d} ))} ); } /* CounterFlow: an odometer. Each digit is a strip of 0 to 9 that rolls into place the first time the number scrolls into view, right digit first. */ export function CounterFlow({ value, prefix, suffix, decimals = 0, locale = "en-US", duration = 1.4, className = "text-4xl font-semibold text-white" }: CounterFlowProps) { const box = useRef(null); const seen = useInView(box, { once: true, amount: 0.5 }); const text = value.toLocaleString(locale, { minimumFractionDigits: decimals, maximumFractionDigits: decimals }); const chars = [...text]; return ( {`${prefix ?? ""}${text}${suffix ?? ""}`} {prefix} {chars.map((char, i) => { const fromRight = chars.length - i; return /\d/.test(char) ? ( ) : ( {char} ); })} {suffix} ); }