'use client'; import { forwardRef, HTMLAttributes, useEffect, useRef, useState } from 'react'; import styles from './prophecy.module.css'; export interface ProphecyProps extends HTMLAttributes { /** The prophecy text to reveal */ children: string; /** Speed of character reveal: slow, medium, fast, instant */ revealSpeed?: 'slow' | 'medium' | 'fast' | 'instant'; /** Use ancient/deteriorated font style */ ancientFont?: boolean; /** Delay before revelation starts (ms) */ startDelay?: number; /** Loop the revelation animation */ loop?: boolean; /** Callback when revelation completes */ onComplete?: () => void; } export const Prophecy = forwardRef( ( { children, revealSpeed = 'medium', ancientFont = true, startDelay = 500, loop = false, onComplete, className, style, ...props }, ref ) => { const [revealedChars, setRevealedChars] = useState(0); const [hasStarted, setHasStarted] = useState(false); const containerRef = useRef(null); const timeoutRef = useRef(); const intervalRef = useRef(); useEffect(() => { if (!hasStarted) { const startTimeout = setTimeout(() => { setHasStarted(true); setRevealedChars(0); const speedMap = { slow: 150, medium: 80, fast: 40, instant: 10, }; const interval = setInterval(() => { setRevealedChars((prev) => { const next = prev + 1; if (next >= children.length) { clearInterval(interval); onComplete?.(); if (loop) { setTimeout(() => { setRevealedChars(0); }, 2000); } return next; } return next; }); }, speedMap[revealSpeed]); intervalRef.current = interval; }, startDelay); timeoutRef.current = startTimeout; } return () => { clearTimeout(timeoutRef.current); clearInterval(intervalRef.current); }; }, [hasStarted, children.length, revealSpeed, startDelay, loop, onComplete]); const chars = children.split(''); return (
{ if (typeof ref === 'function') ref(node); containerRef.current = node; }} className={`${styles.prophecy} ${ancientFont ? styles.ancientFont : ''} ${className || ''}`} style={style} {...props} > {chars.map((char, index) => ( {char === ' ' ? '\u00A0' : char} ))}
); }); Prophecy.displayName = 'Prophecy'; export default Prophecy;