mirror of
https://github.com/Since-3/since3-website.git
synced 2026-10-12 19:51:16 +00:00
55 lines
1.4 KiB
TypeScript
55 lines
1.4 KiB
TypeScript
"use client"
|
|
|
|
import { useEffect, useRef } from "react"
|
|
|
|
import { cn } from "@/lib/utils"
|
|
|
|
/** Pulls its child towards the pointer while hovered. */
|
|
export function Magnetic({
|
|
children,
|
|
strength = 0.35,
|
|
className,
|
|
}: {
|
|
children: React.ReactNode
|
|
strength?: number
|
|
className?: string
|
|
}) {
|
|
const ref = useRef<HTMLDivElement>(null)
|
|
|
|
useEffect(() => {
|
|
const el = ref.current
|
|
if (!el) return
|
|
const fine = window.matchMedia("(hover: hover) and (pointer: fine)").matches
|
|
const reduced = window.matchMedia("(prefers-reduced-motion: reduce)").matches
|
|
if (!fine || reduced) return
|
|
|
|
const onMove = (event: PointerEvent) => {
|
|
const rect = el.getBoundingClientRect()
|
|
const dx = event.clientX - (rect.left + rect.width / 2)
|
|
const dy = event.clientY - (rect.top + rect.height / 2)
|
|
el.style.translate = `${dx * strength}px ${dy * strength}px`
|
|
}
|
|
const onLeave = () => {
|
|
el.style.translate = "0px 0px"
|
|
}
|
|
|
|
el.addEventListener("pointermove", onMove)
|
|
el.addEventListener("pointerleave", onLeave)
|
|
return () => {
|
|
el.removeEventListener("pointermove", onMove)
|
|
el.removeEventListener("pointerleave", onLeave)
|
|
}
|
|
}, [strength])
|
|
|
|
return (
|
|
<div
|
|
ref={ref}
|
|
className={cn(
|
|
"inline-block transition-[translate] duration-700 ease-out-expo",
|
|
className
|
|
)}
|
|
>
|
|
{children}
|
|
</div>
|
|
)
|
|
}
|