"use client";
import { AnimatePresence, motion, useMotionValue } from "framer-motion";
import React, { useEffect } from "react";
import clsx from "clsx";
const PointerCard = ({ title }: { title: string }) => {
const x = useMotionValue(0);
const y = useMotionValue(0);
const ref = React.useRef<HTMLDivElement>(null);
const [rect, setRect] = React.useState<DOMRect | null>(null);
const [isInside, setIsInside] = React.useState(false);
useEffect(() => {
if (ref.current) {
setRect(ref.current.getBoundingClientRect());
}
}, []);
const handleMouseMove = (event: { clientX: number; clientY: number }) => {
if (rect) {
const newX = event.clientX - rect.left;
const newY = event.clientY - rect.top;
x.set(newX);
y.set(newY);
console.log('PointerCard - x:', newX, 'y:', newY);
}
};
const handleMouseLeave = () => {
setIsInside(false);
};
const handleMouseEnter = () => {
setIsInside(true);
};
const colors = [
"var(--red-200)",
"var(--blue-200)",
"var(--green-200)",
"var(--yellow-200)",
"var(--orange-200)",
"var(--indigo-200)",
];
const randomColor = colors[Math.floor(Math.random() * colors.length)];
useEffect(() => {
const unsubscribeX = x.onChange(latestX => {
console.log('x:', latestX);
});
const unsubscribeY = y.onChange(latestY => {
console.log('y:', latestY);
});
return () => {
unsubscribeX();
unsubscribeY();
};
}, [x, y]);
return (
<div
ref={ref}
onMouseMove={handleMouseMove}
onMouseLeave={handleMouseLeave}
onMouseEnter={handleMouseEnter}
style={{ cursor: "none" }}
className={clsx(
"relative w-72 h-72 bg-[#ff8ba7] rounded-lg flex items-center justify-center ml-[100px]"
)}
>
<AnimatePresence>
{isInside && (
<motion.div
className="absolute z-50 rounded-full"
style={{
top: y.get(),
left: x.get(),
pointerEvents: "none",
}}
initial={{
scale: 0,
opacity: 0,
}}
animate={{
scale: 1,
opacity: 1,
}}
exit={{
scale: 0,
opacity: 0,
}}
>
<svg
stroke="currentColor"
fill="currentColor"
strokeWidth="1"
viewBox="0 0 16 16"
className="h-6 w-6 text-sky-500 transform -rotate-[70deg] -translate-x-[12px] -translate-y-[10px] stroke-sky-600"
height="1em"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M14.082 2.182a.5.5 0 0 1 .103.557L8.528 15.467a.5.5 0 0 1-.917-.007L5.57 10.694.803 8.652a.5.5 0 0 1-.006-.916l12.728-5.657a.5.5 0 0 1 .556.103z"></path>
</svg>
<motion.div
style={{
backgroundColor: randomColor,
}}
initial={{
scale: 0.5,
opacity: 0,
}}
animate={{
scale: 1,
opacity: 1
}}
exit={{
scale: 0.5,
opacity: 0,
}}
className={clsx(
"px-2 py-2 text-white whitespace-nowrap min-w-max text-xs rounded-full"
)}
>
{title || "Hello"}
</motion.div>
</motion.div>
)}
</AnimatePresence>
<div>{title}</div>
</div>
);
};
export default PointerCard;
this is my component where on hovering the card a custom pointer is supposed to pop up. The problem i am facing is that , everytime i hover the card the custom pointer is sticking to the border of the card. I’ve even checked that the x and y values are calculated correctly with respect to the card’s dimensions. Can someone tell me how to modify such that the pointer moves smoothly even inside the card
New contributor
Suhas A is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.