'use client'; import { useState, useEffect, useRef } from 'react'; import styles from './magnet.module.css'; export interface MagnetProps { /** Child elements to apply magnet effect */ children: React.ReactNode; /** Padding around element to trigger effect (pixels) */ padding?: number; /** Disable the magnet effect */ disabled?: boolean; /** Strength of attraction (higher = less movement) */ magnetStrength?: number; /** Transition when active/attracted */ activeTransition?: string; /** Transition when inactive/released */ inactiveTransition?: string; /** Class for wrapper div */ wrapperClassName?: string; /** Class for inner div */ innerClassName?: string; } const Magnet: React.FC = ({ children, padding = 100, disabled = false, magnetStrength = 2, activeTransition = 'transform 0.3s ease-out', inactiveTransition = 'transform 0.5s ease-in-out', wrapperClassName = '', innerClassName = '', }) => { const [isActive, setIsActive] = useState(false); const [position, setPosition] = useState({ x: 0, y: 0 }); const magnetRef = useRef(null); useEffect(() => { if (disabled) { setPosition({ x: 0, y: 0 }); return; } const handleMouseMove = (e: MouseEvent) => { if (!magnetRef.current) return; const { left, top, width, height } = magnetRef.current.getBoundingClientRect(); const centerX = left + width / 2; const centerY = top + height / 2; const distX = Math.abs(centerX - e.clientX); const distY = Math.abs(centerY - e.clientY); if (distX < width / 2 + padding && distY < height / 2 + padding) { setIsActive(true); const offsetX = (e.clientX - centerX) / magnetStrength; const offsetY = (e.clientY - centerY) / magnetStrength; setPosition({ x: offsetX, y: offsetY }); } else { setIsActive(false); setPosition({ x: 0, y: 0 }); } }; window.addEventListener('mousemove', handleMouseMove); return () => { window.removeEventListener('mousemove', handleMouseMove); }; }, [padding, disabled, magnetStrength]); const transitionStyle = isActive ? activeTransition : inactiveTransition; return (
{children}
); }; export default Magnet;