{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "r-tooltip",
  "type": "registry:ui",
  "registryDependencies": [],
  "dependencies": ["@radix-ui/react-tooltip", "@radix-ui/react-slot", "motion"],
  "devDependencies": [],
  "files": [
    {
      "path": "r-tooltip.tsx",
      "content": "\"use client\";\n\nimport { Slot } from \"@radix-ui/react-slot\";\nimport * as TooltipPrimitive from \"@radix-ui/react-tooltip\";\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 handleOpenChange = React.useCallback(\n    (nextOpen: boolean) => {\n      clearTimeout(timeoutRef.current);\n\n      if (nextOpen) {\n        if (open) {\n          return;\n        }\n\n        timeoutRef.current = setTimeout(() => setOpen(true), delay * 1000);\n        return;\n      }\n\n      setOpen(false);\n    },\n    [delay, open]\n  );\n\n  React.useEffect(() => () => clearTimeout(timeoutRef.current), []);\n\n  if (normalizedContent.length === 0) {\n    return children;\n  }\n\n  return (\n    <TooltipPrimitive.Provider delayDuration={0} skipDelayDuration={0}>\n      <TooltipPrimitive.Root\n        delayDuration={0}\n        onOpenChange={handleOpenChange}\n        open={open}\n      >\n        <TooltipPrimitive.Trigger asChild>\n          <Slot aria-describedby={triggerDescription}>{children}</Slot>\n        </TooltipPrimitive.Trigger>\n\n        <AnimatePresence>\n          {open && (\n            <TooltipPrimitive.Portal forceMount>\n              <TooltipPrimitive.Content\n                align=\"center\"\n                asChild\n                avoidCollisions\n                collisionPadding={12}\n                forceMount\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-tooltip-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              </TooltipPrimitive.Content>\n            </TooltipPrimitive.Portal>\n          )}\n        </AnimatePresence>\n      </TooltipPrimitive.Root>\n    </TooltipPrimitive.Provider>\n  );\n}\n\nexport { Tooltip as tooltip };\n",
      "type": "registry:ui"
    }
  ],
  "title": "Tooltip (Radix UI)",
  "description": "Tooltip with the same Iconiq API layered over Radix Tooltip primitives, preserving the original controlled delay timing, bubble shell, rotated-square arrow, and spring entrance motion."
}
