48 lines
1.2 KiB
TypeScript
48 lines
1.2 KiB
TypeScript
'use client'
|
|
|
|
import clsx from "clsx";
|
|
import React, { useEffect, useState } from "react";
|
|
|
|
interface CursorPopoverProps {
|
|
text: string;
|
|
}
|
|
|
|
interface PoopoverTextProps extends CursorPopoverProps {
|
|
children: React.ReactNode
|
|
}
|
|
|
|
export const CursorPopover: React.FC<CursorPopoverProps> = ({ text }) => {
|
|
const [position, setPosition] = useState({ x: 0, y: 0 });
|
|
|
|
useEffect(() => {
|
|
const handleMouseMove = (e: MouseEvent) => {
|
|
setTimeout(() => setPosition({ x: e.clientX, y: e.clientY }), 50)
|
|
};
|
|
window.addEventListener("mousemove", handleMouseMove);
|
|
return () => {
|
|
window.removeEventListener("mousemove", handleMouseMove);
|
|
};
|
|
}, []);
|
|
|
|
return (
|
|
<div
|
|
className={clsx((position.x > 0 && position.y > 0) ? "fixed" : "hidden", "pointer-events-none text-white bg-background border border-primary px-3 py-1.5 text-sm z-[9999]")}
|
|
style={{ left: position.x + 12, top: position.y + 12 }}
|
|
>
|
|
{text}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export const PopoverText: React.FC<PoopoverTextProps> = ({ text, children }) => {
|
|
const [hovered, setHovered] = useState(false);
|
|
return (
|
|
<div
|
|
onMouseEnter={() => setHovered(true)}
|
|
onMouseLeave={() => setHovered(false)}
|
|
>
|
|
{hovered && <CursorPopover text={text} />}
|
|
{children}
|
|
</div>
|
|
)
|
|
} |