{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "tooltip",
  "type": "registry:ui",
  "registryDependencies": [],
  "dependencies": ["@radix-ui/react-popover", "@radix-ui/react-slot", "motion"],
  "devDependencies": [],
  "files": [
    {
      "path": "tooltip.tsx",
      "content": "\"use client\";\n\nimport * as PopoverPrimitive from \"@radix-ui/react-popover\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { AnimatePresence, motion } from \"motion/react\";\nimport * as React from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\nconst controlCornerClassName =\n  \"rounded-lg supports-[corner-shape:squircle]:corner-squircle supports-[corner-shape:squircle]:rounded-[11px]\";\n\nconst tooltipThemeClassName =\n  \"[--tt-surface:#111111] [--tt-foreground:#ffffff] dark:[--tt-surface:#f6f3ec] dark:[--tt-foreground:#111111]\";\n\nconst tooltipContentClassName = cn(\n  controlCornerClassName,\n  \"group/tooltip pointer-events-none relative z-50 max-w-60 whitespace-normal bg-[color:var(--tt-surface)] px-3 py-1.5 font-medium text-[color:var(--tt-foreground)] text-xs leading-snug shadow-[0_4px_24px_-4px_rgba(0,0,0,0.25)]\"\n);\n\nconst tooltipArrowClassName =\n  \"absolute h-2 w-2 rotate-45 bg-[color:var(--tt-surface)] group-data-[side=bottom]/tooltip:-top-1 group-data-[side=left]/tooltip:top-1/2 group-data-[side=right]/tooltip:top-1/2 group-data-[side=left]/tooltip:-right-1 group-data-[side=top]/tooltip:-bottom-1 group-data-[side=bottom]/tooltip:left-1/2 group-data-[side=right]/tooltip:-left-1 group-data-[side=top]/tooltip:left-1/2 group-data-[side=bottom]/tooltip:-translate-x-1/2 group-data-[side=top]/tooltip:-translate-x-1/2 group-data-[side=left]/tooltip:-translate-y-1/2 group-data-[side=right]/tooltip:-translate-y-1/2\";\n\ntype Side = \"top\" | \"bottom\" | \"left\" | \"right\";\ntype TooltipTriggerElement = React.ReactElement<{\n  \"aria-describedby\"?: string;\n}>;\n\nexport interface TooltipProps {\n  children: TooltipTriggerElement;\n  content: string;\n  side?: Side;\n  delay?: number;\n  className?: string;\n}\n\nconst MAX_TOOLTIP_CHARACTERS = 80;\n\nfunction isTooltipTriggerElement(\n  node: React.ReactNode\n): node is TooltipTriggerElement {\n  return React.isValidElement(node) && node.type !== React.Fragment;\n}\n\nfunction mergeDescribedBy(...ids: Array<string | undefined>) {\n  const merged = ids.filter(Boolean).join(\" \");\n\n  return merged.length > 0 ? merged : undefined;\n}\n\nexport function Tooltip({\n  children,\n  content,\n  side = \"top\",\n  delay = 0.15,\n  className,\n}: TooltipProps) {\n  const [open, setOpen] = React.useState(false);\n  const timeoutRef = React.useRef<ReturnType<typeof setTimeout>>(undefined);\n  const tooltipId = React.useId();\n  const normalizedContent = content.trim();\n\n  if (!isTooltipTriggerElement(children)) {\n    throw new Error(\n      \"Tooltip expects a single element child so it can forward hover, focus, and accessibility props.\"\n    );\n  }\n\n  React.useEffect(() => {\n    if (\n      process.env.NODE_ENV !== \"production\" &&\n      (normalizedContent.length > MAX_TOOLTIP_CHARACTERS ||\n        normalizedContent.includes(\"\\n\"))\n    ) {\n      console.warn(\n        \"Tooltip content should stay short, single-line, and non-interactive. Use Popover for longer or multiline content.\"\n      );\n    }\n  }, [normalizedContent]);\n\n  const childAriaDescribedBy = children.props[\"aria-describedby\"];\n  const triggerDescription = open\n    ? mergeDescribedBy(childAriaDescribedBy, tooltipId)\n    : childAriaDescribedBy;\n\n  const handleEnter = () => {\n    clearTimeout(timeoutRef.current);\n    timeoutRef.current = setTimeout(() => setOpen(true), delay * 1000);\n  };\n  const handleLeave = () => {\n    clearTimeout(timeoutRef.current);\n    setOpen(false);\n  };\n\n  React.useEffect(() => () => clearTimeout(timeoutRef.current), []);\n\n  if (normalizedContent.length === 0) {\n    return children;\n  }\n\n  return (\n    <PopoverPrimitive.Root modal={false} onOpenChange={setOpen} open={open}>\n      <PopoverPrimitive.Anchor asChild>\n        <Slot\n          aria-describedby={triggerDescription}\n          onBlur={handleLeave}\n          onFocus={handleEnter}\n          onMouseEnter={handleEnter}\n          onMouseLeave={handleLeave}\n        >\n          {children}\n        </Slot>\n      </PopoverPrimitive.Anchor>\n\n      <AnimatePresence>\n        {open && (\n          <PopoverPrimitive.Portal forceMount>\n            <PopoverPrimitive.Content\n              align=\"center\"\n              asChild\n              avoidCollisions\n              collisionPadding={12}\n              forceMount\n              onCloseAutoFocus={(event) => event.preventDefault()}\n              onOpenAutoFocus={(event) => event.preventDefault()}\n              side={side}\n              sideOffset={10}\n            >\n              <motion.div\n                animate={{\n                  opacity: 1,\n                  scale: 1,\n                  filter: \"blur(0px)\",\n                }}\n                className={cn(\n                  tooltipThemeClassName,\n                  tooltipContentClassName,\n                  className\n                )}\n                exit={{\n                  opacity: 0,\n                  scale: 0.92,\n                  filter: \"blur(4px)\",\n                }}\n                id={tooltipId}\n                initial={{\n                  opacity: 0,\n                  scale: 0.92,\n                  filter: \"blur(4px)\",\n                }}\n                role=\"tooltip\"\n                style={{\n                  transformOrigin:\n                    \"var(--radix-popover-content-transform-origin)\",\n                }}\n                transition={{\n                  type: \"spring\",\n                  stiffness: 400,\n                  damping: 24,\n                  mass: 0.6,\n                }}\n              >\n                <motion.span\n                  animate={{ scale: 1 }}\n                  className={tooltipArrowClassName}\n                  exit={{ scale: 0.95, opacity: 0 }}\n                  initial={{ scale: 0.95, opacity: 0 }}\n                  transition={{\n                    type: \"spring\",\n                    stiffness: 500,\n                    damping: 28,\n                    delay: 0.03,\n                  }}\n                />\n                {normalizedContent}\n              </motion.div>\n            </PopoverPrimitive.Content>\n          </PopoverPrimitive.Portal>\n        )}\n      </AnimatePresence>\n    </PopoverPrimitive.Root>\n  );\n}\n\nexport { Tooltip as tooltip };\n",
      "type": "registry:ui"
    }
  ],
  "title": "Tooltip",
  "description": "Animated hover/focus tooltip with collision-aware portaled positioning, Slot-based triggers, short-string content, and optional delay and side placement. Built with Motion and Radix Popover."
}
