{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "announcement-bar",
  "title": "Announcement Bar",
  "author": "Poyraz Avsever",
  "description": "Poyraz Soft Glass Announcement Bar with container-responsive layout and semantic tokens.",
  "dependencies": [
    "class-variance-authority@^0.7.1",
    "lucide-react@^0.574.0"
  ],
  "registryDependencies": [
    "@poyraz/poyraz-utils",
    "@poyraz/poyraz-theme"
  ],
  "files": [
    {
      "path": "registry/poyraz/ui/phase8/announcement-bar.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { X } from \"lucide-react\";\n\nimport { cn } from \"@/lib/utils\";\n\n/* ================================================================== */\n/*  ANNOUNCEMENT BAR — Dismissable top-of-page notification strip      */\n/* ================================================================== */\n\nconst announcementBarVariants = cva(\n  [\n    \"relative w-full\",\n    \"text-sm font-medium tracking-wide\",\n    \"border-b\",\n    \"data-[state=open]:animate-poyraz-slide-in-from-top\",\n    \"transition-colors duration-[var(--poyraz-motion-duration-fast)] ease-[var(--poyraz-motion-ease-out)]\",\n  ].join(\" \"),\n  {\n    variants: {\n      variant: {\n        default: \"bg-inverted text-inverted-foreground border-inverted\",\n        info: \"bg-info text-info-foreground border-info-border\",\n        success: \"bg-success text-success-foreground border-success-border\",\n        warning: \"bg-warning text-warning-foreground border-warning-border\",\n        danger: \"bg-destructive text-destructive-foreground border-destructive\",\n        branded: \"bg-primary text-primary-foreground border-primary-800\",\n      },\n    },\n    defaultVariants: {\n      variant: \"default\",\n    },\n  },\n);\n\nexport interface AnnouncementBarProps\n  extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof announcementBarVariants> {\n  /** Allow users to dismiss the bar */\n  dismissible?: boolean;\n  /** Callback when dismissed */\n  onDismiss?: () => void;\n  /** Icon to show before the content */\n  icon?: React.ReactNode;\n  /** Action element (e.g. link or button) at the end */\n  action?: React.ReactNode;\n  /** Controlled visibility. Persistence belongs to the caller or optional hook. */\n  open?: boolean;\n  /** Initial visibility for uncontrolled usage. */\n  defaultOpen?: boolean;\n  /** Called whenever visibility changes. */\n  onOpenChange?: (open: boolean) => void;\n}\n\nconst AnnouncementBar = React.forwardRef<HTMLDivElement, AnnouncementBarProps>(\n  (\n    {\n      className,\n      variant,\n      dismissible = true,\n      onDismiss,\n      icon,\n      action,\n      open: controlledOpen,\n      defaultOpen = true,\n      onOpenChange,\n      onAnimationEnd,\n      onTransitionEnd,\n      children,\n      ...props\n    },\n    ref,\n  ) => {\n    const [internalOpen, setInternalOpen] = React.useState(defaultOpen);\n    const open = controlledOpen ?? internalOpen;\n    const [present, setPresent] = React.useState(open);\n    const dismissPending = React.useRef(false);\n\n    const finishExit = React.useCallback(() => {\n      setPresent(false);\n      if (dismissPending.current) {\n        dismissPending.current = false;\n        onDismiss?.();\n      }\n    }, [onDismiss]);\n\n    React.useEffect(() => {\n      if (open) {\n        dismissPending.current = false;\n        setPresent(true);\n        return;\n      }\n      if (!present) return;\n      const reducedMotion = window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n      const timer = window.setTimeout(finishExit, reducedMotion ? 0 : 320);\n      return () => window.clearTimeout(timer);\n    }, [finishExit, open, present]);\n\n    if (!present) return null;\n\n    const handleDismiss = () => {\n      dismissPending.current = true;\n      if (controlledOpen === undefined) setInternalOpen(false);\n      onOpenChange?.(false);\n    };\n\n    return (\n      <div\n        ref={ref}\n        role=\"banner\"\n        data-slot=\"announcement-bar\"\n        data-variant={variant ?? \"default\"}\n        data-state={open ? \"open\" : \"closed\"}\n        onAnimationEnd={(event) => {\n          onAnimationEnd?.(event);\n          if (!open && event.currentTarget === event.target) finishExit();\n        }}\n        onTransitionEnd={(event) => {\n          onTransitionEnd?.(event);\n        }}\n        className={cn(\n          announcementBarVariants({ variant }),\n          \"motion-reduce:transition-none motion-reduce:data-[state=closed]:animate-none\",\n          open\n            ? \"opacity-100\"\n            : \"animate-poyraz-fade-out duration-[var(--poyraz-motion-duration-slow)]\",\n          className,\n        )}\n        {...props}\n      >\n        <div\n          data-slot=\"announcement-bar-content\"\n          className=\"@container/announcement mx-auto flex min-h-0 w-full max-w-5xl flex-wrap items-center justify-center gap-x-3 gap-y-1 overflow-hidden px-10 py-2 @sm/announcement:flex-nowrap\"\n        >\n          {icon && (\n            <span\n              data-slot=\"announcement-bar-icon\"\n              className=\"shrink-0 animate-poyraz-scale-in motion-reduce:animate-none\"\n            >\n              {icon}\n            </span>\n          )}\n          <span\n            data-slot=\"announcement-bar-message\"\n            className=\"min-w-0 text-center text-xs @sm/announcement:text-sm\"\n          >\n            {children}\n          </span>\n          {action && (\n            <span data-slot=\"announcement-bar-action\" className=\"shrink-0\">\n              {action}\n            </span>\n          )}\n          {dismissible && (\n            <button\n              type=\"button\"\n              data-slot=\"announcement-bar-close\"\n              onClick={handleDismiss}\n              className=\"absolute right-3 top-1/2 -translate-y-1/2 p-1 opacity-70 hover:opacity-100 hover:scale-105 active:scale-95 transition-[opacity,transform] duration-[var(--poyraz-motion-duration-fast)] ease-[var(--poyraz-motion-ease-out)] cursor-pointer\"\n              aria-label=\"Dismiss\"\n            >\n              <X className=\"h-3.5 w-3.5\" />\n            </button>\n          )}\n        </div>\n      </div>\n    );\n  },\n);\nAnnouncementBar.displayName = \"AnnouncementBar\";\n\nexport { AnnouncementBar, announcementBarVariants };\n",
      "type": "registry:ui",
      "target": "@ui/organisms/announcement-bar.tsx"
    }
  ],
  "meta": {
    "category": "phase-8-organism",
    "phase": "beta",
    "responsive": "container",
    "accessibilityReviewed": true
  },
  "type": "registry:ui"
}