import React, { useCallback, useState, useMemo, isValidElement } from "react"; import { CellInterface, GridRef } from "../Grid"; export interface TooltipOptions { /** * Tooltip component */ component?: React.FC | React.ComponentClass; /** * Grid references */ gridRef: React.MutableRefObject; /** * Tooltip value getter of a cell */ getValue: (cell: CellInterface) => any; } export interface TooltipResults { /** * Tooltip component to inject into the page */ tooltipComponent: React.ReactElement | null; /** * Mousemove listener to align tooltip */ onMouseMove: (e: React.MouseEvent) => void; /** * Mouse leave listener to hide tooltip */ onMouseLeave: (e: React.MouseEvent) => void; } export interface TooltipProps { /** * Tooltip content */ content: string; /** * Tooltip x position */ x: number; /** * Tooltip y position */ y: number; } const DefaultTooltipComponent: React.FC = ({ content, x, y }) => { const offset = 10; return (
{content}
); }; const useTooltip = ({ getValue, gridRef, component: Component = DefaultTooltipComponent, }: TooltipOptions): TooltipResults => { const [activeCell, setActiveCell] = useState(null); const [tooltipPosition, setTooltipPosition] = useState< Pick >({ x: 0, y: 0 }); const content = useMemo( () => (activeCell ? getValue(activeCell) ?? null : null), [activeCell] ); const showTooltip = activeCell && content !== null; const tooltipProps: TooltipProps = { content, x: tooltipPosition.x, y: tooltipPosition.y, }; const tooltipComponent = showTooltip ? : null; const handleMouseMove = useCallback( (e: React.MouseEvent) => { const coords = gridRef.current.getCellCoordsFromOffset( e.clientX, e.clientY ); if (!coords) return; const { rowIndex, columnIndex } = coords; setTooltipPosition({ x: e.clientX, y: e.clientY, }); /* Exit if its the same cell */ if ( activeCell && activeCell.rowIndex === rowIndex && activeCell.columnIndex === columnIndex ) return; setActiveCell({ rowIndex, columnIndex }); }, [activeCell] ); const handleMouseLeave = useCallback((e) => { setActiveCell(null); }, []); return { tooltipComponent, onMouseMove: handleMouseMove, onMouseLeave: handleMouseLeave, }; }; export default useTooltip;