e4dcfc49aa
Tests / Import Check (Python 3.13) (push) Has been cancelled
Tests / Import Check (Python 3.14) (push) Has been cancelled
Tests / Python Tests (Python 3.11) (push) Has been cancelled
Tests / Python Tests (Python 3.12) (push) Has been cancelled
Tests / Python Tests (Python 3.14) (push) Has been cancelled
Tests / Test Summary (push) Has been cancelled
Tests / Lint and Format (push) Has been cancelled
Tests / Web Node Tests (push) Has been cancelled
Tests / Import Check (Python 3.11) (push) Has been cancelled
Tests / Import Check (Python 3.12) (push) Has been cancelled
Tests / Python Tests (Python 3.13) (push) Has been cancelled
74 lines
1.6 KiB
TypeScript
74 lines
1.6 KiB
TypeScript
"use client";
|
|
|
|
import {
|
|
ReactNode,
|
|
useState,
|
|
useCallback,
|
|
useEffect,
|
|
useRef,
|
|
useId,
|
|
} from "react";
|
|
|
|
interface TooltipProps {
|
|
label: string;
|
|
description?: string;
|
|
children: ReactNode;
|
|
side?: "right" | "bottom";
|
|
}
|
|
|
|
export function Tooltip({
|
|
label,
|
|
description,
|
|
children,
|
|
side = "right",
|
|
}: TooltipProps) {
|
|
const [visible, setVisible] = useState(false);
|
|
const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
const tooltipId = useId();
|
|
|
|
const showTooltip = useCallback(() => {
|
|
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
|
timeoutRef.current = setTimeout(() => setVisible(true), 300);
|
|
}, []);
|
|
|
|
const showNow = useCallback(() => {
|
|
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
|
setVisible(true);
|
|
}, []);
|
|
|
|
const hideTooltip = useCallback(() => {
|
|
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
|
setVisible(false);
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
return () => {
|
|
if (timeoutRef.current) clearTimeout(timeoutRef.current);
|
|
};
|
|
}, []);
|
|
|
|
return (
|
|
<div
|
|
className="dt-tooltip-wrapper"
|
|
onMouseEnter={showTooltip}
|
|
onMouseLeave={hideTooltip}
|
|
onFocus={showNow}
|
|
onBlur={hideTooltip}
|
|
aria-describedby={visible ? tooltipId : undefined}
|
|
>
|
|
{children}
|
|
{visible && (
|
|
<div
|
|
id={tooltipId}
|
|
className="dt-tooltip-content"
|
|
data-side={side}
|
|
role="tooltip"
|
|
>
|
|
<div className="dt-tooltip-label">{label}</div>
|
|
{description && <div className="dt-tooltip-desc">{description}</div>}
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|