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