import "./Tooltip.css" ; import { Children , ComponentProps , FocusEvent , ReactElement , ReactNode , SyntheticEvent , forwardRef , useCallback } from "react" ; import { InternalProps , OmitInternalProps , StyledComponentProps , augmentElement , isNil , mergeProps , resolveChildren , useControllableState , useEventCallback , useId , useMergedRefs } from "../../shared" ; import { Overlay , OverlayArrow , OverlayPositionProp , isTargetParent , useOverlayPosition , useOverlayTrigger } from "../../overlay" ; import { useResponsiveValue , useThemeContext } from "../../styling" ; import { Div } from "../../html" ; import { TooltipTriggerContext } from "./TooltipTriggerContext" ; const DefaultElement = "div" ; export interface InnerTooltipTriggerProps extends InternalProps , Omit < StyledComponentProps < typeof DefaultElement > , "position" > { /**
     * Whether or not the tooltip element can flip when it will overflow it's boundary area.
     */ allowFlip ? : boolean ; /**
     * Whether or not the tooltip element position can change to prevent it from being cut off so that it stays visible within its boundary area.
     */ allowPreventOverflow ? : boolean ; /**
     * React children.
     */ children : ReactNode ; ignore containerElement ? : HTMLElement ; /**
     * The initial value of `open` when in auto controlled mode.
     */ defaultOpen ? : boolean ; /**
     * Whether or not the tooltip should be disabled, independent from the trigger.
     */ disabled ? : boolean ; param { SyntheticEvent } event param { boolean } isOpen returns { void } onOpenChange ? : ( event : SyntheticEvent , isOpen : boolean ) => void ; /**
    * Whether or not to show the tooltip.
    */ open ? : boolean | null ; /**
     * Position of the tooltip element related to the trigger.
     */ position ? : OverlayPositionProp ; /**
     * The z-index of the popover element.
     */ zIndex ? : number ; } export function parseTooltipTrigger ( children ) { const array = Children . toArray ( resolveChildren ( children ) ) ; if ( array . length !== 2 ) { throw new Error ( "A tooltip trigger must have exactly 2 children." ) ; } return array as [ ReactElement , ReactElement ] ; } export function InnerTooltipTrigger ( { allowFlip = true , allowPreventOverflow = true , as = DefaultElement , children , containerElement , defaultOpen , disabled , forwardedRef , onOpenChange , open , position : positionProp = "top" , zIndex = 10000 , ... rest } ) { const positionValue = useResponsiveValue ( positionProp ) ; const { themeAccessor } = useThemeContext ( ) ; const [ isOpen , setIsOpen ] = useControllableState ( open , defaultOpen , false ) ; const updateIsOpen = useCallback ( ( event , newValue ) => { if ( isOpen !== newValue ) { setIsOpen ( newValue ) ; if ( ! isNil ( onOpenChange ) ) { onOpenChange ( event , newValue ) ; } } } , [ onOpenChange , isOpen , setIsOpen ] ) ; const close = useCallback ( ( event ) => { updateIsOpen ( event , false ) ; } , [ updateIsOpen ] ) ; const { arrowRef , overlayRef : overlayPositionRef , triggerRef } = useOverlayPosition ( { allowFlip , allowPreventOverflow , boundaryElement : containerElement , hasArrow : true , position : positionValue } ) ; const overlayRef = useMergedRefs ( overlayPositionRef , forwardedRef ) ; const triggerProps = useOverlayTrigger ( isOpen , { hideOnLeave : true , isDisabled : disabled , onHide : useEventCallback ( ( event ) => { if ( ! isTargetParent ( ( event as FocusEvent ) . relatedTarget , overlayRef ) ) { updateIsOpen ( event , false ) ; } } ) , onShow : useEventCallback ( ( event ) => { updateIsOpen ( event , true ) ; } ) , trigger : "hover" } ) ; const [ trigger , tooltip ] = parseTooltipTrigger ( children ) ; const tooltipId = useId ( tooltip . props . id , "o-ui-tooltip" ) ; const triggerWithDescribedBy = augmentElement ( trigger , { "aria-describedby" : isOpen ? tooltipId : undefined } ) ; const triggerElement = ! triggerWithDescribedBy . props . disabled ? triggerWithDescribedBy : ( < Div className = "o-ui-tooltip-disabled-wrapper" > { triggerWithDescribedBy } < /Div>); const triggerMarkup = augmentElement ( triggerElement , mergeProps ( triggerProps , { ref : triggerRef } ) ) ; const tooltipMarkup = augmentElement ( tooltip , { id : tooltipId } ) ; return ( < TooltipTriggerContext . Provider value = { { close , isOpen } } > { triggerMarkup } < Overlay { ... mergeProps ( rest , { as , borderOffset : themeAccessor . getSpace ( 3 ) , ref : overlayRef , show : isOpen , zIndex } ) } > { tooltipMarkup } < OverlayArrow ref = { arrowRef } zIndex = { zIndex + 100 } /> < /Overlay> < /TooltipTriggerContext.Provider>); } InnerTooltipTrigger . defaultElement = DefaultElement ; export const TooltipTrigger = forwardRef < any , OmitInternalProps < InnerTooltipTriggerProps > > ( ( props , ref ) => ( < InnerTooltipTrigger { ... props } forwardedRef = { ref } / > ) ) ; export type TooltipTriggerProps = ComponentProps < typeof TooltipTrigger > ;