{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "callout",
  "type": "registry:ui",
  "dependencies": [
    "clsx",
    "tailwind-merge"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "callout.tsx",
      "target": "components/ui/callout.tsx",
      "type": "registry:ui",
      "content": "\"use client\";\nimport * as React from \"react\";\nimport { cn } from \"@/lib/utils\";\n\nexport type CalloutTone = \"neutral\" | \"info\" | \"success\" | \"warning\" | \"danger\";\n\ninterface ToneStyle {\n  icon: React.ReactNode;\n  text: string;\n  dot: string;\n  tint: string;\n}\n\nconst toneStyles: Record<Exclude<CalloutTone, \"neutral\">, ToneStyle> = {\n  info: {\n    icon: <InfoIcon />,\n    text: \"text-info\",\n    dot: \"bg-info\",\n    tint: \"bg-info/[0.06]\",\n  },\n  success: {\n    icon: <CheckIcon />,\n    text: \"text-success\",\n    dot: \"bg-success\",\n    tint: \"bg-success/[0.06]\",\n  },\n  warning: {\n    icon: <AlertIcon />,\n    text: \"text-warning\",\n    dot: \"bg-warning\",\n    tint: \"bg-warning/[0.06]\",\n  },\n  danger: {\n    icon: <ErrorIcon />,\n    text: \"text-danger\",\n    dot: \"bg-danger\",\n    tint: \"bg-danger/[0.07]\",\n  },\n};\n\nexport interface CalloutProps\n  extends Omit<React.HTMLAttributes<HTMLDivElement>, \"title\"> {\n  tone?: CalloutTone;\n  title?: React.ReactNode;\n  /** One action on the end of the block. Anything more belongs on the page. */\n  action?: React.ReactNode;\n  /** Swap the tone icon, or pass false to drop it. */\n  icon?: React.ReactNode | false;\n  /** A callout that vanishes on its own is a toast, so this is opt-in. */\n  dismissible?: boolean;\n  onDismiss?: () => void;\n  dismissLabel?: string;\n}\n\nexport const Callout = React.forwardRef<HTMLDivElement, CalloutProps>(\n  (\n    {\n      className,\n      tone = \"neutral\",\n      title,\n      action,\n      icon,\n      dismissible = false,\n      onDismiss,\n      dismissLabel = \"Dismiss\",\n      children,\n      ...props\n    },\n    ref,\n  ) => {\n    const [dismissed, setDismissed] = React.useState(false);\n    if (dismissed) return null;\n\n    const styles = tone === \"neutral\" ? undefined : toneStyles[tone];\n    const glyph = icon === false ? null : (icon ?? styles?.icon ?? null);\n\n    return (\n      <div\n        ref={ref}\n        role={tone === \"danger\" ? \"alert\" : \"status\"}\n        data-tone={tone}\n        className={cn(\n          \"relative isolate flex w-full gap-3 rounded-xl border border-border bg-surface p-4 text-ink\",\n          className,\n        )}\n        {...props}\n      >\n        {styles ? (\n          <span\n            aria-hidden=\"true\"\n            className={cn(\n              \"pointer-events-none absolute inset-0 rounded-[inherit]\",\n              styles.tint,\n            )}\n          />\n        ) : null}\n\n        {glyph ? (\n          <span\n            aria-hidden=\"true\"\n            className={cn(\"relative mt-px shrink-0\", styles?.text)}\n          >\n            {glyph}\n          </span>\n        ) : null}\n\n        <div className=\"relative flex min-w-0 flex-1 flex-col gap-1\">\n          {title ? (\n            <div className=\"flex items-center gap-2\">\n              {styles ? (\n                <span\n                  aria-hidden=\"true\"\n                  className={cn(\"size-1.5 shrink-0 rounded-full\", styles.dot)}\n                />\n              ) : null}\n              <p className=\"font-semibold text-sm text-ink\">{title}</p>\n            </div>\n          ) : null}\n          {children ? (\n            <div className=\"text-sm text-muted text-pretty\">{children}</div>\n          ) : null}\n          {action ? <div className=\"mt-2 flex gap-2\">{action}</div> : null}\n        </div>\n\n        {dismissible ? (\n          <button\n            type=\"button\"\n            aria-label={dismissLabel}\n            onClick={() => {\n              setDismissed(true);\n              onDismiss?.();\n            }}\n            className={cn(\n              \"relative -mt-1 -mr-1 grid size-7 shrink-0 place-items-center self-start rounded-md text-muted outline-none\",\n              \"transition-control duration-base ease-soft motion-reduce:transition-none\",\n              \"hover:bg-surface-2 hover:text-ink focus-visible:ring-focus\",\n            )}\n          >\n            <CloseIcon />\n          </button>\n        ) : null}\n      </div>\n    );\n  },\n);\nCallout.displayName = \"Callout\";\n\nfunction CheckIcon() {\n  return (\n    <svg\n      viewBox=\"0 0 24 24\"\n      width=\"18\"\n      height=\"18\"\n      fill=\"none\"\n      stroke=\"currentColor\"\n      strokeWidth=\"2\"\n      strokeLinecap=\"round\"\n      strokeLinejoin=\"round\"\n      aria-hidden=\"true\"\n    >\n      <circle cx=\"12\" cy=\"12\" r=\"9\" />\n      <path d=\"m8.5 12 2.5 2.5 4.5-5\" />\n    </svg>\n  );\n}\n\nfunction AlertIcon() {\n  return (\n    <svg\n      viewBox=\"0 0 24 24\"\n      width=\"18\"\n      height=\"18\"\n      fill=\"none\"\n      stroke=\"currentColor\"\n      strokeWidth=\"2\"\n      strokeLinecap=\"round\"\n      strokeLinejoin=\"round\"\n      aria-hidden=\"true\"\n    >\n      <path d=\"M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0Z\" />\n      <path d=\"M12 9v4M12 17h.01\" />\n    </svg>\n  );\n}\n\nfunction ErrorIcon() {\n  return (\n    <svg\n      viewBox=\"0 0 24 24\"\n      width=\"18\"\n      height=\"18\"\n      fill=\"none\"\n      stroke=\"currentColor\"\n      strokeWidth=\"2\"\n      strokeLinecap=\"round\"\n      strokeLinejoin=\"round\"\n      aria-hidden=\"true\"\n    >\n      <circle cx=\"12\" cy=\"12\" r=\"9\" />\n      <path d=\"m15 9-6 6M9 9l6 6\" />\n    </svg>\n  );\n}\n\nfunction InfoIcon() {\n  return (\n    <svg\n      viewBox=\"0 0 24 24\"\n      width=\"18\"\n      height=\"18\"\n      fill=\"none\"\n      stroke=\"currentColor\"\n      strokeWidth=\"2\"\n      strokeLinecap=\"round\"\n      strokeLinejoin=\"round\"\n      aria-hidden=\"true\"\n    >\n      <circle cx=\"12\" cy=\"12\" r=\"9\" />\n      <path d=\"M12 11v5M12 8h.01\" />\n    </svg>\n  );\n}\n\nfunction CloseIcon() {\n  return (\n    <svg\n      viewBox=\"0 0 24 24\"\n      width=\"14\"\n      height=\"14\"\n      fill=\"none\"\n      stroke=\"currentColor\"\n      strokeWidth=\"2\"\n      strokeLinecap=\"round\"\n      strokeLinejoin=\"round\"\n      aria-hidden=\"true\"\n    >\n      <path d=\"M18 6 6 18M6 6l12 12\" />\n    </svg>\n  );\n}\n"
    }
  ]
}