'use client'
import * as React from 'react'
import { motion, type HTMLMotionProps, type Transition } from 'motion/react'
import type { VariantProps } from 'class-variance-authority'
import { cn } from '@/lib/utils'
import { buttonVariants } from '@/components/ui/button'
interface Position {
x: number
y: number
}
interface MagneticButtonProps extends HTMLMotionProps<'button'>, VariantProps<typeof buttonVariants> {
scale?: number
transition?: Transition
}
function MagneticButton({ className, size, variant, ...props }: MagneticButtonProps) {
const ref = React.useRef<HTMLButtonElement>(null)
const [position, setPosition] = React.useState<Position>({ x: 0, y: 0 })
const handleMouse = (e: React.MouseEvent<HTMLButtonElement>) => {
if (ref.current) {
const { clientX, clientY } = e
const { height, width, left, top } = ref.current.getBoundingClientRect()
const middleX = clientX - (left + width / 2)
const middleY = clientY - (top + height / 2)
setPosition({ x: middleX, y: middleY })
}
}
const reset = () => {
setPosition({ x: 0, y: 0 })
}
const { x, y } = position
return (
<motion.button
ref={ref}
onMouseMove={handleMouse}
onMouseLeave={reset}
animate={{ x, y }}
transition={{ type: 'spring', stiffness: 170, damping: 18, mass: 0.1 }}
whileTap={{
scale: 0.75
}}
className={cn(buttonVariants({ variant, size }), 'relative transition-none', className)}
{...props}
>
Magnetic Button
</motion.button>
)
}
export { MagneticButton, type MagneticButtonProps }