{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "exit-intent-survey",
  "title": "Exit Intent — Survey",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-angular/blocks/exit-intent-survey/exit-intent-survey.component.ts",
      "content": "// One-question exit survey asking what the visitor did not find, with preset answers, an\n// optional free-text field, and a thank-you state that closes itself. Fires once per session\n// when the pointer leaves toward the browser chrome. Port of the Vue/React block 1:1.\nimport { ChangeDetectionStrategy, Component, DestroyRef, Input, OnDestroy, OnInit, inject, signal } from '@angular/core'\nimport { Check, LucideAngularModule } 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 { UiTextareaComponent } from '@/ui/textarea/textarea.component'\nimport { UiToggleGroupComponent, UiToggleGroupItemComponent } from '@/ui/toggle-group/toggle-group.component'\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.Eager,\n  selector: 'ui-exit-intent-survey, [ui-exit-intent-survey]',\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    UiTextareaComponent,\n    UiToggleGroupComponent,\n    UiToggleGroupItemComponent,\n  ],\n  template: `\n    <div data-slot=\"exit-intent-survey\">\n      <ui-dialog [open]=\"open()\" (openChange)=\"open.set($event)\">\n        <ui-dialog-content class=\"sm:max-w-md\">\n          @if (!sent()) {\n            <div>\n              <div ui-dialog-header>\n                <span ui-badge variant=\"secondary\" class=\"w-fit\">One question</span>\n                <h2 ui-dialog-title class=\"mt-3 text-xl leading-snug text-balance\">What were you looking for?</h2>\n                <p ui-dialog-description>\n                  It goes to the people who build the page. No follow-up email unless you ask for one.\n                </p>\n              </div>\n\n              <ui-toggle-group\n                type=\"single\"\n                [value]=\"choice()\"\n                variant=\"outline\"\n                size=\"sm\"\n                class=\"mt-5 flex-wrap justify-start\"\n                aria-label=\"Reason for leaving\"\n                (valueChange)=\"onChoiceChange($event)\"\n              >\n                @for (option of options; track option) {\n                  <button ui-toggle-group-item [value]=\"option\">{{ option }}</button>\n                }\n              </ui-toggle-group>\n\n              <ui-textarea\n                [value]=\"detail()\"\n                (valueChange)=\"detail.set($event)\"\n                class=\"mt-3\"\n                [rows]=\"3\"\n                placeholder=\"Anything more (optional)\"\n                label=\"Anything more (optional)\"\n              />\n\n              <div class=\"mt-4 flex items-center gap-2\">\n                <button ui-button [disabled]=\"!choice()\" (click)=\"submit()\">Send</button>\n                <button ui-button variant=\"ghost\" (click)=\"open.set(false)\">Skip</button>\n              </div>\n            </div>\n          } @else {\n            <div class=\"py-6 text-center\" aria-live=\"polite\">\n              <span class=\"bg-success/10 mx-auto flex size-10 items-center justify-center rounded-full\">\n                <lucide-icon [img]=\"Check\" class=\"text-success size-5\" aria-hidden=\"true\" />\n              </span>\n              <p class=\"mt-3 text-sm font-medium\">Thanks — that is genuinely useful.</p>\n            </div>\n          }\n        </ui-dialog-content>\n      </ui-dialog>\n    </div>\n  `,\n})\nexport class UiExitIntentSurveyComponent implements OnInit, OnDestroy {\n  protected readonly Check = Check\n\n  @Input() storageKey = 'uipkge:exit-survey-seen'\n\n  readonly open = signal(false)\n  readonly choice = signal('')\n  readonly detail = signal('')\n  readonly sent = signal(false)\n\n  protected readonly options = [\n    'Pricing was unclear',\n    'Missing an integration',\n    'Just browsing',\n    'Security questions',\n    'Something else',\n  ]\n\n  private sendTimer: ReturnType<typeof setTimeout> | undefined\n\n  private readonly onPointerOut = (event: MouseEvent): void => {\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  constructor() {\n    inject(DestroyRef).onDestroy(() => clearTimeout(this.sendTimer))\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  onChoiceChange(value: string): void {\n    this.choice.set(value ?? '')\n  }\n\n  submit(): void {\n    if (!this.choice()) return\n    this.sent.set(true)\n    // Close on its own rather than making someone dismiss a thank-you.\n    clearTimeout(this.sendTimer)\n    this.sendTimer = setTimeout(() => this.open.set(false), 1400)\n  }\n}\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/exit-intent-survey/exit-intent-survey.component.ts"
    },
    {
      "path": "packages/registry-angular/blocks/exit-intent-survey/index.ts",
      "content": "export { UiExitIntentSurveyComponent } from './exit-intent-survey.component'\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/exit-intent-survey/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/textarea.json",
    "https://uipkge.dev/r/angular/toggle-group.json"
  ],
  "description": "One-question exit survey asking what the visitor did not find, with preset answers, an optional free-text field, and a thank-you state that closes itself.",
  "categories": [
    "marketing"
  ],
  "deprecated": true,
  "replacedBy": "exit-intent"
}