Files
portifolio-evandrodevbr/app/components/cinematic/MagneticButton.tsx
T

112 lines
2.4 KiB
TypeScript

"use client";
import { motion } from "motion/react";
import { type MouseEvent, type ReactNode, useState } from "react";
interface MagneticButtonProps {
children: ReactNode;
className?: string;
href?: string;
onClick?: () => void;
strength?: number;
as?: "a" | "button" | "div" | "span" | "li";
target?: string;
rel?: string;
download?: boolean | string;
type?: "button" | "submit" | "reset";
wrapperClassName?: string;
"aria-label"?: string;
}
export default function MagneticButton({
children,
className = "",
href,
onClick,
strength = 0.3,
as = "button",
target,
rel,
download,
type,
wrapperClassName = "",
"aria-label": ariaLabel,
}: MagneticButtonProps) {
const [position, setPosition] = useState({ x: 0, y: 0 });
const handleMouse = (e: MouseEvent<HTMLElement>) => {
const rect = e.currentTarget.getBoundingClientRect();
const centerX = rect.left + rect.width / 2;
const centerY = rect.top + rect.height / 2;
setPosition({
x: (e.clientX - centerX) * strength,
y: (e.clientY - centerY) * strength,
});
};
const handleMouseLeave = () => {
setPosition({ x: 0, y: 0 });
};
const Tag =
as === "a"
? motion.a
: as === "button"
? motion.button
: as === "div"
? motion.div
: as === "span"
? motion.span
: motion.li;
const linkProps = as === "a" ? { href, target, rel, download } : {};
const buttonProps = as === "button" ? { type } : {};
const motionProps = {
animate: {
x: position.x,
y: position.y,
},
transition: {
type: "spring" as const,
stiffness: 350,
damping: 15,
mass: 0.5,
},
};
if (as === "li") {
return (
<Tag
className={`${className} ${wrapperClassName}`.trim()}
onMouseMove={handleMouse}
onMouseLeave={handleMouseLeave}
onClick={onClick}
{...motionProps}
{...linkProps}
{...buttonProps}
aria-label={ariaLabel}
>
{children}
</Tag>
);
}
return (
<div className={`inline-block ${wrapperClassName}`.trim()}>
<Tag
className={className}
onMouseMove={handleMouse}
onMouseLeave={handleMouseLeave}
onClick={onClick}
{...motionProps}
{...linkProps}
{...buttonProps}
aria-label={ariaLabel}
>
{children}
</Tag>
</div>
);
}