Spaces:
Sleeping
Sleeping
File size: 1,443 Bytes
02e775b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | 'use client';
import { useRef, useState } from 'react';
import { motion } from 'framer-motion';
/**
* MagneticButton — a button that gravitates toward the cursor.
*
* As the mouse gets close, the button slightly moves toward it.
* Creates a premium, tactile feel that reduces click friction.
*/
export function MagneticButton({ children, className = '', onClick, disabled }: {
children: React.ReactNode;
className?: string;
onClick?: () => void;
disabled?: boolean;
}) {
const ref = useRef<HTMLButtonElement>(null);
const [offset, setOffset] = useState({ x: 0, y: 0 });
const handleMouseMove = (e: React.MouseEvent) => {
if (disabled) return;
const el = ref.current;
if (!el) return;
const rect = el.getBoundingClientRect();
const centerX = rect.left + rect.width / 2;
const centerY = rect.top + rect.height / 2;
const dx = (e.clientX - centerX) * 0.3; // 30% magnetic pull
const dy = (e.clientY - centerY) * 0.3;
setOffset({ x: dx, y: dy });
};
const handleMouseLeave = () => {
setOffset({ x: 0, y: 0 });
};
return (
<motion.button
ref={ref}
onMouseMove={handleMouseMove}
onMouseLeave={handleMouseLeave}
onClick={onClick}
disabled={disabled}
animate={{ x: offset.x, y: offset.y }}
transition={{ type: 'spring', stiffness: 300, damping: 20 }}
className={className}
>
{children}
</motion.button>
);
}
|