Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import { forwardRef, useEffect, useRef, type ComponentType } from "react"
- import { useMotionValue, useSpring } from "framer-motion"
- import { RenderTarget } from "framer"
- /* ───────────── SETTINGS (tweak these) ───────────── */
- const MAGNET = {
- strength: 0.35, // 0–1, how far the element follows the cursor
- radius: 120, // px around the element where the pull begins
- spring: { stiffness: 200, damping: 15, mass: 0.2 },
- }
- /* ───────────── Helpers ───────────── */
- const isCanvas = () => RenderTarget.current() === RenderTarget.canvas
- function mergeRefs(...refs: any[]) {
- return (node: any) => {
- refs.forEach((r) => {
- if (typeof r === "function") r(node)
- else if (r) r.current = node
- })
- }
- }
- /* ───────────── Override: Magnetic element ─────────────
- Apply to a button, card, logo, etc. */
- export function withMagnetic(Component: ComponentType<any>): ComponentType<any> {
- return forwardRef<any, any>((props, ref) => {
- const el = useRef<HTMLElement | null>(null)
- const x = useMotionValue(0)
- const y = useMotionValue(0)
- const sx = useSpring(x, MAGNET.spring)
- const sy = useSpring(y, MAGNET.spring)
- useEffect(() => {
- if (isCanvas()) return
- const onMove = (e: MouseEvent) => {
- const node = el.current
- if (!node) return
- const r = node.getBoundingClientRect()
- const cx = r.left + r.width / 2
- const cy = r.top + r.height / 2
- const dx = e.clientX - cx
- const dy = e.clientY - cy
- const reach = MAGNET.radius + Math.max(r.width, r.height) / 2
- if (Math.hypot(dx, dy) < reach) {
- x.set(dx * MAGNET.strength)
- y.set(dy * MAGNET.strength)
- } else {
- x.set(0)
- y.set(0)
- }
- }
- const reset = () => {
- x.set(0)
- y.set(0)
- }
- window.addEventListener("mousemove", onMove)
- document.addEventListener("mouseleave", reset)
- return () => {
- window.removeEventListener("mousemove", onMove)
- document.removeEventListener("mouseleave", reset)
- }
- }, [])
- return (
- <Component
- ref={mergeRefs(ref, el)}
- {...props}
- style={{ ...props.style, x: sx, y: sy }}
- />
- )
- })
- }
Advertisement
Add Comment
Please, Sign In to add comment