"use client"; import { animate, useInView, useMotionValue, useTransform } from "motion/react"; import { motion } from "motion/react"; import { type CSSProperties, useEffect, useRef } from "react"; const pairToIndex = (p: string): number => (p.charCodeAt(0) - 65) * 26 + (p.charCodeAt(1) - 65); const indexToPair = (i: number): string => { const f = Math.floor(i / 26); const s = i % 26; return String.fromCharCode(65 + f) + String.fromCharCode(65 + s); }; type LetterCounterProps = { from?: string; to?: string; duration?: number; delay?: number; className?: string; style?: CSSProperties; }; /** * Letter "spin" between two two-letter codes (default AA → NN). * Use as an animated placeholder while a real value loads or to imply a pending figure. */ export function LetterCounter({ from = "AA", to = "NN", duration = 1.0, delay = 0.2, className, style, }: LetterCounterProps) { const ref = useRef(null); const inView = useInView(ref, { once: true, amount: 0.4 }); const value = useMotionValue(pairToIndex(from)); const display = useTransform(value, (latest) => indexToPair(Math.round(latest))); useEffect(() => { if (!inView) return; const controls = animate(value, pairToIndex(to), { duration, delay, ease: "linear", }); return controls.stop; }, [inView, to, duration, delay, value]); return ( {display} ); }