import React , { useCallback , useContext , useMemo , useState } from 'react' ; import { createPortal } from 'react-dom' ; import { PortalContext } from 'reakit' ; import TooltipWrapper from './TooltipWrapper' ; type OpenFn = ( e : React . MouseEvent , target : HTMLElement ) => void ; type CloseFn = ( ) => void ; type State = { isOpen : false ; } | { isOpen : true ; clickPoint : { clientX : number ; clientY : number ; } ; target : HTMLElement ; } ; export default function usePopover ( opts , render ) { const [ state , setState ] = useState < State > ( { isOpen : false , } ) ; const open = useCallback < OpenFn > ( ( e , target ) => { setState ( { isOpen : true , clickPoint : { clientX : e . clientX , clientY : e . clientY } , target , } ) ; } , [ ] ) ; const close = useCallback < CloseFn > ( ( ) => { setState ( { isOpen : false } ) ; } , [ ] ) ; const onClickOutside = useCallback ( ( ) => { if ( opts . closeOnClickOutside !== false ) { close ( ) ; } } , [ opts . closeOnClickOutside ] ) ; const portalLayer = useContext ( PortalContext ) ; const onPointerOutside = useMemo ( ( ) => { if ( opts . closeWhenPointerIsDistant === false ) return undefined ; return { threshold : opts . pointerDistanceThreshold ?? 100 , callback : close , } ; } , [ opts . closeWhenPointerIsDistant ] ) ; const node = state . isOpen ? ( createPortal ( < TooltipWrapper children = { render } target = { state . target } onClickOutside = { onClickOutside } onPointerOutside = { onPointerOutside } / > , portalLayer ! ) ) : ( < > < />); return [ node , open , close , state . isOpen ] ; }