import type { ComponentType } from "react"
import { useEffect, useRef } from "react"
import { motion } from "framer-motion"
export function withColorfulGradientHover(
Component,
colors = ["turquoise", "violet", "blue", "pink"]
): ComponentType {
return (props) => {
const gradientRef = useRef(null)
const containerRef = useRef(null)
const cursorPosition = useRef({
x: window.innerWidth / 2,
y: window.innerHeight / 2,
})
const handleMouseMove = (event) => {
cursorPosition.current = { x: event.clientX, y: event.clientY }
}
const handleTouchMove = (event) => {
cursorPosition.current = {
x: event.touches[0].clientX,
y: event.touches[0].clientY,
}
}
useEffect(() => {
window.addEventListener("mousemove", handleMouseMove)
window.addEventListener("touchmove", handleTouchMove)
return () => {
window.removeEventListener("mousemove", handleMouseMove)
window.removeEventListener("touchmove", handleTouchMove)
}
}, [])
useEffect(() => {
const updateGradientPosition = () => {
if (!containerRef.current || !gradientRef.current) return
const rect = containerRef.current.getBoundingClientRect()
const mouseX = cursorPosition.current.x - rect.left
const mouseY = cursorPosition.current.y - rect.top
gradientRef.current.style.setProperty("--x", `${mouseX}px`)
gradientRef.current.style.setProperty("--y", `${mouseY}px`)
requestAnimationFrame(updateGradientPosition)
}
updateGradientPosition()
}, [])
const gradientBackground = `radial-gradient(circle at var(--x, 20%) var(--y, 20%), ${colors.join(
", "
)})`
return (
<Component
{...props}
as={motion.div}
ref={containerRef}
style={{
...props.style,
position: "relative",
overflow: "hidden",
}}
>
<motion.div
ref={gradientRef}
style={{
position: "absolute",
top: 0,
left: 0,
width: "100%",
height: "100%",
background: gradientBackground,
mixBlendMode: "overlay",
transition: "background-position 0.2s",
}}
initial={{ scale: 1 }}
animate={{ scale: 1 }}
exit={{ scale: 0 }}
transition={{ duration: 0.4 }}
/>
{props.children}
</Component>
)
}
}