/** * Token-styled Radix tooltip — counterpart to `src/ui/tooltip`. * Portals copy `--og-*` tokens so embeds keep the host theme outside `.og-root`. * * Background/foreground are applied as inline styles (not only Tailwind * utilities): `.og-root` sets `color: var(--og-color-fg)` after utilities in the * consumer CSS cascade, which would otherwise paint light-on-light inverted * tips and look like a blank white bubble. */ import { Tooltip as TooltipPrimitive } from "radix-ui"; import { containedPortal } from "../ui/portal-container"; import { createContext, useContext, useLayoutEffect, useMemo, useRef, useState, type ComponentProps, type CSSProperties, } from "react"; import { cn } from "../lib/cn"; import { usePortalTokenStyle } from "../lib/use-portal-token-style"; const TooltipContainedPortal = containedPortal(TooltipPrimitive.Portal); type TooltipSourceContextValue = { source: HTMLElement | null; ref: (node: HTMLElement | null) => void; }; const TooltipSourceContext = createContext(null); function TooltipProvider({ delayDuration = 300, ...props }: ComponentProps) { return ; } function Tooltip({ children, ...props }: ComponentProps) { const { onOpenChange, ...rootProps } = props; const sourceRef = useRef(null); const sourcePublishedRef = useRef(false); const [source, setSource] = useState(null); const ref = useRef((node: HTMLElement | null) => { sourceRef.current = node; if (sourcePublishedRef.current) setSource(node); }).current; useLayoutEffect(() => { if (rootProps.open === true || rootProps.defaultOpen === true) { sourcePublishedRef.current = true; setSource(sourceRef.current); } }, [rootProps.defaultOpen, rootProps.open]); const sourceContext = useMemo(() => ({ source, ref }), [ref, source]); return ( { if (open) { sourcePublishedRef.current = true; setSource(sourceRef.current); } onOpenChange?.(open); }} {...rootProps} > {children} ); } function TooltipTrigger({ asChild = true, ...props }: ComponentProps) { const sourceRef = useContext(TooltipSourceContext); return ( { sourceRef?.ref(node); }} {...props} /> ); } const tooltipSurfaceStyle: CSSProperties = { backgroundColor: "var(--og-color-fg)", color: "var(--og-color-bg)", }; function TooltipContent({ className, sideOffset = 6, children, style, ...props }: ComponentProps) { const source = useContext(TooltipSourceContext); const portalStyle = usePortalTokenStyle(source?.source ?? null); return ( {children} ); } export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger };