Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | /**
* @fileoverview Custom Tooltip Component
* @description Styled tooltips to replace native title attributes
* @module components/Tooltip
*/
import { useState, useRef, useEffect } from 'react';
import './Tooltip.css';
/**
* Tooltip Component
*/
function Tooltip({ children, content, position = 'top', delay = 300 }) {
const [isVisible, setIsVisible] = useState(false);
const [coords, setCoords] = useState({ x: 0, y: 0 });
const timeoutRef = useRef(null);
const triggerRef = useRef(null);
const showTooltip = () => {
timeoutRef.current = setTimeout(() => {
if (triggerRef.current) {
const rect = triggerRef.current.getBoundingClientRect();
setCoords({
x: rect.left + rect.width / 2,
y: position === 'top' ? rect.top : rect.bottom
});
setIsVisible(true);
}
}, delay);
};
const hideTooltip = () => {
clearTimeout(timeoutRef.current);
setIsVisible(false);
};
useEffect(() => {
return () => clearTimeout(timeoutRef.current);
}, []);
if (!content) return children;
return (
<>
<span
ref={triggerRef}
className="tooltip-trigger"
onMouseEnter={showTooltip}
onMouseLeave={hideTooltip}
onFocus={showTooltip}
onBlur={hideTooltip}
>
{children}
</span>
{isVisible && (
<div
className={`tooltip tooltip-${position}`}
style={{
left: coords.x,
top: coords.y
}}
>
{content}
<div className="tooltip-arrow" />
</div>
)}
</>
);
}
export default Tooltip;
|