{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "exit-intent-newsletter",
  "title": "Exit Intent — Newsletter",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-angular/blocks/exit-intent-newsletter/exit-intent-newsletter.component.ts",
      "content": "// Exit-intent capture for the monthly notes rather than a discount, naming the last issue\n// so the ask is concrete. Fires once per session when the pointer leaves toward the browser\n// chrome. Port of the Vue/React block 1:1.\nimport { ChangeDetectionStrategy, Component, Input, OnDestroy, OnInit, signal } from '@angular/core'\nimport { Check, LucideAngularModule, Mail } from 'lucide-angular'\nimport { UiBadgeComponent } from '@/ui/badge/badge.component'\nimport { UiButtonComponent } from '@/ui/button/button.component'\nimport {\n  UiDialogComponent,\n  UiDialogContentComponent,\n  UiDialogDescriptionComponent,\n  UiDialogHeaderComponent,\n  UiDialogTitleComponent,\n} from '@/ui/dialog/dialog.component'\nimport { UiInputComponent } from '@/ui/input/input.component'\nimport { UiSeparatorComponent } from '@/ui/separator/separator.component'\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.Eager,\n  selector: 'ui-exit-intent-newsletter, [ui-exit-intent-newsletter]',\n  standalone: true,\n  // The block renders its own root <div> (and the dialog portals to body): keep the host out of layout.\n  host: { '[attr.class]': '\"contents\"' },\n  imports: [\n    LucideAngularModule,\n    UiBadgeComponent,\n    UiButtonComponent,\n    UiDialogComponent,\n    UiDialogContentComponent,\n    UiDialogDescriptionComponent,\n    UiDialogHeaderComponent,\n    UiDialogTitleComponent,\n    UiInputComponent,\n    UiSeparatorComponent,\n  ],\n  template: `\n    <div data-slot=\"exit-intent-newsletter\">\n      <ui-dialog [open]=\"open()\" (openChange)=\"open.set($event)\">\n        <ui-dialog-content class=\"sm:max-w-md\">\n          <div ui-dialog-header>\n            <span ui-badge variant=\"secondary\" class=\"w-fit gap-1.5\">\n              <lucide-icon [img]=\"Mail\" class=\"size-3\" aria-hidden=\"true\" />\n              Monthly notes\n            </span>\n            <h2 ui-dialog-title class=\"mt-3 text-xl leading-snug text-balance\">\n              Not ready to trial? Take the writing instead\n            </h2>\n            <p ui-dialog-description class=\"leading-relaxed\">\n              Last issue: “Why we version metric definitions instead of dashboards.” One email a month, no product\n              announcements, unsubscribe in one click.\n            </p>\n          </div>\n\n          <ui-separator />\n\n          <form (submit)=\"subscribe($event)\">\n            <div class=\"flex gap-2\">\n              <ui-input\n                [value]=\"email()\"\n                (valueChange)=\"email.set($event)\"\n                type=\"email\"\n                required\n                placeholder=\"you@company.com\"\n                autoComplete=\"email\"\n                aria-label=\"Email address\"\n              />\n              <button ui-button type=\"submit\" class=\"shrink-0\">Subscribe</button>\n            </div>\n            <p class=\"mt-2 min-h-5 text-xs\" aria-live=\"polite\">\n              @if (submitted()) {\n                <span class=\"text-success inline-flex items-center gap-1.5\">\n                  <lucide-icon [img]=\"Check\" class=\"size-3\" aria-hidden=\"true\" />\n                  Check your inbox to confirm.\n                </span>\n              } @else {\n                <span class=\"text-muted-foreground\">8,400 subscribers, mostly data and finance engineers.</span>\n              }\n            </p>\n          </form>\n        </ui-dialog-content>\n      </ui-dialog>\n    </div>\n  `,\n})\nexport class UiExitIntentNewsletterComponent implements OnInit, OnDestroy {\n  protected readonly Check = Check\n  protected readonly Mail = Mail\n\n  @Input() storageKey = 'uipkge:exit-newsletter-seen'\n\n  readonly open = signal(false)\n  readonly email = signal('')\n  readonly submitted = signal(false)\n\n  private readonly onPointerOut = (event: MouseEvent): void => {\n    // Top edge only: leaving sideways is usually the scrollbar or another window.\n    if (event.relatedTarget || event.clientY > 4) return\n    try {\n      if (window.sessionStorage.getItem(this.storageKey) === '1') return\n      window.sessionStorage.setItem(this.storageKey, '1')\n    } catch {\n      // Blocked storage: shows once more this page view, never in a loop.\n    }\n    this.open.set(true)\n    document.removeEventListener('mouseout', this.onPointerOut)\n  }\n\n  ngOnInit(): void {\n    document.addEventListener('mouseout', this.onPointerOut)\n  }\n\n  ngOnDestroy(): void {\n    document.removeEventListener('mouseout', this.onPointerOut)\n  }\n\n  subscribe(event: Event): void {\n    event.preventDefault()\n    if (!this.email().trim()) return\n    this.submitted.set(true)\n  }\n}\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/exit-intent-newsletter/exit-intent-newsletter.component.ts"
    },
    {
      "path": "packages/registry-angular/blocks/exit-intent-newsletter/index.ts",
      "content": "export { UiExitIntentNewsletterComponent } from './exit-intent-newsletter.component'\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/exit-intent-newsletter/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/dialog.json",
    "https://uipkge.dev/r/angular/input.json",
    "https://uipkge.dev/r/angular/separator.json"
  ],
  "description": "Exit-intent dialog capturing an email for the monthly notes rather than pushing a discount, with the last issue named so the ask is concrete.",
  "categories": [
    "marketing"
  ],
  "deprecated": true,
  "replacedBy": "exit-intent"
}