// ✅ Correct import { useEffect, useRef, useState } from 'react'; import { motion } from 'motion/react'; import './TrueFocus.css'; interface TrueFocusProps { sentence?: string; separator?: string; manualMode?: boolean; blurAmount?: number; borderColor?: string; glowColor?: string; animationDuration?: number; pauseBetweenAnimations?: number; } interface FocusRect { x: number; y: number; width: number; height: number; } const TrueFocus: React.FC = ({ sentence = '', separator = ' ', manualMode = false, blurAmount = 10, borderColor = 'green', glowColor = 'rgba(0, 255, 0, 0.6)', animationDuration = 1, pauseBetweenAnimations = 2 }) => { const words = sentence.split(separator); const [currentIndex, setCurrentIndex] = useState(0); const [lastActiveIndex, setLastActiveIndex] = useState(null); const containerRef = useRef(null); const wordRefs: React.MutableRefObject<(HTMLSpanElement | null)[]> = useRef([]); const [focusRect, setFocusRect] = useState({ x: 0, y: 0, width: 0, height: 0 }); useEffect(() => { if (!manualMode) { const interval = setInterval( () => { setCurrentIndex(prev => (prev + 1) % words.length); }, (animationDuration + pauseBetweenAnimations) * 1000 ); return () => clearInterval(interval); } }, [manualMode, animationDuration, pauseBetweenAnimations, words.length]); useEffect(() => { if (currentIndex === null || currentIndex === -1) return; if (!wordRefs.current[currentIndex] || !containerRef.current) return; const parentRect = containerRef.current.getBoundingClientRect(); const activeRect = wordRefs.current[currentIndex]!.getBoundingClientRect(); setFocusRect({ x: activeRect.left - parentRect.left, y: activeRect.top - parentRect.top, width: activeRect.width, height: activeRect.height }); }, [currentIndex, words.length]); const handleMouseEnter = (index: number) => { if (manualMode) { setLastActiveIndex(index); setCurrentIndex(index); } }; const handleMouseLeave = () => { if (manualMode) { setCurrentIndex(lastActiveIndex ?? 0); } }; return (
{words.map((word, index) => { const isActive = index === currentIndex; return ( { if (el) { wordRefs.current[index] = el; } }} className={`focus-word ${manualMode ? 'manual' : ''} ${isActive && !manualMode ? 'active' : ''}`} style={ { filter: manualMode ? isActive ? `blur(0px)` : `blur(${blurAmount}px)` : isActive ? `blur(0px)` : `blur(${blurAmount}px)`, transition: `filter ${animationDuration}s ease`, '--border-color': borderColor, '--glow-color': glowColor } as React.CSSProperties } onMouseEnter={() => handleMouseEnter(index)} onMouseLeave={handleMouseLeave} > {word} ); })} = 0 ? 1 : 0 }} transition={{ duration: animationDuration }} style={ { '--border-color': borderColor, '--glow-color': glowColor } as React.CSSProperties } >
); }; export default TrueFocus;