Follower Pointer
Preview
Vercel
Code
"use client";
import { motion, useMotionValue, useSpring } from "framer-motion";
import React, { type FC, type ReactNode, useRef } from "react";
import { cn } from "@/lib/utils";
interface FollowerPointerProps {
children: ReactNode;
title?: ReactNode;
className?: string;
}
const FollowerPointer: FC<FollowerPointerProps> = ({
children,
title,
className,
}) => {
const ref = useRef<HTMLDivElement>(null);
const x = useMotionValue(0);
const y = useMotionValue(0);
const springConfig = { damping: 30, stiffness: 200, mass: 0.5 };
const xSpring = useSpring(x, springConfig);
const ySpring = useSpring(y, springConfig);
const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {
if (!ref.current) return;
const rect = ref.current.getBoundingClientRect();
x.set(e.clientX - rect.left);
y.set(e.clientY - rect.top);
};
return (
<div
ref={ref}
onMouseMove={handleMouseMove}
className={cn("relative", className)}
>
<motion.div
style={{
translateX: xSpring,
translateY: ySpring,
}}
className="absolute left-0 top-0 h-4 w-4 rounded-full bg-purple-500 pointer-events-none"
>
{title && (
<motion.div
initial={{ scale: 0.5, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
exit={{ scale: 0.5, opacity: 0 }}
className="absolute top-full left-1/2 -translate-x-1/2 whitespace-nowrap mt-2"
>
<div className="px-2 py-1 rounded-md bg-black/80 text-white text-xs border border-white/10 backdrop-blur-sm">
{title}
</div>
</motion.div>
)}
</motion.div>
{children}
</div>
);
};
export default FollowerPointer;