/** @flow */ import * as React from 'react'; import {useRef} from 'react'; import styles from './Tooltip.css'; const initialTooltipState = {height: 0, mouseX: 0, mouseY: 0, width: 0}; export default function Tooltip({children, label}: any) { const containerRef = useRef(null); const tooltipRef = useRef(null); // update the position of the tooltip based on current mouse position const updateTooltipPosition = (event: SyntheticMouseEvent<*>) => { const element = tooltipRef.current; if (element != null) { // first find the mouse position const mousePosition = getMousePosition(containerRef.current, event); // use the mouse position to find the position of tooltip const {left, top} = getTooltipPosition(element, mousePosition); // update tooltip position element.style.left = left; element.style.top = top; } }; const onMouseMove = (event: SyntheticMouseEvent<*>) => { updateTooltipPosition(event); }; const tooltipClassName = label === null ? styles.hidden : ''; return (
{label}
{children}
); } const TOOLTIP_OFFSET = 5; // Method used to find the position of the tooltip based on current mouse position function getTooltipPosition(element, mousePosition) { const {height, mouseX, mouseY, width} = mousePosition; let top = 0; let left = 0; if (mouseY + TOOLTIP_OFFSET + element.offsetHeight >= height) { if (mouseY - TOOLTIP_OFFSET - element.offsetHeight > 0) { top = `${mouseY - element.offsetHeight - TOOLTIP_OFFSET}px`; } else { top = '0px'; } } else { top = `${mouseY + TOOLTIP_OFFSET}px`; } if (mouseX + TOOLTIP_OFFSET + element.offsetWidth >= width) { if (mouseX - TOOLTIP_OFFSET - element.offsetWidth > 0) { left = `${mouseX - element.offsetWidth - TOOLTIP_OFFSET}px`; } else { left = '0px'; } } else { left = `${mouseX + TOOLTIP_OFFSET * 2}px`; } return {left, top}; } // method used to find the current mouse position inside the container function getMousePosition( relativeContainer, mouseEvent: SyntheticMouseEvent<*>, ) { if (relativeContainer !== null) { // Position within the nearest position:relative container. let targetContainer = relativeContainer; while (targetContainer.parentElement != null) { if (targetContainer.style.position === 'relative') { break; } else { targetContainer = targetContainer.parentElement; } } const {height, left, top, width} = targetContainer.getBoundingClientRect(); const mouseX = mouseEvent.clientX - left; const mouseY = mouseEvent.clientY - top; return {height, mouseX, mouseY, width}; } else { return initialTooltipState; } }