'use client'; import * as React from 'react'; import { Tooltip as TooltipPrimitive } from '@base-ui-components/react/tooltip'; import { AnimatePresence, type HTMLMotionProps, motion, type Transition, } from 'motion/react'; import { cn } from '@workspace/ui/lib/utils'; type TooltipContextType = { isOpen: boolean; }; const TooltipContext = React.createContext( undefined, ); const useTooltip = (): TooltipContextType => { const context = React.useContext(TooltipContext); if (!context) { throw new Error('useTooltip must be used within a Tooltip'); } return context; }; type Side = React.ComponentPropsWithoutRef< typeof TooltipPrimitive.Positioner >['side']; type Align = React.ComponentPropsWithoutRef< typeof TooltipPrimitive.Positioner >['align']; const getInitialPosition = (side: Side) => { switch (side) { case 'top': return { y: 15 }; case 'bottom': return { y: -15 }; case 'left': case 'inline-start': return { x: 15 }; case 'right': case 'inline-end': return { x: -15 }; } }; type TooltipProviderProps = React.ComponentProps< typeof TooltipPrimitive.Provider >; function TooltipProvider(props: TooltipProviderProps) { return ; } type TooltipProps = React.ComponentProps; function Tooltip(props: TooltipProps) { const [isOpen, setIsOpen] = React.useState( props?.open ?? props?.defaultOpen ?? false, ); React.useEffect(() => { if (props?.open !== undefined) setIsOpen(props.open); }, [props?.open]); const handleOpenChange = React.useCallback( ( open: boolean, event: Event | undefined, reason: Parameters>[2], ) => { setIsOpen(open); props.onOpenChange?.(open, event, reason); }, [props], ); return ( ); } type TooltipTriggerProps = React.ComponentProps< typeof TooltipPrimitive.Trigger >; function TooltipTrigger(props: TooltipTriggerProps) { return ; } type TooltipContentProps = React.ComponentProps< typeof TooltipPrimitive.Positioner > & { transition?: Transition; popupProps?: typeof TooltipPrimitive.Popup; motionProps?: HTMLMotionProps<'div'>; positionerClassName?: string; arrow?: boolean; }; function TooltipContent({ className, popupProps, motionProps, positionerClassName, side = 'top', sideOffset = 10, transition = { type: 'spring', stiffness: 300, damping: 25 }, arrow = true, children, ...props }: TooltipContentProps) { const { isOpen } = useTooltip(); const initialPosition = getInitialPosition(side); return ( {isOpen && ( } > {children} {arrow && ( )} )} ); } export { TooltipProvider, Tooltip, TooltipTrigger, TooltipContent, useTooltip, type TooltipContextType, type TooltipProviderProps, type TooltipProps, type TooltipTriggerProps, type TooltipContentProps, type Side, type Align, };