import { AnimatePresence, motion, type Transition, type Variants, } from "motion/react"; import { useMemo, useId } from "react"; export type TextMorphProps = { children: string; as?: React.ElementType; className?: string; style?: React.CSSProperties; variants?: Variants; transition?: Transition; }; export function TextMorph({ children, as: Component = "p", className, style, variants, transition, }: TextMorphProps) { const uniqueId = useId(); const Tag = Component as React.ComponentType<{ className?: string; "aria-label"?: string; style?: React.CSSProperties; children?: React.ReactNode; }>; const characters = useMemo(() => { const charCounts: Record = {}; return children.split("").map((char) => { const lowerChar = char.toLowerCase(); charCounts[lowerChar] = (charCounts[lowerChar] || 0) + 1; return { id: `${uniqueId}-${lowerChar}${charCounts[lowerChar]}`, label: char === " " ? "\u00A0" : char, }; }); }, [children, uniqueId]); const defaultVariants: Variants = { initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 }, }; const defaultTransition: Transition = { type: "spring", stiffness: 280, damping: 18, mass: 0.3, }; return ( {characters.map((character) => ( ))} ); }