'use client';
import { forwardRef, HTMLAttributes, useEffect, useState, useRef } from 'react';
export interface StrikeRevealProps extends HTMLAttributes {
children: string;
revealText?: string;
variant?: 'permanent' | 'crossout' | 'redacted' | 'censored' | 'glitch';
color?: 'default' | 'blood' | 'cyber' | 'acid' | 'void';
trigger?: 'auto' | 'hover' | 'scroll' | 'click';
delay?: number;
double?: boolean;
strikeColor?: string;
onReveal?: () => void;
}
const colorStyles = {
default: 'bg-current',
blood: 'bg-rose-500',
cyber: 'bg-cyan-400',
acid: 'bg-lime-400',
void: 'bg-[#0a0a0a]',
};
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 handleMouseEnter = () => {
if (trigger === 'hover') setIsActive(true);
};
const handleMouseLeave = () => {
if (trigger === 'hover') setIsActive(false);
};
const strikeHeight = variant === 'redacted' ? 'h-[1em]' : variant === 'censored' ? 'h-full' : 'h-0.5';
const bgStyle = strikeColor ? { backgroundColor: strikeColor } : undefined;
return (
{
(containerRef as React.MutableRefObject).current = node;
if (typeof ref === 'function') ref(node);
else if (ref) ref.current = node;
}}
className={`relative inline-block ${className}`}
style={style}
onClick={handleClick}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
{...props}
>
{children}
{double && (
)}
{revealText && (
{revealText}
)}
);
}
);
StrikeReveal.displayName = 'StrikeReveal';
export default StrikeReveal;