{"version":3,"file":"Tooltip.cjs","names":[],"sources":["../../../src/components/Tooltip/Tooltip.tsx"],"sourcesContent":["/*\nCopyright 2023, 2024 New Vector Ltd.\n\nSPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial\nPlease see LICENSE files in the repository root for full details.\n*/\n\nimport { TooltipContext, useTooltipContext } from \"./TooltipContext\";\nimport {\n  FloatingArrow,\n  FloatingPortal,\n  useMergeRefs,\n} from \"@floating-ui/react\";\nimport React, {\n  type PropsWithChildren,\n  type Ref,\n  type JSX,\n  isValidElement,\n  cloneElement,\n  useMemo,\n  type ReactNode,\n  type FC,\n  type ReactElement,\n} from \"react\";\n\nimport classNames from \"classnames\";\nimport styles from \"./Tooltip.module.css\";\nimport {\n  type CommonUseTooltipProps,\n  type TooltipDescription,\n  type TooltipLabel,\n  useTooltip,\n} from \"./useTooltip\";\n\n// Unfortunately Omit doesn't distribute nicely over sum types, so we have to\n// piece together the useTooltip options type by hand\ntype TooltipProps = Omit<CommonUseTooltipProps, \"isTriggerInteractive\"> &\n  (TooltipLabel | TooltipDescription) & {\n    /**\n     * Whether the trigger element is interactive.\n     * When trigger is interactive:\n     *      - tooltip will be shown after a 300ms delay.\n     * When trigger is not interactive:\n     *      - tooltip will be shown instantly when pointer enters trigger.\n     *      - trigger will be wrapped in a span with a tab index from prop nonInteractiveTriggerTabIndex\n     * @default true\n     */\n    isTriggerInteractive?: boolean;\n    /**\n     * The tab index for the non interactive trigger.\n     * @default 0\n     */\n    nonInteractiveTriggerTabIndex?: number;\n  };\n\nconst hasLabel = (\n  props: TooltipLabel | TooltipDescription,\n): props is TooltipLabel => \"label\" in props && !!props.label;\n\n/**\n * A tooltip component\n */\nexport function Tooltip({\n  children,\n  isTriggerInteractive = true,\n  nonInteractiveTriggerTabIndex = 0,\n  ...props\n}: PropsWithChildren<TooltipProps>): JSX.Element {\n  const context = useTooltip({ isTriggerInteractive, ...props });\n\n  return (\n    <TooltipContext.Provider value={context}>\n      <TooltipAnchor\n        isTriggerInteractive={isTriggerInteractive}\n        nonInteractiveTriggerTabIndex={nonInteractiveTriggerTabIndex}\n      >\n        {children}\n      </TooltipAnchor>\n      <TooltipContent>\n        <span id={context.labelId}>\n          {hasLabel(props) ? props.label : props.description}\n        </span>\n        <Caption />\n      </TooltipContent>\n    </TooltipContext.Provider>\n  );\n}\n\nfunction Caption() {\n  const { caption, captionId } = useTooltipContext();\n  if (!caption) return null;\n\n  const isCaptionString = typeof caption === \"string\";\n  const Container = isCaptionString ? \"span\" : \"div\";\n\n  /**\n   * Forcing dark theme, so that we have the correct contrast when\n   * using the text color secondary on a solid dark background.\n   * This is temporary and should only remain until we figure out\n   * the approach to on-solid tokens\n   **/\n  return (\n    <Container\n      id={captionId}\n      className={classNames(styles.caption, \"cpd-theme-dark\")}\n    >\n      {caption}\n    </Container>\n  );\n}\n\n/**\n * The content of the tooltip\n * @param children\n */\nfunction TooltipContent({\n  children,\n}: Readonly<PropsWithChildren>): JSX.Element | null {\n  const {\n    context: floatingContext,\n    open,\n    arrowRef,\n    purpose,\n    ...rest\n  } = useTooltipContext();\n\n  // Label tooltips are kept in the DOM even when not visually open\n  if (!open && purpose !== \"label\") return null;\n\n  return (\n    <FloatingPortal>\n      <div\n        ref={rest.refs.setFloating}\n        style={rest.floatingStyles}\n        {...rest.tooltipProps}\n        {...rest.getFloatingProps()}\n        className={classNames(styles.tooltip, {\n          [styles.invisible]: purpose === \"label\" && !open,\n        })}\n      >\n        <FloatingArrow\n          ref={arrowRef}\n          context={floatingContext}\n          // design absolute value\n          width={10}\n          height={6}\n          className={styles.arrow}\n        />\n        {children}\n      </div>\n    </FloatingPortal>\n  );\n}\n\ninterface TooltipAnchorProps {\n  children: ReactNode;\n  isTriggerInteractive: boolean;\n  nonInteractiveTriggerTabIndex?: number;\n}\n\n/**\n * The anchor of the tooltip\n * @param children\n */\nconst TooltipAnchor: FC<TooltipAnchorProps> = ({\n  children,\n  isTriggerInteractive,\n  nonInteractiveTriggerTabIndex,\n}) => {\n  const context = useTooltipContext();\n\n  // The children can have a ref and we don't want to discard it\n  // Doing a dirty cast to get the optional ref\n  const childrenRef = (children as unknown as { ref?: Ref<HTMLElement> })?.ref;\n  const ref = useMergeRefs([context.refs.setReference, childrenRef]);\n\n  const element = useMemo(() => {\n    if (!isValidElement(children)) return;\n\n    if (isTriggerInteractive) {\n      const props = context.getReferenceProps({\n        // To support React 18, we need to explicitly pass the children's props. See  https://github.com/element-hq/compound/issues/333\n        // In React 19, this is not necessary. `getReferenceProps` is able to get the props directly from the ref.\n        ...(typeof children.props === \"object\" ? children.props : {}),\n        ref,\n      });\n      return cloneElement(children, props);\n    } else {\n      // For a non-interactive trigger, we want most of the props to go on the\n      // span element that we provide, since that's what receives focus, but it\n      // should still be the trigger that receives the label/description. It\n      // would be wrong to label the span element, as it lacks a role.\n      const props = context.getReferenceProps({\n        ref,\n        tabIndex: nonInteractiveTriggerTabIndex,\n      });\n      const {\n        \"aria-labelledby\": labelId,\n        \"aria-describedby\": descriptionId,\n        ...spanProps\n      } = props;\n      return (\n        <span tabIndex={nonInteractiveTriggerTabIndex} {...spanProps}>\n          {cloneElement(children as ReactElement<Record<string, unknown>>, {\n            \"aria-labelledby\": labelId,\n            \"aria-describedby\": descriptionId,\n          })}\n        </span>\n      );\n    }\n  }, [context, ref, children]);\n\n  if (!element) {\n    throw new Error(\"Tooltip anchor must be a single valid React element\");\n  }\n\n  return element;\n};\n"],"mappings":";;;;;;;;;;;AAuDA,IAAM,YACJ,UAC0B,WAAW,SAAS,CAAC,CAAC,MAAM;;;;AAKxD,SAAgB,QAAQ,EACtB,UACA,uBAAuB,MACvB,gCAAgC,GAChC,GAAG,SAC4C;CAC/C,MAAM,UAAU,mBAAA,WAAW;EAAE;EAAsB,GAAG;EAAO,CAAC;AAE9D,QACE,iBAAA,GAAA,kBAAA,MAAC,uBAAA,eAAe,UAAhB;EAAyB,OAAO;YAAhC,CACE,iBAAA,GAAA,kBAAA,KAAC,eAAD;GACwB;GACS;GAE9B;GACa,CAAA,EAChB,iBAAA,GAAA,kBAAA,MAAC,gBAAD,EAAA,UAAA,CACE,iBAAA,GAAA,kBAAA,KAAC,QAAD;GAAM,IAAI,QAAQ;aACf,SAAS,MAAM,GAAG,MAAM,QAAQ,MAAM;GAClC,CAAA,EACP,iBAAA,GAAA,kBAAA,KAAC,SAAD,EAAW,CAAA,CACI,EAAA,CAAA,CACO;;;AAI9B,SAAS,UAAU;CACjB,MAAM,EAAE,SAAS,cAAc,uBAAA,mBAAmB;AAClD,KAAI,CAAC,QAAS,QAAO;;;;;;;AAWrB,QACE,iBAAA,GAAA,kBAAA,KAVsB,OAAO,YAAY,WACP,SAAS,OAS3C;EACE,IAAI;EACJ,YAAA,GAAA,WAAA,SAAsB,uBAAA,QAAO,SAAS,iBAAiB;YAEtD;EACS,CAAA;;;;;;AAQhB,SAAS,eAAe,EACtB,YACkD;CAClD,MAAM,EACJ,SAAS,iBACT,MACA,UACA,SACA,GAAG,SACD,uBAAA,mBAAmB;AAGvB,KAAI,CAAC,QAAQ,YAAY,QAAS,QAAO;AAEzC,QACE,iBAAA,GAAA,kBAAA,KAAC,mBAAA,gBAAD,EAAA,UACE,iBAAA,GAAA,kBAAA,MAAC,OAAD;EACE,KAAK,KAAK,KAAK;EACf,OAAO,KAAK;EACZ,GAAI,KAAK;EACT,GAAI,KAAK,kBAAkB;EAC3B,YAAA,GAAA,WAAA,SAAsB,uBAAA,QAAO,SAAS,GACnC,uBAAA,QAAO,YAAY,YAAY,WAAW,CAAC,MAC7C,CAAC;YAPJ,CASE,iBAAA,GAAA,kBAAA,KAAC,mBAAA,eAAD;GACE,KAAK;GACL,SAAS;GAET,OAAO;GACP,QAAQ;GACR,WAAW,uBAAA,QAAO;GAClB,CAAA,EACD,SACG;KACS,CAAA;;;;;;AAcrB,IAAM,iBAAyC,EAC7C,UACA,sBACA,oCACI;CACJ,MAAM,UAAU,uBAAA,mBAAmB;CAInC,MAAM,cAAe,UAAoD;CACzE,MAAM,OAAA,GAAA,mBAAA,cAAmB,CAAC,QAAQ,KAAK,cAAc,YAAY,CAAC;CAElE,MAAM,WAAA,GAAA,MAAA,eAAwB;AAC5B,MAAI,EAAA,GAAA,MAAA,gBAAgB,SAAS,CAAE;AAE/B,MAAI,qBAOF,SAAA,GAAA,MAAA,cAAoB,UANN,QAAQ,kBAAkB;GAGtC,GAAI,OAAO,SAAS,UAAU,WAAW,SAAS,QAAQ,EAAE;GAC5D;GACD,CAAC,CACkC;OAC/B;GASL,MAAM,EACJ,mBAAmB,SACnB,oBAAoB,eACpB,GAAG,cAPS,QAAQ,kBAAkB;IACtC;IACA,UAAU;IACX,CAAC;AAMF,UACE,iBAAA,GAAA,kBAAA,KAAC,QAAD;IAAM,UAAU;IAA+B,GAAI;sCACnC,UAAmD;KAC/D,mBAAmB;KACnB,oBAAoB;KACrB,CAAC;IACG,CAAA;;IAGV;EAAC;EAAS;EAAK;EAAS,CAAC;AAE5B,KAAI,CAAC,QACH,OAAM,IAAI,MAAM,sDAAsD;AAGxE,QAAO"}