import { createContext, memo, ReactElement, useCallback, useEffect, useMemo, useRef } from 'react'; import { ViewStyle, ViewProps } from 'react-native'; import { useSubcomponents, useToggle } from '../../hooks'; import { Popover, type PopoverProps } from '../Popover'; import { tooltipStyles } from './utils'; export type Props = Omit & { fadeInDelay?: number; fadeOutDelay?: number; showArrow?: boolean; style?: ViewStyle; children: ReactElement | ReactElement[]; hoverableContent?: boolean; }; const Tooltip = ({ style, children, fadeInDelay = 100, fadeOutDelay = 300, showArrow = false, hoverableContent = false, ...rest }: Props) => { const { state: isOpen, setState: setIsOpen } = useToggle(false); const triggerRef = useRef(null); const timeOutRef = useRef(undefined); const popoverTimeoutRef = useRef(undefined); const preventCloseRef = useRef(false); const onClose = useCallback(() => { if (preventCloseRef.current) return; clearTimeout(timeOutRef.current); timeOutRef.current = setTimeout(() => setIsOpen(false), fadeOutDelay); }, [fadeOutDelay, setIsOpen]); const onOpen = useCallback(() => { clearTimeout(timeOutRef.current); timeOutRef.current = setTimeout(() => setIsOpen(true), fadeInDelay); }, [fadeInDelay, setIsOpen]); // const setPopoverOpen = useCallback( // (_isOpen: boolean) => { // clearTimeout(popoverTimeoutRef.current); // popoverTimeoutRef.current = setTimeout( // () => setIsOpen(_isOpen), // isOpen ? fadeInDelay : fadeOutDelay, // ); // }, // [fadeInDelay, fadeOutDelay, isOpen, setIsOpen], // ); const { Tooltip_Trigger, Tooltip_Content } = useSubcomponents({ children, allowedChildren: ['Tooltip_Trigger', 'Tooltip_Content'], }); const contextValue = useMemo( () => ({ triggerRef, onOpen, onClose, }), [onClose, onOpen], ); const { popoverContentProps, popoverStyle } = useMemo( () => ({ popoverContentProps: (hoverableContent ? { onMouseEnter: () => { preventCloseRef.current = true; clearTimeout(timeOutRef.current); setIsOpen(true); }, onMouseLeave: () => { preventCloseRef.current = false; clearTimeout(timeOutRef.current); setIsOpen(false); }, } : {}) as ViewProps, popoverStyle: [tooltipStyles.content, style], }), [hoverableContent, setIsOpen, style], ); useEffect(() => { const popoverTimeout = popoverTimeoutRef; return () => { clearTimeout(timeOutRef.current); clearTimeout(popoverTimeout.current); }; }, []); return ( {Tooltip_Trigger[0]} {isOpen && ( {Tooltip_Content[0]} )} ); }; export const TooltipContext = createContext({ onOpen: () => {}, onClose: () => {}, triggerRef: null as any, }); export default memo(Tooltip);