{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "announcement-corner-toast",
  "title": "Announcement — Corner Card",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-angular/blocks/announcement-corner-toast/announcement-corner-toast.component.ts",
      "content": "// Edit this file to change the copy, the `delay` or the dismissal key.\n// Dismissal is session-scoped (sessionStorage), so the card comes back in a new tab.\nimport {\n  Component,\n  DestroyRef,\n  Input,\n  afterNextRender,\n  computed,\n  inject,\n  signal,\n  ChangeDetectionStrategy,\n} from '@angular/core'\nimport { ArrowRight, Bell, LucideAngularModule, X } from 'lucide-angular'\nimport { cn } from '@/lib/utils'\nimport { UiBadgeComponent } from '@/ui/badge/badge.component'\nimport { UiButtonComponent } from '@/ui/button/button.component'\nimport { UiCardComponent, UiCardContentComponent } from '@/ui/card/card.component'\nimport { UiSeparatorComponent } from '@/ui/separator/separator.component'\n\n/**\n * AnnouncementCornerToast -- the React block, 1:1: a fixed bottom-right card that slides\n * in `delay` ms after the first render with a badge, headline, supporting line and two\n * actions. \"Not now\" and the close button dismiss it for the rest of the session.\n */\n@Component({\n  changeDetection: ChangeDetectionStrategy.Eager,\n  selector: 'ui-announcement-corner-toast, [ui-announcement-corner-toast]',\n  standalone: true,\n  // React renders the fixed <div> itself: keep this wrapper out of the layout.\n  host: { class: 'contents' },\n  imports: [\n    LucideAngularModule,\n    UiBadgeComponent,\n    UiButtonComponent,\n    UiCardComponent,\n    UiCardContentComponent,\n    UiSeparatorComponent,\n  ],\n  template: `\n    <div\n      data-slot=\"announcement-corner-toast\"\n      [class]=\"rootClass()\"\n      role=\"complementary\"\n      aria-label=\"Product announcement\"\n      [attr.aria-hidden]=\"!visible()\"\n    >\n      <ui-card class=\"shadow-lg\">\n        <ui-card-content class=\"p-4\">\n          <div class=\"flex items-start gap-3\">\n            <span\n              class=\"border-border bg-muted flex size-10 shrink-0 items-center justify-center rounded-lg border\"\n              aria-hidden=\"true\"\n            >\n              <lucide-icon [img]=\"Bell\" class=\"text-primary size-4\" />\n            </span>\n            <div class=\"min-w-0 flex-1\">\n              <span ui-badge variant=\"secondary\" class=\"mb-1.5\">New</span>\n              <p class=\"text-sm font-semibold\">Scoping now follows SCIM groups</p>\n              <p class=\"text-muted-foreground mt-1 text-xs leading-relaxed\">\n                Move someone between teams in your IdP and their dashboards follow within the sync window.\n              </p>\n            </div>\n            <button\n              ui-button\n              variant=\"ghost\"\n              size=\"icon\"\n              class=\"-mt-1 -mr-1 size-7 shrink-0\"\n              aria-label=\"Dismiss announcement\"\n              (click)=\"dismiss()\"\n            >\n              <lucide-icon [img]=\"X\" class=\"size-3.5\" aria-hidden=\"true\" />\n            </button>\n          </div>\n\n          <ui-separator class=\"my-3\" />\n\n          <div class=\"flex items-center gap-2\">\n            <!-- px-2.5: React's size=\"sm\" gets it from has-[>svg], but here the svg sits inside <lucide-icon>. -->\n            <button ui-button size=\"sm\" class=\"h-7 px-2.5\">\n              Read the changelog\n              <!-- [class] (not class=) feeds only the svg, so ml-1 is not applied twice (host + svg). -->\n              <lucide-icon [img]=\"ArrowRight\" [class]=\"'ml-1 size-3.5'\" aria-hidden=\"true\" />\n            </button>\n            <button ui-button variant=\"ghost\" size=\"sm\" class=\"h-7\" (click)=\"dismiss()\">Not now</button>\n          </div>\n        </ui-card-content>\n      </ui-card>\n    </div>\n  `,\n})\nexport class UiAnnouncementCornerToastComponent {\n  /** Milliseconds before the card slides in. */\n  @Input() delay = 1200\n  /** sessionStorage key holding the dismissal. */\n  @Input() storageKey = 'uipkge:corner-announcement-dismissed'\n\n  // Hidden on the server and on first paint; the delay timer is what reveals it.\n  readonly visible = signal(false)\n\n  protected readonly rootClass = computed(() =>\n    cn(\n      'fixed right-4 bottom-4 z-50 w-[22rem] max-w-[calc(100vw-2rem)] transition duration-300',\n      this.visible() ? 'translate-y-0 opacity-100' : 'pointer-events-none invisible translate-y-4 opacity-0',\n    ),\n  )\n\n  protected readonly Bell = Bell\n  protected readonly X = X\n  protected readonly ArrowRight = ArrowRight\n\n  private timer: ReturnType<typeof setTimeout> | undefined\n\n  constructor() {\n    // Browser only, after the first render (React's useEffect).\n    afterNextRender(() => {\n      if (this.wasDismissed()) return\n      this.timer = setTimeout(() => this.visible.set(true), this.delay)\n    })\n    inject(DestroyRef).onDestroy(() => clearTimeout(this.timer))\n  }\n\n  dismiss(): void {\n    this.visible.set(false)\n    try {\n      window.sessionStorage.setItem(this.storageKey, '1')\n    } catch {\n      // Blocked storage: the dismissal still holds for this page view.\n    }\n  }\n\n  private wasDismissed(): boolean {\n    try {\n      return window.sessionStorage.getItem(this.storageKey) === '1'\n    } catch {\n      return false\n    }\n  }\n}\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/announcement-corner-toast/announcement-corner-toast.component.ts"
    },
    {
      "path": "packages/registry-angular/blocks/announcement-corner-toast/index.ts",
      "content": "export { UiAnnouncementCornerToastComponent } from './announcement-corner-toast.component'\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/announcement-corner-toast/index.ts"
    }
  ],
  "dependencies": [
    "lucide-angular"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/angular/badge.json",
    "https://uipkge.dev/r/angular/button.json",
    "https://uipkge.dev/r/angular/card.json",
    "https://uipkge.dev/r/angular/separator.json"
  ],
  "description": "Corner announcement card that slides in after a delay carrying a thumbnail, headline, supporting line, and two actions, staying out of the page flow entirely.",
  "categories": [
    "marketing"
  ],
  "deprecated": true,
  "replacedBy": "announcement"
}