'use client'; import React, { useRef, useState, useCallback, useEffect } from 'react'; import { motion, useSpring, useTransform, SpringOptions } from 'framer-motion'; import { cn } from '@/lib/utils'; type SpotlightProps = { className?: string; size?: number; springOptions?: SpringOptions; }; export function Spotlight({ className, size = 200, springOptions = { bounce: 0 }, }: SpotlightProps) { const containerRef = useRef(null); const [isHovered, setIsHovered] = useState(false); const [parentElement, setParentElement] = useState(null); const mouseX = useSpring(0, springOptions); const mouseY = useSpring(0, springOptions); const spotlightLeft = useTransform(mouseX, (x) => `${x - size / 2}px`); const spotlightTop = useTransform(mouseY, (y) => `${y - size / 2}px`); useEffect(() => { if (containerRef.current) { const parent = containerRef.current.parentElement; if (parent) { parent.style.position = 'relative'; parent.style.overflow = 'hidden'; setParentElement(parent); } } }, []); const handleMouseMove = useCallback( (event: MouseEvent) => { if (!parentElement) return; const { left, top } = parentElement.getBoundingClientRect(); mouseX.set(event.clientX - left); mouseY.set(event.clientY - top); }, [mouseX, mouseY, parentElement] ); useEffect(() => { if (!parentElement) return; parentElement.addEventListener('mousemove', handleMouseMove); parentElement.addEventListener('mouseenter', () => setIsHovered(true)); parentElement.addEventListener('mouseleave', () => setIsHovered(false)); return () => { parentElement.removeEventListener('mousemove', handleMouseMove); parentElement.removeEventListener('mouseenter', () => setIsHovered(true)); parentElement.removeEventListener('mouseleave', () => setIsHovered(false) ); }; }, [parentElement, handleMouseMove]); return ( ); }