"use client" import * as React from "react" import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, useTooltipProvided, } from "./tooltip" import { useOverlayElevation } from "../../lib/overlay-elevation" import { cn } from "../../lib/utils" interface TipProps { /** Plain string or text + `` — see `.cursor/rules/exxat-kbd-shortcuts.mdc` */ label: React.ReactNode children: React.ReactNode side?: "top" | "bottom" | "left" | "right" /** Merged onto `TooltipContent` — e.g. `z-properties-sheet-tooltip` inside floating sheets. */ contentClassName?: string /** Merged onto `TooltipTrigger` when `asChild` — use `inline-flex` for icon-only hosts. */ triggerClassName?: string /** * Force the tooltip above floating sheets (`z-[80]`). Rarely needed: a `Tip` * inside a rail is elevated automatically by the rail's own context. */ contentZIndex?: number /** * Keep the tooltip mounted but never open it. * * For a host that is only sometimes worth explaining — a tab label that reads * for itself until the row runs out of room and hides it. Rendering the `Tip` * conditionally instead would remount the host, which resets anything it was * in the middle of: focus, a text selection, a transition. */ disabled?: boolean } export function Tip({ label, children, side = "top", contentClassName, triggerClassName, contentZIndex, disabled = false, }: TipProps) { const provided = useTooltipProvided() // A tooltip inside a rail must clear it, and the author of a one-off icon // button in an actions slot should not have to know that. const inheritedZIndex = useOverlayElevation() const zIndex = contentZIndex ?? (contentClassName?.includes("properties-sheet-tooltip") ? 100 : null) ?? inheritedZIndex // Held here rather than left to Radix so that `disabled` has something to // override. Handing `open` over only while disabled would move the tooltip // between controlled and uncontrolled, which React warns about and which // loses whatever state it was in at the swap. const [open, setOpen] = React.useState(false) React.useEffect(() => { if (disabled) setOpen(false) }, [disabled]) const tip = ( { if (!disabled) setOpen(next) }} > {children} {label} ) return provided ? tip : {tip} }