'use client'; import { forwardRef, HTMLAttributes, useEffect, useState, useRef } from 'react'; import styles from './strike-reveal.module.css'; export interface StrikeRevealProps extends HTMLAttributes { /** Original text to strike through */ children: string; /** Text to reveal after strike */ revealText?: string; /** Visual variant */ variant?: 'permanent' | 'crossout' | 'redacted' | 'censored' | 'glitch'; /** Color variant */ color?: 'default' | 'blood' | 'cyber' | 'acid' | 'void'; /** Trigger mode */ trigger?: 'auto' | 'hover' | 'scroll' | 'click'; /** Delay before animation (ms) */ delay?: number; /** Double strike line */ double?: boolean; /** Custom strike color */ strikeColor?: string; /** Callback when reveal completes */ onReveal?: () => void; } export const StrikeReveal = forwardRef( ( { children, revealText, variant = 'permanent', color = 'default', trigger = 'auto', delay = 0, double = false, strikeColor, onReveal, className, style, ...props }, ref ) => { const [isActive, setIsActive] = useState(false); const containerRef = useRef(null); useEffect(() => { if (trigger === 'auto') { const timeout = setTimeout(() => { setIsActive(true); setTimeout(() => onReveal?.(), 700); }, delay); return () => clearTimeout(timeout); } if (trigger === 'scroll') { const observer = new IntersectionObserver( ([entry]) => { if (entry.isIntersecting) { setTimeout(() => { setIsActive(true); setTimeout(() => onReveal?.(), 700); }, delay); } }, { threshold: 0.5 } ); if (containerRef.current) { observer.observe(containerRef.current); } return () => observer.disconnect(); } }, [trigger, delay, onReveal]); const handleClick = () => { if (trigger === 'click') { setIsActive(true); setTimeout(() => onReveal?.(), 700); } }; const containerClasses = [ styles.container, styles[variant], color !== 'default' && styles[color], double && styles.double, trigger === 'hover' && styles.hover, isActive && styles.active, className ].filter(Boolean).join(' '); return ( { (containerRef as React.MutableRefObject).current = node; if (typeof ref === 'function') ref(node); else if (ref) ref.current = node; }} className={containerClasses} style={{ '--strike-color': strikeColor, '--delay': `${delay}ms`, ...style } as React.CSSProperties} onClick={handleClick} {...props} > {children} {revealText && ( {revealText} )} ); } ); StrikeReveal.displayName = 'StrikeReveal'; export default StrikeReveal;