"use client"; import { motion, Variants } from "framer-motion"; import React, { ElementType, ReactNode, useEffect, useState, } from "react"; import { cn } from "../../lib/utils"; export interface TypingTextProps { children: ReactNode; as?: ElementType; className?: string; delay?: number; duration?: number; fontSize?: string; fontWeight?: string; color?: string; letterSpacing?: string; align?: "left" | "center" | "right"; loop?: boolean; } export const TypingText = ({ children, as: Component = "div", className = "", delay = 0, duration = 2, fontSize = "text-4xl", fontWeight = "font-bold", color = "text-white", letterSpacing = "tracking-wide", align = "left", loop = false, }: TypingTextProps) => { const [textContent, setTextContent] = useState(""); useEffect(() => { const extractText = (node: ReactNode): string => { if (typeof node === "string" || typeof node === "number") { return node.toString(); } if (Array.isArray(node)) { return node.map(extractText).join(""); } if ( React.isValidElement(node) && typeof node.props.children !== "undefined" ) { return extractText(node.props.children); } return ""; }; setTextContent(extractText(children)); }, [children]); const characters = textContent.split("").map((char) => char === " " ? "\u00A0" : char ); const characterVariants: Variants = { hidden: { opacity: 0, scale: 0.95 }, visible: (i: number) => ({ opacity: 1, scale: 1, transition: { delay: delay + i * (duration / characters.length), duration: 0.3, ease: "easeInOut", }, }), }; return ( {characters.map((char, index) => ( {char} ))} ); };