{"version":3,"sources":["../src/components/Tooltip/useTooltip.ts"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport {\n  applyTriggerPropsToChildren,\n  getReactElementRef,\n  getTriggerChild,\n  mergeCallbacks,\n  slot,\n  useControllableState,\n  useEventCallback,\n  useId,\n  useIsomorphicLayoutEffect,\n  useIsSSR,\n  useMergedRefs,\n  useTimeout,\n} from '@fluentui/react-utilities';\nimport { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';\nimport type { KeyborgFocusInEvent } from '@fluentui/react-tabster';\nimport { KEYBORG_FOCUSIN, useIsNavigatingWithKeyboard } from '@fluentui/react-tabster';\n\nimport type { OnVisibleChangeData, TooltipProps, TooltipState, TooltipTriggerProps } from './Tooltip.types';\nimport { resolvePositioningShorthand, usePositioning } from '../../positioning';\nimport { stringifyDataAttribute } from '../../utils';\n\n/**\n * Create the state required to render Tooltip.\n *\n * @param props - props from this instance of Tooltip\n */\nexport const useTooltip = (props: TooltipProps): TooltipState => {\n  const isServerSideRender = useIsSSR();\n  const { targetDocument } = useFluent();\n\n  const [visible, setVisibleInternal] = useControllableState({ state: props.visible, initialState: false });\n\n  const {\n    children,\n    content,\n    positioning = 'above',\n    withArrow = false,\n    onVisibleChange,\n    relationship,\n    showDelay = 250,\n    hideDelay = 250,\n  } = props;\n\n  const state: TooltipState = {\n    positioning,\n    showDelay,\n    hideDelay,\n    relationship,\n    visible,\n    shouldRenderTooltip: visible,\n    withArrow,\n    // Slots\n    components: {\n      content: 'div',\n    },\n    content: slot.always(content, {\n      defaultProps: {\n        role: 'tooltip',\n        popover: 'hint',\n      },\n      elementType: 'div',\n    }),\n  };\n\n  const positioningOptions = resolvePositioningShorthand(positioning);\n  const { targetRef, containerRef } = usePositioning(positioningOptions);\n\n  state.content.id = useId('tooltip-', state.content.id);\n  state.content['data-open'] = stringifyDataAttribute(state.visible);\n\n  const contentRef = useMergedRefs(state.content.ref, containerRef);\n  state.content.ref = contentRef;\n\n  const [setDelayTimeout, clearDelayTimeout] = useTimeout();\n\n  const setVisible = React.useCallback(\n    (ev: React.PointerEvent<HTMLElement> | React.FocusEvent<HTMLElement> | undefined, data: OnVisibleChangeData) => {\n      clearDelayTimeout();\n      setVisibleInternal(oldVisible => {\n        if (data.visible !== oldVisible) {\n          onVisibleChange?.(ev, data);\n        }\n        return data.visible;\n      });\n    },\n    [clearDelayTimeout, setVisibleInternal, onVisibleChange],\n  );\n\n  const onToggle = useEventCallback((event: Event) => {\n    if ((event as ToggleEvent).newState === 'closed') {\n      setVisible(undefined, { visible: false });\n    }\n  });\n\n  // Keep the tooltip in sync with the state when it is changed programmatically.\n  // Also sync React state when the browser auto-dismisses the hint popover (click outside, Escape).\n  useIsomorphicLayoutEffect(() => {\n    const el = contentRef.current;\n    if (!el) {\n      return;\n    }\n\n    el.addEventListener('toggle', onToggle);\n\n    try {\n      if (visible) {\n        el.showPopover();\n      } else if (el.matches(':popover-open')) {\n        el.hidePopover();\n      }\n    } catch (error) {\n      if (process.env.NODE_ENV === 'development') {\n        // eslint-disable-next-line no-console\n        console.warn(\n          [\n            'Popover API is not supported in this browser, and the tooltip will not work correctly.',\n            'Please include a popover polyfill for better browser support.',\n          ].join(' '),\n          { error },\n        );\n      }\n    }\n\n    return () => {\n      el.removeEventListener('toggle', onToggle);\n    };\n  }, [contentRef, visible, setVisible, onToggle]);\n\n  // Used to skip showing the tooltip  in certain situations when the trigger is focused.\n  // See comments where this is set for more info.\n  const ignoreNextFocusEventRef = React.useRef(false);\n\n  // Listener for onPointerEnter and onFocus on the trigger element\n  const onEnterTrigger = React.useCallback(\n    // eslint-disable-next-line react-hooks/preserve-manual-memoization\n    (ev: React.PointerEvent<HTMLElement> | React.FocusEvent<HTMLElement>) => {\n      if (ev.type === 'focus' && ignoreNextFocusEventRef.current) {\n        ignoreNextFocusEventRef.current = false;\n        return;\n      }\n\n      setDelayTimeout(() => {\n        setVisible(ev, { visible: true });\n      }, state.showDelay);\n\n      ev.persist(); // Persist the event since the setVisible call will happen asynchronously\n    },\n    [setDelayTimeout, setVisible, state.showDelay],\n  );\n\n  const isNavigatingWithKeyboard = useIsNavigatingWithKeyboard();\n\n  // Callback ref that attaches a keyborg:focusin event listener.\n  const [keyborgListenerCallbackRef] = React.useState(() => {\n    const onKeyborgFocusIn = ((ev: KeyborgFocusInEvent) => {\n      // Skip showing the tooltip if focus moved programmatically.\n      // For example, we don't want to show the tooltip when a dialog is closed\n      // and Tabster programmatically restores focus to the trigger button.\n      // See https://github.com/microsoft/fluentui/issues/27576\n      if (ev.detail?.isFocusedProgrammatically && !isNavigatingWithKeyboard()) {\n        ignoreNextFocusEventRef.current = true;\n      }\n    }) as EventListener;\n\n    // Save the current element to remove the listener when the ref changes\n    let current: Element | null = null;\n\n    // Callback ref that attaches the listener to the element\n    return (element: Element | null) => {\n      current?.removeEventListener(KEYBORG_FOCUSIN, onKeyborgFocusIn);\n      element?.addEventListener(KEYBORG_FOCUSIN, onKeyborgFocusIn);\n      current = element;\n    };\n  });\n\n  // Listener for onPointerLeave and onBlur on the trigger element\n  const onLeaveTrigger = React.useCallback(\n    // eslint-disable-next-line react-hooks/preserve-manual-memoization\n    (ev: React.PointerEvent<HTMLElement> | React.FocusEvent<HTMLElement>) => {\n      let delay = state.hideDelay;\n\n      if (ev.type === 'blur') {\n        // Hide immediately when losing focus\n        delay = 0;\n\n        // The focused element gets a blur event when the document loses focus\n        // (e.g. switching tabs in the browser), but we don't want to show the\n        // tooltip again when the document gets focus back. Handle this case by\n        // checking if the blurred element is still the document's activeElement.\n        // See https://github.com/microsoft/fluentui/issues/13541\n        ignoreNextFocusEventRef.current = targetDocument?.activeElement === ev.target;\n      }\n\n      setDelayTimeout(() => {\n        setVisible(ev, { visible: false });\n      }, delay);\n\n      ev.persist(); // Persist the event since the setVisible call will happen asynchronously\n    },\n    [setDelayTimeout, setVisible, state.hideDelay, targetDocument],\n  );\n\n  // Cancel the hide timer when the mouse or focus enters the tooltip, and restart it when the mouse or focus leaves.\n  // This keeps the tooltip visible when the mouse is moved over it, or it has focus within.\n  // eslint-disable-next-line react-hooks/immutability\n  state.content.onPointerEnter = mergeCallbacks(state.content.onPointerEnter, clearDelayTimeout);\n  // eslint-disable-next-line react-hooks/immutability, react-hooks/refs\n  state.content.onPointerLeave = mergeCallbacks(state.content.onPointerLeave, onLeaveTrigger);\n  // eslint-disable-next-line react-hooks/immutability\n  state.content.onFocus = mergeCallbacks(state.content.onFocus, clearDelayTimeout);\n  // eslint-disable-next-line react-hooks/immutability, react-hooks/refs\n  state.content.onBlur = mergeCallbacks(state.content.onBlur, onLeaveTrigger);\n\n  const child = getTriggerChild(children);\n\n  const triggerAriaProps: Pick<TooltipTriggerProps, 'aria-label' | 'aria-labelledby' | 'aria-describedby'> = {};\n  const isPopupExpanded =\n    child?.props?.['aria-haspopup'] &&\n    (child?.props?.['aria-expanded'] === true || child?.props?.['aria-expanded'] === 'true');\n\n  if (relationship === 'label') {\n    // aria-label only works if the content is a string. Otherwise, need to use aria-labelledby.\n    if (typeof state.content.children === 'string') {\n      triggerAriaProps['aria-label'] = state.content.children;\n    } else {\n      triggerAriaProps['aria-labelledby'] = state.content.id;\n      // Always render the tooltip even if hidden, so that aria-labelledby refers to a valid element\n      // eslint-disable-next-line react-hooks/immutability\n      state.shouldRenderTooltip = true;\n    }\n  } else if (relationship === 'description') {\n    triggerAriaProps['aria-describedby'] = state.content.id;\n    // Always render the tooltip even if hidden, so that aria-describedby refers to a valid element\n    // eslint-disable-next-line react-hooks/immutability\n    state.shouldRenderTooltip = true;\n  }\n\n  // Case 1: Don't render the Tooltip in SSR to avoid hydration errors\n  // Case 2: Don't render the Tooltip, if it triggers Menu or another popup and it's already opened\n  if (isServerSideRender || isPopupExpanded) {\n    // eslint-disable-next-line react-hooks/immutability\n    state.shouldRenderTooltip = false;\n  }\n\n  // Apply the trigger props to the child, either by calling the render function, or cloning with the new props\n  // eslint-disable-next-line react-hooks/immutability\n  state.children = applyTriggerPropsToChildren(children, {\n    ...triggerAriaProps,\n    ...child?.props,\n    ref: useMergedRefs(\n      getReactElementRef<HTMLButtonElement>(child),\n      keyborgListenerCallbackRef,\n      // If the target prop is not provided, attach targetRef to the trigger element's ref prop\n      positioningOptions.target === undefined ? targetRef : undefined,\n    ),\n    // eslint-disable-next-line react-hooks/refs\n    onPointerEnter: useEventCallback(mergeCallbacks(child?.props?.onPointerEnter, onEnterTrigger)),\n    // eslint-disable-next-line react-hooks/refs\n    onPointerLeave: useEventCallback(mergeCallbacks(child?.props?.onPointerLeave, onLeaveTrigger)),\n    // eslint-disable-next-line react-hooks/refs\n    onFocus: useEventCallback(mergeCallbacks(child?.props?.onFocus, onEnterTrigger)),\n    // eslint-disable-next-line react-hooks/refs\n    onBlur: useEventCallback(mergeCallbacks(child?.props?.onBlur, onLeaveTrigger)),\n  });\n\n  return state;\n};\n"],"names":["useTooltip","props","isServerSideRender","useIsSSR","targetDocument","useFluent","visible","setVisibleInternal","useControllableState","state","initialState","children","content","positioning","withArrow","onVisibleChange","relationship","showDelay","hideDelay","shouldRenderTooltip","components","slot","always","defaultProps","role","popover","elementType","positioningOptions","resolvePositioningShorthand","targetRef","containerRef","usePositioning","id","useId","stringifyDataAttribute","contentRef","useMergedRefs","ref","setDelayTimeout","clearDelayTimeout","useTimeout","setVisible","React","useCallback","ev","data","oldVisible","onToggle","useEventCallback","event","newState","undefined","useIsomorphicLayoutEffect","el","current","addEventListener","showPopover","matches","hidePopover","error","process","env","NODE_ENV","console","warn","join","removeEventListener","ignoreNextFocusEventRef","useRef","onEnterTrigger","type","persist","isNavigatingWithKeyboard","useIsNavigatingWithKeyboard","keyborgListenerCallbackRef","useState","onKeyborgFocusIn","detail","isFocusedProgrammatically","element","KEYBORG_FOCUSIN","onLeaveTrigger","delay","activeElement","target","onPointerEnter","mergeCallbacks","onPointerLeave","onFocus","onBlur","child","getTriggerChild","triggerAriaProps","isPopupExpanded","applyTriggerPropsToChildren","getReactElementRef"],"mappings":"AAAA;;;;;+BA8BaA;;;eAAAA;;;;iEA5BU;gCAchB;qCACyC;8BAEa;6BAGD;uBACrB;AAOhC,MAAMA,aAAa,CAACC;IACzB,MAAMC,qBAAqBC,IAAAA,wBAAQ;IACnC,MAAM,EAAEC,cAAc,EAAE,GAAGC,IAAAA,uCAAS;IAEpC,MAAM,CAACC,SAASC,mBAAmB,GAAGC,IAAAA,oCAAoB,EAAC;QAAEC,OAAOR,MAAMK,OAAO;QAAEI,cAAc;IAAM;IAEvG,MAAM,EACJC,QAAQ,EACRC,OAAO,EACPC,cAAc,OAAO,EACrBC,YAAY,KAAK,EACjBC,eAAe,EACfC,YAAY,EACZC,YAAY,GAAG,EACfC,YAAY,GAAG,EAChB,GAAGjB;IAEJ,MAAMQ,QAAsB;QAC1BI;QACAI;QACAC;QACAF;QACAV;QACAa,qBAAqBb;QACrBQ;QACA,QAAQ;QACRM,YAAY;YACVR,SAAS;QACX;QACAA,SAASS,oBAAI,CAACC,MAAM,CAACV,SAAS;YAC5BW,cAAc;gBACZC,MAAM;gBACNC,SAAS;YACX;YACAC,aAAa;QACf;IACF;IAEA,MAAMC,qBAAqBC,IAAAA,wCAA2B,EAACf;IACvD,MAAM,EAAEgB,SAAS,EAAEC,YAAY,EAAE,GAAGC,IAAAA,2BAAc,EAACJ;IAEnDlB,MAAMG,OAAO,CAACoB,EAAE,GAAGC,IAAAA,qBAAK,EAAC,YAAYxB,MAAMG,OAAO,CAACoB,EAAE;IACrDvB,MAAMG,OAAO,CAAC,YAAY,GAAGsB,IAAAA,6BAAsB,EAACzB,MAAMH,OAAO;IAEjE,MAAM6B,aAAaC,IAAAA,6BAAa,EAAC3B,MAAMG,OAAO,CAACyB,GAAG,EAAEP;IACpDrB,MAAMG,OAAO,CAACyB,GAAG,GAAGF;IAEpB,MAAM,CAACG,iBAAiBC,kBAAkB,GAAGC,IAAAA,0BAAU;IAEvD,MAAMC,aAAaC,OAAMC,WAAW,CAClC,CAACC,IAAiFC;QAChFN;QACAhC,mBAAmBuC,CAAAA;YACjB,IAAID,KAAKvC,OAAO,KAAKwC,YAAY;gBAC/B/B,kBAAkB6B,IAAIC;YACxB;YACA,OAAOA,KAAKvC,OAAO;QACrB;IACF,GACA;QAACiC;QAAmBhC;QAAoBQ;KAAgB;IAG1D,MAAMgC,WAAWC,IAAAA,gCAAgB,EAAC,CAACC;QACjC,IAAI,AAACA,MAAsBC,QAAQ,KAAK,UAAU;YAChDT,WAAWU,WAAW;gBAAE7C,SAAS;YAAM;QACzC;IACF;IAEA,+EAA+E;IAC/E,kGAAkG;IAClG8C,IAAAA,yCAAyB,EAAC;QACxB,MAAMC,KAAKlB,WAAWmB,OAAO;QAC7B,IAAI,CAACD,IAAI;YACP;QACF;QAEAA,GAAGE,gBAAgB,CAAC,UAAUR;QAE9B,IAAI;YACF,IAAIzC,SAAS;gBACX+C,GAAGG,WAAW;YAChB,OAAO,IAAIH,GAAGI,OAAO,CAAC,kBAAkB;gBACtCJ,GAAGK,WAAW;YAChB;QACF,EAAE,OAAOC,OAAO;YACd,IAAIC,QAAQC,GAAG,CAACC,QAAQ,KAAK,eAAe;gBAC1C,sCAAsC;gBACtCC,QAAQC,IAAI,CACV;oBACE;oBACA;iBACD,CAACC,IAAI,CAAC,MACP;oBAAEN;gBAAM;YAEZ;QACF;QAEA,OAAO;YACLN,GAAGa,mBAAmB,CAAC,UAAUnB;QACnC;IACF,GAAG;QAACZ;QAAY7B;QAASmC;QAAYM;KAAS;IAE9C,uFAAuF;IACvF,gDAAgD;IAChD,MAAMoB,0BAA0BzB,OAAM0B,MAAM,CAAC;IAE7C,iEAAiE;IACjE,MAAMC,iBAAiB3B,OAAMC,WAAW,CACtC,mEAAmE;IACnE,CAACC;QACC,IAAIA,GAAG0B,IAAI,KAAK,WAAWH,wBAAwBb,OAAO,EAAE;YAC1Da,wBAAwBb,OAAO,GAAG;YAClC;QACF;QAEAhB,gBAAgB;YACdG,WAAWG,IAAI;gBAAEtC,SAAS;YAAK;QACjC,GAAGG,MAAMQ,SAAS;QAElB2B,GAAG2B,OAAO,IAAI,yEAAyE;IACzF,GACA;QAACjC;QAAiBG;QAAYhC,MAAMQ,SAAS;KAAC;IAGhD,MAAMuD,2BAA2BC,IAAAA,yCAA2B;IAE5D,+DAA+D;IAC/D,MAAM,CAACC,2BAA2B,GAAGhC,OAAMiC,QAAQ,CAAC;QAClD,MAAMC,mBAAoB,CAAChC;YACzB,4DAA4D;YAC5D,yEAAyE;YACzE,qEAAqE;YACrE,yDAAyD;YACzD,IAAIA,GAAGiC,MAAM,EAAEC,6BAA6B,CAACN,4BAA4B;gBACvEL,wBAAwBb,OAAO,GAAG;YACpC;QACF;QAEA,uEAAuE;QACvE,IAAIA,UAA0B;QAE9B,yDAAyD;QACzD,OAAO,CAACyB;YACNzB,SAASY,oBAAoBc,6BAAe,EAAEJ;YAC9CG,SAASxB,iBAAiByB,6BAAe,EAAEJ;YAC3CtB,UAAUyB;QACZ;IACF;IAEA,gEAAgE;IAChE,MAAME,iBAAiBvC,OAAMC,WAAW,CACtC,mEAAmE;IACnE,CAACC;QACC,IAAIsC,QAAQzE,MAAMS,SAAS;QAE3B,IAAI0B,GAAG0B,IAAI,KAAK,QAAQ;YACtB,qCAAqC;YACrCY,QAAQ;YAER,sEAAsE;YACtE,sEAAsE;YACtE,uEAAuE;YACvE,yEAAyE;YACzE,yDAAyD;YACzDf,wBAAwBb,OAAO,GAAGlD,gBAAgB+E,kBAAkBvC,GAAGwC,MAAM;QAC/E;QAEA9C,gBAAgB;YACdG,WAAWG,IAAI;gBAAEtC,SAAS;YAAM;QAClC,GAAG4E;QAEHtC,GAAG2B,OAAO,IAAI,yEAAyE;IACzF,GACA;QAACjC;QAAiBG;QAAYhC,MAAMS,SAAS;QAAEd;KAAe;IAGhE,mHAAmH;IACnH,0FAA0F;IAC1F,oDAAoD;IACpDK,MAAMG,OAAO,CAACyE,cAAc,GAAGC,IAAAA,8BAAc,EAAC7E,MAAMG,OAAO,CAACyE,cAAc,EAAE9C;IAC5E,sEAAsE;IACtE9B,MAAMG,OAAO,CAAC2E,cAAc,GAAGD,IAAAA,8BAAc,EAAC7E,MAAMG,OAAO,CAAC2E,cAAc,EAAEN;IAC5E,oDAAoD;IACpDxE,MAAMG,OAAO,CAAC4E,OAAO,GAAGF,IAAAA,8BAAc,EAAC7E,MAAMG,OAAO,CAAC4E,OAAO,EAAEjD;IAC9D,sEAAsE;IACtE9B,MAAMG,OAAO,CAAC6E,MAAM,GAAGH,IAAAA,8BAAc,EAAC7E,MAAMG,OAAO,CAAC6E,MAAM,EAAER;IAE5D,MAAMS,QAAQC,IAAAA,+BAAe,EAAChF;IAE9B,MAAMiF,mBAAqG,CAAC;IAC5G,MAAMC,kBACJH,OAAOzF,OAAO,CAAC,gBAAgB,IAC9ByF,CAAAA,OAAOzF,OAAO,CAAC,gBAAgB,KAAK,QAAQyF,OAAOzF,OAAO,CAAC,gBAAgB,KAAK,MAAK;IAExF,IAAIe,iBAAiB,SAAS;QAC5B,4FAA4F;QAC5F,IAAI,OAAOP,MAAMG,OAAO,CAACD,QAAQ,KAAK,UAAU;YAC9CiF,gBAAgB,CAAC,aAAa,GAAGnF,MAAMG,OAAO,CAACD,QAAQ;QACzD,OAAO;YACLiF,gBAAgB,CAAC,kBAAkB,GAAGnF,MAAMG,OAAO,CAACoB,EAAE;YACtD,8FAA8F;YAC9F,oDAAoD;YACpDvB,MAAMU,mBAAmB,GAAG;QAC9B;IACF,OAAO,IAAIH,iBAAiB,eAAe;QACzC4E,gBAAgB,CAAC,mBAAmB,GAAGnF,MAAMG,OAAO,CAACoB,EAAE;QACvD,+FAA+F;QAC/F,oDAAoD;QACpDvB,MAAMU,mBAAmB,GAAG;IAC9B;IAEA,oEAAoE;IACpE,iGAAiG;IACjG,IAAIjB,sBAAsB2F,iBAAiB;QACzC,oDAAoD;QACpDpF,MAAMU,mBAAmB,GAAG;IAC9B;IAEA,6GAA6G;IAC7G,oDAAoD;IACpDV,MAAME,QAAQ,GAAGmF,IAAAA,2CAA2B,EAACnF,UAAU;QACrD,GAAGiF,gBAAgB;QACnB,GAAGF,OAAOzF,KAAK;QACfoC,KAAKD,IAAAA,6BAAa,EAChB2D,IAAAA,kCAAkB,EAAoBL,QACtChB,4BACA,yFAAyF;QACzF/C,mBAAmByD,MAAM,KAAKjC,YAAYtB,YAAYsB;QAExD,4CAA4C;QAC5CkC,gBAAgBrC,IAAAA,gCAAgB,EAACsC,IAAAA,8BAAc,EAACI,OAAOzF,OAAOoF,gBAAgBhB;QAC9E,4CAA4C;QAC5CkB,gBAAgBvC,IAAAA,gCAAgB,EAACsC,IAAAA,8BAAc,EAACI,OAAOzF,OAAOsF,gBAAgBN;QAC9E,4CAA4C;QAC5CO,SAASxC,IAAAA,gCAAgB,EAACsC,IAAAA,8BAAc,EAACI,OAAOzF,OAAOuF,SAASnB;QAChE,4CAA4C;QAC5CoB,QAAQzC,IAAAA,gCAAgB,EAACsC,IAAAA,8BAAc,EAACI,OAAOzF,OAAOwF,QAAQR;IAChE;IAEA,OAAOxE;AACT"}