{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "banner",
  "title": "Banner",
  "author": "Ballmac <https://ui.ballmac.com>",
  "description": "A page-wide announcement with semantic tones, optional action, and controlled or local dismissal.",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "utils",
    "https://ui.ballmac.com/r/i18n.json"
  ],
  "files": [
    {
      "path": "registry/ballmac/components/banner.tsx",
      "content": "// Ballmac UI: Banner. https://ui.ballmac.com/components/banner\n\"use client\"\n\nimport * as React from \"react\"\nimport { CheckCircle2, Info, TriangleAlert, X } from \"lucide-react\"\nimport { cn } from \"@/lib/utils\"\nimport { useMessages } from \"@/lib/ballmac/i18n\"\n\ntype BannerProps = Omit<React.ComponentProps<\"section\">, \"title\"> & {\n  /** Short headline that names the announcement. */\n  title: string\n  /** Supporting detail, kept concise for a page-wide banner. */\n  description?: React.ReactNode\n  /** Semantic tone of the announcement. */\n  tone?: \"info\" | \"success\" | \"warning\"\n  /** Optional link or button placed after the message. */\n  action?: React.ReactNode\n  /** Show a dismiss button. */\n  dismissible?: boolean\n  /** Controlled visibility. */\n  visible?: boolean\n  /** Initial visibility when uncontrolled. */\n  defaultVisible?: boolean\n  /** Called when visibility changes. */\n  onVisibleChange?: (visible: boolean) => void\n}\n\nfunction Banner({\n  className,\n  title,\n  description,\n  tone = \"info\",\n  action,\n  dismissible = false,\n  visible,\n  defaultVisible = true,\n  onVisibleChange,\n  ...props\n}: BannerProps) {\n  const msg = useMessages()\n  const [internalVisible, setInternalVisible] = React.useState(defaultVisible)\n  const shown = visible ?? internalVisible\n  if (!shown) return null\n  const Icon =\n    tone === \"success\"\n      ? CheckCircle2\n      : tone === \"warning\"\n        ? TriangleAlert\n        : Info\n  function dismiss() {\n    if (visible === undefined) setInternalVisible(false)\n    onVisibleChange?.(false)\n  }\n  return (\n    <section\n      data-slot=\"banner\"\n      aria-label={title}\n      className={cn(\n        \"grid w-full min-w-0 grid-cols-[auto_minmax(0,1fr)_auto] items-start gap-x-3 gap-y-2 rounded-xl border px-4 py-3 text-sm shadow-sm sm:flex sm:flex-wrap sm:items-center\",\n        tone === \"info\" && \"border-primary/25 bg-primary/5\",\n        tone === \"success\" && \"border-chart-2/30 bg-chart-2/10\",\n        tone === \"warning\" && \"border-chart-3/30 bg-chart-3/10\",\n        className,\n      )}\n      {...props}\n    >\n      <Icon aria-hidden=\"true\" className=\"text-foreground col-start-1 row-start-1 mt-0.5 size-4 shrink-0 sm:mt-0\" />\n      <div className=\"col-start-2 row-start-1 min-w-0 flex-1 leading-5\">\n        <strong className=\"font-semibold\">{title}</strong>\n        {description && (\n          <span className=\"text-muted-foreground block sm:ms-1.5 sm:inline\">{description}</span>\n        )}\n      </div>\n      {action && (\n        <div data-slot=\"banner-action\" className=\"col-start-2 row-start-2 shrink-0\">\n          {action}\n        </div>\n      )}\n      {dismissible && (\n        <button\n          type=\"button\"\n          aria-label={msg(\"banner.dismiss\", \"Dismiss {title}\", { title })}\n          onClick={dismiss}\n          className=\"text-muted-foreground hover:bg-accent hover:text-foreground col-start-3 row-start-1 flex size-8 shrink-0 items-center justify-center rounded-md outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50\"\n        >\n          <X aria-hidden=\"true\" className=\"size-4\" />\n        </button>\n      )}\n    </section>\n  )\n}\n\nexport { Banner, type BannerProps }\n",
      "type": "registry:ui",
      "target": "@components/ballmac/banner.tsx"
    }
  ],
  "meta": {
    "schema": 1,
    "tier": "free",
    "tags": [
      "announcement",
      "status",
      "dismissible"
    ],
    "version": "1.0.0",
    "updated": "2026-09-30",
    "ai": {
      "summary": "A page-wide announcement with semantic tones, optional action, and controlled or local dismissal.",
      "whenToUse": [
        "Announce a page-level update",
        "Keep a persistent notice above page content"
      ],
      "whenNotToUse": [
        "Use alert for content scoped to one panel"
      ],
      "composesWith": [
        "alert",
        "button"
      ],
      "a11y": [
        {
          "keys": "Tab / Enter",
          "action": "Focus and activate the action or dismiss control"
        }
      ],
      "customization": [
        "tone: info | success | warning",
        "Controlled or uncontrolled visibility"
      ]
    },
    "examples": [
      "banner-demo",
      "banner-states"
    ],
    "url": "https://ui.ballmac.com/components/banner"
  },
  "categories": [
    "feedback"
  ],
  "type": "registry:ui"
}