import React, { useState } from 'react' import { autoPlacement, autoUpdate, flip, FloatingPortal, offset, type Placement, safePolygon, shift, useDismiss, useFloating, useFocus, useHover, useInteractions, useRole, useTransitionStyles, } from '@floating-ui/react' import styles from './_tooltip.module.scss' import Button from '../Button/Button' import Icon from '../Icons/Icon' import { SideDrawer } from '../SideDrawer/SideDrawer' import { toast } from '../Toast/Toast' import { useMediaQuery } from '../../hooks/responsiveHooks' import { c } from '../../translations/LibraryTranslationService' export type TooltipProps = { /** The element that you need to hover to show the tooltip. */ tooltipContent?: | ((props: { setVisible: (value: boolean) => void }) => React.JSX.Element) | React.ReactNode /** The content inside of the tooltip. */ children: React.ReactNode /** The position of the tooltip. */ position?: Placement | 'auto' /** Optional className for the tooltip. */ className?: string /** Optional prop to restrict the max width of the tooltip. */ maxWidth?: string /** Optional prop to show the `SideDrawer` when in a mobile view. */ useSideDrawerForMobile?: boolean /** Optional prop to show custom header content on `SideDrawer` for mobile view. Only applicable in case of `useSideDrawerForMobile` is set to true. */ sideDrawerHeader?: string /** Optional prop to show copy icon to copy the tooltip content. */ copyToClipboard?: boolean /** Optional prop to set the color of the arrow. */ /** * @deprecated This prop is no longer supported. **/ arrowColor?: 'medium-purple' | 'red' | 'green' | 'blue' | 'white' /** Optional prop to remove padding */ noPadding?: boolean /** Optional prop to disable the tooltip. */ disabled?: boolean /** Optional prop to disable click event propagation on the tooltip. */ enableClickThrough?: boolean /** Optional prop to add a test id to the Tooltip for QA testing */ qaTestId?: string } const Tooltip = ({ tooltipContent, children, position = 'right', className = '', maxWidth = '300px', useSideDrawerForMobile = false, sideDrawerHeader = '', copyToClipboard = false, noPadding = false, disabled = false, enableClickThrough = false, qaTestId = 'tooltip', }: TooltipProps): React.JSX.Element => { const [mobileDrawerOpen, setMobileDrawerOpen] = useState(false) const screenLargerThanMd = useMediaQuery({ type: 'min', breakpoint: 'md' }) const [isTooltipOpen, setIsTooltipOpen] = useState(false) const isCopyToClipboardValid = copyToClipboard && typeof tooltipContent === 'string' const { refs: { setReference, setFloating }, floatingStyles, context, } = useFloating({ open: isTooltipOpen && !disabled, onOpenChange: setIsTooltipOpen, strategy: 'fixed', ...(position !== 'auto' ? { placement: position } : {}), middleware: [ offset(8), ...(position === 'auto' ? [autoPlacement()] : [flip()]), // autoPlacement() is used to automatically place the tooltip in the best position and it internally uses flip() shift({ padding: 4 }), ], whileElementsMounted: autoUpdate, }) const role = useRole(context, { role: 'tooltip' }) const hover = useHover(context, { move: false, delay: { open: 100, close: 0 }, handleClose: // Makes the Tooltip interactive safePolygon({ requireIntent: false, blockPointerEvents: true, buffer: 1, }), }) const focus = useFocus(context) const dismiss = useDismiss(context, { ancestorScroll: true, // close Tooltip on scrolling }) const { isMounted, styles: transitionStyles } = useTransitionStyles(context, { initial: { opacity: 0, transform: 'scale(0.8)', }, duration: 200, // transition duration when opening and closing the Tooltip }) const { getReferenceProps, getFloatingProps } = useInteractions([ hover, focus, dismiss, role, ]) if (useSideDrawerForMobile && !screenLargerThanMd) { return ( <> setMobileDrawerOpen(false)} headerContent={sideDrawerHeader} onlyMobile qaTestId={`${qaTestId}-drawer`} > {typeof tooltipContent === 'function' ? tooltipContent({ setVisible: setMobileDrawerOpen }) : tooltipContent} ) } else { return ( <> {/* Tooltip reference element */}
{children}
{/* Floating element i.e Tooltip */} {isMounted && tooltipContent ? (
e.stopPropagation() } : {})} qa-test-id={`${qaTestId}-floating`} >
{typeof tooltipContent === 'function' ? tooltipContent({ setVisible: setIsTooltipOpen }) : tooltipContent} {isCopyToClipboardValid ? (
) : null}
) : null} ) } } export default Tooltip