"use client"; import { cn } from "@/lib/utils"; import { motion, MotionProps } from "framer-motion"; import { useEffect, useRef, useState } from "react"; interface AnimatedSpanProps extends MotionProps { children: React.ReactNode; delay?: number; className?: string; } export const AnimatedSpan = ({ children, delay = 0, className, ...props }: AnimatedSpanProps) => ( {children} ); interface TypingAnimationProps extends MotionProps { children: string; className?: string; duration?: number; delay?: number; as?: React.ElementType; } export const TypingAnimation = ({ children, className, duration = 60, delay = 0, as: Component = "span", ...props }: TypingAnimationProps) => { if (typeof children !== "string") { throw new Error("TypingAnimation: children must be a string. Received:"); } const MotionComponent = motion.create(Component, { forwardMotionProps: true, }); const [displayedText, setDisplayedText] = useState(""); const [started, setStarted] = useState(false); const elementRef = useRef(null); useEffect(() => { const startTimeout = setTimeout(() => { setStarted(true); }, delay); return () => clearTimeout(startTimeout); }, [delay]); useEffect(() => { if (!started) return; let i = 0; const typingEffect = setInterval(() => { if (i < children.length) { setDisplayedText(children.substring(0, i + 1)); i++; } else { clearInterval(typingEffect); } }, duration); return () => { clearInterval(typingEffect); }; }, [children, duration, started]); return ( {displayedText} ); }; interface TerminalProps { children: React.ReactNode; className?: string; } export const Terminal = ({ children, className }: TerminalProps) => { return (
        {children}
      
); };