"use client"; // Adapted from Magic UI (MIT). See THIRD_PARTY_NOTICES.md. import { type ComponentProps, useEffect, useRef } from "react"; export interface TypingAnimationProps extends Omit< ComponentProps<"span">, "children" > { children: string; duration?: number; delay?: number; } export function TypingAnimation({ children, duration = 45, delay = 0, className = "", ...props }: TypingAnimationProps) { const visual = useRef(null); useEffect(() => { const media = matchMedia("(prefers-reduced-motion: reduce)"); const chars = Array.from(children); let timer: ReturnType; let index = 0; const finish = () => { clearTimeout(timer); if (visual.current) visual.current.textContent = children; }; const tick = () => { if (visual.current) visual.current.textContent = chars.slice(0, ++index).join(""); if (index < chars.length) timer = setTimeout(tick, Math.max(16, duration)); }; if (media.matches || duration <= 0 || !Number.isFinite(duration)) finish(); else { if (visual.current) visual.current.textContent = ""; timer = setTimeout(tick, Math.max(0, delay)); } media.addEventListener("change", finish); return () => { clearTimeout(timer); media.removeEventListener("change", finish); }; }, [children, duration, delay]); return ( {children} ); }