'use client'; import React, { useState, useEffect, useRef } from 'react'; import { motion, useMotionValue, useSpring, type SpringOptions, } from 'motion/react'; const SPRING_CONFIG = { stiffness: 26.7, damping: 4.1, mass: 0.2 }; export type MagneticProps = { children: React.ReactNode; intensity?: number; range?: number; actionArea?: 'self' | 'parent' | 'global'; springOptions?: SpringOptions; }; export function Magnetic({ children, intensity = 0.6, range = 100, actionArea = 'self', springOptions = SPRING_CONFIG, }: MagneticProps) { const [isHovered, setIsHovered] = useState(false); const ref = useRef(null); const x = useMotionValue(0); const y = useMotionValue(0); const springX = useSpring(x, springOptions); const springY = useSpring(y, springOptions); useEffect(() => { const calculateDistance = (e: MouseEvent) => { if (ref.current) { const rect = ref.current.getBoundingClientRect(); const centerX = rect.left + rect.width / 2; const centerY = rect.top + rect.height / 2; const distanceX = e.clientX - centerX; const distanceY = e.clientY - centerY; const absoluteDistance = Math.sqrt(distanceX ** 2 + distanceY ** 2); if (isHovered && absoluteDistance <= range) { const scale = 1 - absoluteDistance / range; x.set(distanceX * intensity * scale); y.set(distanceY * intensity * scale); } else { x.set(0); y.set(0); } } }; document.addEventListener('mousemove', calculateDistance); return () => { document.removeEventListener('mousemove', calculateDistance); }; }, [ref, isHovered, intensity, range]); useEffect(() => { if (actionArea === 'parent' && ref.current?.parentElement) { const parent = ref.current.parentElement; const handleParentEnter = () => setIsHovered(true); const handleParentLeave = () => setIsHovered(false); parent.addEventListener('mouseenter', handleParentEnter); parent.addEventListener('mouseleave', handleParentLeave); return () => { parent.removeEventListener('mouseenter', handleParentEnter); parent.removeEventListener('mouseleave', handleParentLeave); }; } else if (actionArea === 'global') { setIsHovered(true); } }, [actionArea]); const handleMouseEnter = () => { if (actionArea === 'self') { setIsHovered(true); } }; const handleMouseLeave = () => { if (actionArea === 'self') { setIsHovered(false); x.set(0); y.set(0); } }; return ( {children} ); }