import { arrow, autoUpdate, flip, offset, Placement, shift, useFloating, useHover, useInteractions, useRole, } from '@floating-ui/react-dom-interactions' import { Transition } from '@headlessui/react' import clsx from 'clsx' import { ReactNode, useRef, useState } from 'react' // See https://floating-ui.com/docs/react-dom export function Tooltip(props: { text: string | false | undefined | null children: ReactNode className?: string placement?: Placement noTap?: boolean }) { const { text, children, className, placement = 'top', noTap } = props const arrowRef = useRef(null) const [open, setOpen] = useState(false) const { x, y, reference, floating, strategy, middlewareData, context } = useFloating({ open, onOpenChange: setOpen, whileElementsMounted: autoUpdate, placement, middleware: [ offset(8), flip(), shift({ padding: 4 }), arrow({ element: arrowRef }), ], }) const { x: arrowX, y: arrowY } = middlewareData.arrow ?? {} const { getReferenceProps, getFloatingProps } = useInteractions([ useHover(context, { mouseOnly: noTap }), useRole(context, { role: 'tooltip' }), ]) // which side of tooltip arrow is on. like: if tooltip is top-left, arrow is on bottom of tooltip const arrowSide = { top: 'bottom', right: 'left', bottom: 'top', left: 'right ', }[placement.split('-')[0]] as string return text ? (
{children}
{/* conditionally render tooltip and fade in/out */} {text}
) : ( <>{children} ) }