// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 import React, { useCallback, useEffect, useState } from 'react'; import ReactDOM from 'react-dom'; import { useLogger } from '../../../providers/LoggerProvider'; import { StyledTooltip } from './Styled'; export type ToolTipPositionType = 'top' | 'bottom' | 'right' | 'left'; export interface Tooltipable { /* Put tooltips on any buttons */ ['data-tooltip']?: boolean; /* Tooltips location on any buttons */ ['data-tooltip-position']?: ToolTipPositionType; /* The element ID of an existing element to render tooltips into */ tooltipContainerId?: string; /* Content for tooltip. Falls back to the label */ tooltipContent?: React.ReactNode; } export interface ToolTipProps { label?: string; tooltipContent?: React.ReactNode; tooltipPosition?: ToolTipPositionType; } interface WithTooltipState { bounds: DOMRect | null; show: boolean; } const initialState: WithTooltipState = { show: false, bounds: null }; export const WithTooltip =

( Component: React.ComponentType>, container_id?: string ) => (props: P & ToolTipProps) => { const logger = useLogger(); const [{ show, bounds }, setShow] = useState(initialState); const [container, setContainer] = useState(null); const position = props.tooltipPosition ?? 'top'; const showToolTip = useCallback((e: Event) => { e.preventDefault(); e.stopPropagation(); let component = e.target as Element; while (!component.getAttribute('data-tooltip')) component = component.parentElement as Element; const bounds = component.getBoundingClientRect(); setShow({ show: true, bounds }); }, []); const hideToolTip = useCallback((e: Event) => { e.preventDefault(); e.stopPropagation(); setShow(initialState); }, []); useEffect(() => { document.addEventListener('scroll', hideToolTip, true); return () => document.removeEventListener('scroll', hideToolTip, true); }, []); useEffect(() => { const container = document.getElementById( container_id || 'Tooltip__container' ); if (!container) { logger.warn( `Attempted to use 'WithTooltip' but could not find container element.Pass a valid element ID or add 'Tooltip__container' ID to existing element` ); return; } setContainer(container); }, [container_id]); return ( <> {show && bounds && container && ReactDOM.createPortal( {props.tooltipContent || props.label} , container )} { if (show) hideToolTip(e); (props as any)?.onClick?.(e); }} onFocus={(e: FocusEvent) => { if (!show) showToolTip(e); (props as any)?.onFocus?.(e); }} onBlur={(e: FocusEvent) => { if (show) hideToolTip(e); (props as any)?.onBlur?.(e); }} onMouseEnter={(e: MouseEvent) => { if (!show) showToolTip(e); (props as any)?.onMouseEnter?.(e); }} onMouseLeave={(e: MouseEvent) => { if (show) hideToolTip(e); (props as any)?.onMouseLeave?.(e); }} /> ); };