import { ReactNode, useEffect, useState } from 'react'; /** * Fade in animation wrapper */ export function FadeIn({ children, delay = 0, duration = 300, className = '', }: { children: ReactNode; delay?: number; duration?: number; className?: string; }) { const [visible, setVisible] = useState(false); useEffect(() => { const timer = setTimeout(() => setVisible(true), delay); return () => clearTimeout(timer); }, [delay]); return (
{children}
); } /** * Slide in from direction */ export function SlideIn({ children, direction = 'left', delay = 0, duration = 300, distance = 20, className = '', }: { children: ReactNode; direction?: 'left' | 'right' | 'up' | 'down'; delay?: number; duration?: number; distance?: number; className?: string; }) { const [visible, setVisible] = useState(false); useEffect(() => { const timer = setTimeout(() => setVisible(true), delay); return () => clearTimeout(timer); }, [delay]); const transforms = { left: `translateX(${visible ? 0 : -distance}px)`, right: `translateX(${visible ? 0 : distance}px)`, up: `translateY(${visible ? 0 : -distance}px)`, down: `translateY(${visible ? 0 : distance}px)`, }; return (
{children}
); } /** * Scale in animation */ export function ScaleIn({ children, delay = 0, duration = 200, className = '', }: { children: ReactNode; delay?: number; duration?: number; className?: string; }) { const [visible, setVisible] = useState(false); useEffect(() => { const timer = setTimeout(() => setVisible(true), delay); return () => clearTimeout(timer); }, [delay]); return (
{children}
); } /** * Stagger children animations */ export function StaggerChildren({ children, staggerDelay = 50, initialDelay = 0, className = '', }: { children: ReactNode[]; staggerDelay?: number; initialDelay?: number; className?: string; }) { return (
{children.map((child, index) => ( {child} ))}
); } /** * Pulse animation (for attention) */ export function Pulse({ children, className = '', }: { children: ReactNode; className?: string; }) { return (
{children}
); } /** * Bounce animation */ export function Bounce({ children, className = '', }: { children: ReactNode; className?: string; }) { return (
{children}
); } /** * Number counter animation */ export function CountUp({ end, start = 0, duration = 1000, decimals = 0, prefix = '', suffix = '', className = '', }: { end: number; start?: number; duration?: number; decimals?: number; prefix?: string; suffix?: string; className?: string; }) { const [count, setCount] = useState(start); useEffect(() => { const startTime = Date.now(); const diff = end - start; const animate = () => { const elapsed = Date.now() - startTime; const progress = Math.min(elapsed / duration, 1); // Ease out cubic const eased = 1 - Math.pow(1 - progress, 3); const current = start + diff * eased; setCount(current); if (progress < 1) { requestAnimationFrame(animate); } }; requestAnimationFrame(animate); }, [end, start, duration]); return ( {prefix} {count.toFixed(decimals)} {suffix} ); } /** * Typing animation for text */ export function TypeWriter({ text, speed = 50, delay = 0, className = '', onComplete, }: { text: string; speed?: number; delay?: number; className?: string; onComplete?: () => void; }) { const [displayed, setDisplayed] = useState(''); useEffect(() => { let index = 0; const timer = setTimeout(() => { const interval = setInterval(() => { setDisplayed(text.slice(0, index + 1)); index++; if (index >= text.length) { clearInterval(interval); onComplete?.(); } }, speed); return () => clearInterval(interval); }, delay); return () => clearTimeout(timer); }, [text, speed, delay, onComplete]); return ( {displayed} | ); }