Fortura/apps/www/public/r/magnetic.json
2025-08-20 04:12:49 -06:00

18 lines
3.2 KiB
JSON

{
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
"name": "magnetic",
"type": "registry:ui",
"title": "Magnetic",
"description": "A magnetic effect that clings to the cursor, creating a magnetic attraction effect.",
"dependencies": [
"motion"
],
"files": [
{
"path": "registry/effects/magnetic/index.tsx",
"content": "'use client';\n\nimport * as React from 'react';\nimport {\n HTMLMotionProps,\n motion,\n useMotionValue,\n useSpring,\n type SpringOptions,\n} from 'motion/react';\n\ntype MagneticProps = {\n children: React.ReactElement;\n strength?: number;\n range?: number;\n springOptions?: SpringOptions;\n onlyOnHover?: boolean;\n disableOnTouch?: boolean;\n} & HTMLMotionProps<'div'>;\n\nfunction Magnetic({\n ref,\n children,\n strength = 0.5,\n range = 120,\n springOptions = { stiffness: 100, damping: 10, mass: 0.5 },\n onlyOnHover = false,\n disableOnTouch = true,\n style,\n onMouseEnter,\n onMouseLeave,\n onMouseMove,\n ...props\n}: MagneticProps) {\n const localRef = React.useRef<HTMLDivElement>(null);\n React.useImperativeHandle(ref, () => localRef.current as HTMLDivElement);\n\n const isTouchDevice = React.useMemo(() => {\n if (typeof window === 'undefined') return false;\n return window.matchMedia('(pointer:coarse)').matches;\n }, []);\n\n const [active, setActive] = React.useState(!onlyOnHover);\n\n const rawX = useMotionValue(0);\n const rawY = useMotionValue(0);\n const x = useSpring(rawX, springOptions);\n const y = useSpring(rawY, springOptions);\n\n const compute = React.useCallback(\n (e: MouseEvent | React.MouseEvent) => {\n if (!localRef.current) return;\n const { left, top, width, height } =\n localRef.current.getBoundingClientRect();\n const cx = left + width / 2;\n const cy = top + height / 2;\n const dx = e.clientX - cx;\n const dy = e.clientY - cy;\n const dist = Math.hypot(dx, dy);\n\n if ((active || !onlyOnHover) && dist <= range) {\n const factor = (1 - dist / range) * strength;\n rawX.set(dx * factor);\n rawY.set(dy * factor);\n } else {\n rawX.set(0);\n rawY.set(0);\n }\n },\n [active, onlyOnHover, range, strength, rawX, rawY],\n );\n\n React.useEffect(() => {\n if (disableOnTouch && isTouchDevice) return;\n const handle = (e: MouseEvent) => compute(e);\n window.addEventListener('mousemove', handle);\n return () => window.removeEventListener('mousemove', handle);\n }, [compute, disableOnTouch, isTouchDevice]);\n\n return (\n <motion.div\n ref={localRef}\n style={{ display: 'inline-block', ...style, x, y }}\n onMouseEnter={(e) => {\n if (onlyOnHover) setActive(true);\n onMouseEnter?.(e);\n }}\n onMouseLeave={(e) => {\n if (onlyOnHover) setActive(false);\n rawX.set(0);\n rawY.set(0);\n onMouseLeave?.(e);\n }}\n onMouseMove={(e) => {\n if (onlyOnHover) compute(e);\n onMouseMove?.(e);\n }}\n {...props}\n >\n {children}\n </motion.div>\n );\n}\n\nexport { Magnetic, type MagneticProps };\n",
"type": "registry:ui",
"target": "components/animate-ui/effects/magnetic.tsx"
}
]
}