import type { ComponentType } from "react"
import { useEffect, useRef, useState } from "react"
import { motion, useMotionValue } from "framer-motion"
export function withFollowCursor(Component): ComponentType {
return (props) => {
const rotation = useMotionValue(0)
const [position, setPosition] = useState(null)
const componentRef = useRef()
const handleMove = (event) => {
let x, y
if (event.changedTouches) {
x = event.changedTouches[0].clientX
y = event.changedTouches[0].clientY
} else {
x = event.clientX
y = event.clientY
}
setPosition({ x, y })
}
useEffect(() => {
window.addEventListener("mousemove", handleMove)
window.addEventListener("touchmove", handleMove)
return () => {
window.removeEventListener("mousemove", handleMove)
window.removeEventListener("touchmove", handleMove)
}
}, [])
useEffect(() => {
const updateRotation = () => {
if (!componentRef.current || !position) return
const rect = componentRef.current.getBoundingClientRect()
const centerX = rect.left + rect.width / 2
const centerY = rect.top + rect.height / 2
const deltaY = position.y - centerY
const deltaX = position.x - centerX
const angle =
(Math.atan2(deltaY, deltaX) * (180 / Math.PI) + 360 + 90) %
360
rotation.set(angle)
requestAnimationFrame(updateRotation)
}
updateRotation()
}, [position])
return (
<Component
{...props}
ref={componentRef}
as={motion.div}
style={{
...props.style,
rotate: rotation,
transformOrigin: "center",
}}
/>
)
}
}