import React, { useEffect, useState } from "react"; import ReactDOM from "react-dom"; import { usePopper } from "react-popper"; import styled from "styled-components"; import { editingCellContext } from "../context/EditorContext"; import { hoveredCellContext } from "../context/hoveredCellContext"; import { isSelectingContext } from "../context/SelectionContext"; const HOVER_DELAY_MS = 500; /** * This positions the error tooltips on the correct cell. The same component is * reused for every cell, so only one error tooltip can ever be present */ export const ErrorTooltip = ({ renderErrorTooltip, errors, }: { renderErrorTooltip: (error: TError) => React.ReactNode; errors: (TError | null)[][]; }) => { const { el, x, y } = hoveredCellContext.useState() ?? {}; const isSelecting = isSelectingContext.useState(); const editingCell = editingCellContext.useState(); const [tooltipElement, setTooltipElement] = useState( null ); const errorData = x !== undefined && y !== undefined ? errors[y][x] : null; const error = editingCell ? null : errorData; const { styles, attributes } = usePopper(error ? el : null, tooltipElement, { placement: "bottom-start", }); const [visible, setVisible] = useState(false); useEffect(() => { setVisible(false); if (error) { const timeout = setTimeout(() => setVisible(true), HOVER_DELAY_MS); return () => clearTimeout(timeout); } return; }, [error, x, y, isSelecting]); return ReactDOM.createPortal( {error && x !== undefined && renderErrorTooltip(error)} , document.body ); }; const TooltipContainer = styled.div<{ visible: boolean }>` display: ${({ visible }) => (visible ? "block" : "none")}; z-index: 10; `;