{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "core-info-tip",
  "type": "registry:ui",
  "title": "Info Tip",
  "description": "An (i) console icon button that opens help on Base UI's Popover, so touch, keyboard and screen-reader users can reach it: a click, a tap, Enter or Space opens a dialog named by the label and described by the help, focus moves in, and Escape or an outside press closes it and returns focus to the button. The button sits at the console control height, the popup portals into the fullscreen element in browser fullscreen, and InfoTipContent spaces rich help (paragraphs, lists, code, keys).",
  "dependencies": [
    "@base-ui/react",
    "maruaudio@>=0.0.3 <0.1.0"
  ],
  "registryDependencies": [
    "https://pluginui.com/r/core-console-button.json",
    "https://pluginui.com/r/core-popover.json"
  ],
  "files": [
    {
      "path": "components/ui/info-tip.tsx",
      "content": "/**\n * Source: https://maru.audio/ui-kit/info-tip\n * Copyright © [Maru](https://maru.audio)\n *\n * Maru UI Kit — https://maru.audio/ui-kit\n *\n * Installed from the Maru UI registry. This file is yours now: edit it\n * freely, it will not be overwritten unless you re-run the add command.\n *\n * Keep this item’s companion files and CSS imports together. Dependencies\n * declared by the registry are installed with the source.\n */\n/**\n * InfoTip — an (i) button that opens a short piece of help beside a control:\n * what a seed does, why an option is unavailable, how a notation reads.\n *\n * Built on Base UI's Popover, so unlike a tooltip it works for everyone: a\n * click, a tap, Enter or Space opens it; focus moves into the popup (a\n * dialog named by `label`) so a screen reader reads the help; Escape or a\n * press outside closes it and focus returns to the (i) button.\n *\n *   <InfoTip label=\"About seeds\">\n *     <p>A seed picks one random outcome. The same seed gives the same phrase.</p>\n *   </InfoTip>\n *\n * The button is a square console icon button at the console control height\n * (`size`, \"sm\" by default so it sits inside a label row). The popup is\n * portaled into `overlayContainerFor(trigger)` as it opens, so it stays\n * visible while the face is in browser fullscreen, with the face's theme\n * variables copied onto it. `InfoTipContent` styles rich help (paragraphs,\n * lists, code, keys) the same way the popup does, for a popover of your own.\n */\n\nimport {\n  createElement,\n  useState,\n  type CSSProperties,\n  type ComponentProps,\n  type JSX,\n  type ReactElement,\n  type ReactNode,\n} from \"react\"\nimport { PopoverParts as Popover } from \"@/components/ui/popover\"\nimport {\n  overlayPopupStyle,\n  overlayContainerFor,\n} from \"maruaudio/ui/shared/overlay-container\"\nimport { ConsoleIcon } from \"maruaudio/ui/shared/console-icons\"\nimport {\n  OVERLAY_Z_INDEX,\n  contextMenuPortalTheme,\n} from \"maruaudio/ui/shared/context-menu-target\"\nimport {\n  ConsoleButtonStyles,\n  consoleButtonStyle,\n  consoleIconSize,\n  type ConsoleControlSize,\n} from \"@/components/ui/console-button\"\n\nexport interface InfoTipProps {\n  readonly positionerProps?: Omit<\n    ComponentProps<typeof Popover.Positioner>,\n    \"children\"\n  >\n  /** The (i) button's accessible name and the popup's: \"About seeds\". */\n  readonly label: string\n  /** The help. Plain text or rich content (paragraphs, lists, code). */\n  readonly children: ReactNode\n  /** Optional text/icon content for a compact settings trigger. Defaults to the info icon. */\n  readonly trigger?: ReactNode\n  /** Preferred popup width, still constrained to the available viewport. */\n  readonly popupWidth?: number | string\n  /** Which side of the button the popup opens on. Defaults to \"bottom\". */\n  readonly side?: \"top\" | \"bottom\" | \"left\" | \"right\"\n  /** Button height. Defaults to \"sm\" (24px unless the face sets the variable). */\n  readonly size?: ConsoleControlSize\n  /** On the (i) button. */\n  readonly className?: string\n  /** On the (i) button, after its defaults. */\n  readonly style?: CSSProperties\n}\n\n/** The `href` React dedupes the help content stylesheet by. */\nexport const INFO_TIP_STYLES_HREF = \"uikit-info-tip\"\n\n/**\n * Spacing for rich help inside an InfoTip (or any popover): paragraphs and\n * lists with small gaps, code and keys in the mono font.\n */\nexport const INFO_TIP_STYLES = String.raw`\n[data-info-tip-content]>:first-child{margin-top:0}\n[data-info-tip-content]>:last-child{margin-bottom:0}\n[data-info-tip-content] p,[data-info-tip-content] ul,[data-info-tip-content] ol{margin:0 0 6px}\n[data-info-tip-content] ul,[data-info-tip-content] ol{padding-left:16px}\n[data-info-tip-content] li+li{margin-top:2px}\n[data-info-tip-content] code,[data-info-tip-content] kbd{font-family:var(--uikit-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);font-size:11px}\n[data-info-tip-content] strong{color:var(--uikit-menu-text, #f4f4f5);font-weight:600}\n[data-info-tip-popup]:focus-visible{outline:2px solid var(--uikit-focus, var(--uikit-accent, #6366f1));outline-offset:1px}\n[data-info-tip-popup]{outline:none}\n@media (prefers-reduced-motion: no-preference){\n[data-info-tip-popup]{transition:opacity 100ms ease-out}\n[data-info-tip-popup][data-starting-style],[data-info-tip-popup][data-ending-style]{opacity:0}\n}\n`.replace(/\\n/g, \"\")\n\n/** The help stylesheet as a hoisted, deduped `<style>`. */\nexport function InfoTipStyles(): ReactElement {\n  return createElement(\n    \"style\",\n    { href: INFO_TIP_STYLES_HREF, precedence: \"default\" },\n    INFO_TIP_STYLES\n  )\n}\n\n/** Inline style of the help content: 12px text, readable line length. */\nexport const INFO_TIP_CONTENT_STYLE: CSSProperties = {\n  // 14.6:1 on the fallback surface.\n  color: \"var(--uikit-menu-text, #f4f4f5)\",\n  font: \"12px/1.45 var(--uikit-font, ui-sans-serif, system-ui, sans-serif)\",\n  overflowWrap: \"anywhere\",\n}\n\n/** Rich help content: paragraphs, lists, code and keys spaced for a small popup. */\nexport function InfoTipContent({\n  children,\n  className,\n  style,\n}: {\n  readonly children: ReactNode\n  readonly className?: string\n  readonly style?: CSSProperties\n}): JSX.Element {\n  return (\n    <div\n      data-info-tip-content=\"\"\n      className={className}\n      style={{ ...INFO_TIP_CONTENT_STYLE, ...style }}\n    >\n      <InfoTipStyles />\n      {children}\n    </div>\n  )\n}\n\nconst popupStyle: CSSProperties = {\n  ...overlayPopupStyle({ maxWidth: \"20rem\", maxHeight: \"24rem\" }),\n  width: \"max-content\",\n  padding: \"8px 10px\",\n  borderRadius: 8,\n  border: \"1px solid var(--uikit-menu-border, rgba(148, 163, 184, 0.35))\",\n  background: \"var(--uikit-menu-surface, #202127)\",\n  boxShadow: \"0 12px 32px rgb(0 0 0 / .36)\",\n}\n\ninterface InfoTipLayer {\n  readonly container: HTMLElement\n  readonly theme: CSSProperties\n}\n\n/** An (i) button that opens a popover of help. */\nexport function InfoTip({\n  label,\n  children,\n  trigger,\n  popupWidth,\n  positionerProps,\n  side = \"bottom\",\n  size = \"sm\",\n  className,\n  style,\n}: InfoTipProps): JSX.Element {\n  const [open, setOpen] = useState(false)\n  const [layer, setLayer] = useState<InfoTipLayer | null>(null)\n\n  return (\n    <Popover.Root\n      open={open}\n      onOpenChange={(next, details) => {\n        if (next) {\n          const trigger = details.trigger as HTMLElement | undefined\n          const container = overlayContainerFor(trigger ?? null)\n          if (trigger && container) {\n            setLayer({ container, theme: contextMenuPortalTheme(trigger) })\n          }\n        }\n        setOpen(next)\n      }}\n    >\n      <ConsoleButtonStyles />\n      <Popover.Trigger\n        aria-label={label}\n        className={className}\n        data-console-button=\"\"\n        data-variant=\"ghost\"\n        data-size={size}\n        data-info-tip-trigger=\"\"\n        style={{ ...consoleButtonStyle(size, trigger === undefined), ...style }}\n      >\n        {trigger ?? <ConsoleIcon name=\"info\" size={consoleIconSize(size)} />}\n      </Popover.Trigger>\n      {layer ? (\n        <Popover.Portal>\n          <Popover.Positioner\n            side={side}\n            sideOffset={6}\n            collisionPadding={8}\n            style={{ zIndex: OVERLAY_Z_INDEX }}\n            {...positionerProps}\n          >\n            <Popover.Popup\n              aria-label={label}\n              data-info-tip-popup=\"\"\n              style={{\n                ...popupStyle,\n                ...layer.theme,\n                ...(popupWidth === undefined ? {} : { width: popupWidth }),\n              }}\n            >\n              <InfoTipStyles />\n              {/* A div, not the default p: the help may hold paragraphs and lists. */}\n              <Popover.Description\n                render={<div />}\n                data-info-tip-content=\"\"\n                style={INFO_TIP_CONTENT_STYLE}\n              >\n                {children}\n              </Popover.Description>\n            </Popover.Popup>\n          </Popover.Positioner>\n        </Popover.Portal>\n      ) : null}\n    </Popover.Root>\n  )\n}\n",
      "type": "registry:component",
      "target": "@ui/info-tip.tsx"
    }
  ]
}
