{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "lead-capture-popup",
  "title": "Lead Capture Popup",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-angular/blocks/lead-capture-popup/lead-capture-popup.component.ts",
      "content": "// High-conversion exit-intent discount popup and newsletter lead generator with a live\n// ticking countdown timer, value props, star-rating social proof, and coupon code reveal.\n// Port of the React block 1:1.\nimport { ChangeDetectionStrategy, Component, EventEmitter, Input, OnDestroy, OnInit, Output, signal } from '@angular/core'\nimport {\n  ArrowRight,\n  Check,\n  CheckCircle2,\n  Clock,\n  Copy,\n  Gift,\n  LucideAngularModule,\n  RotateCcw,\n  Star,\n  X,\n} from 'lucide-angular'\nimport { cn } from '@/lib/utils'\nimport { UiBadgeComponent } from '@/ui/badge/badge.component'\nimport { UiButtonComponent } from '@/ui/button/button.component'\nimport { UiInputComponent } from '@/ui/input/input.component'\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.Eager,\n  selector: 'ui-lead-capture-popup, [ui-lead-capture-popup]',\n  standalone: true,\n  // The block renders its own root <div> (form vs dismissed fallback): keep the host out of layout.\n  host: { '[attr.class]': '\"contents\"' },\n  imports: [LucideAngularModule, UiBadgeComponent, UiButtonComponent, UiInputComponent],\n  template: `\n    @if (!isDismissed()) {\n      <div data-slot=\"lead-capture-popup\" [class]=\"rootClass\">\n        <div\n          class=\"bg-card text-card-foreground border-border relative mx-auto w-full max-w-lg overflow-hidden rounded-2xl border p-6 shadow-xl sm:p-8\"\n        >\n          <!-- Top Right Dismiss Button -->\n          <button\n            type=\"button\"\n            aria-label=\"Dismiss popup\"\n            class=\"text-muted-foreground hover:text-foreground focus-visible:ring-ring absolute top-4 right-4 rounded-full p-1.5 transition-colors focus-visible:ring-2 focus-visible:outline-hidden\"\n            (click)=\"handleDismiss()\"\n          >\n            <lucide-icon [img]=\"X\" class=\"size-4\" />\n          </button>\n\n          <!-- FORM STATE -->\n          @if (!isSubmitted()) {\n            <div class=\"relative z-10 space-y-6\">\n              <!-- Top Badge -->\n              <div class=\"flex items-center\">\n                <span\n                  ui-badge\n                  variant=\"secondary\"\n                  class=\"border-primary/20 bg-primary/10 text-primary inline-flex items-center gap-1.5 px-3 py-1 text-xs font-medium\"\n                >\n                  <lucide-icon [img]=\"Gift\" class=\"text-primary size-3.5\" />\n                  Limited Time Welcome Gift\n                </span>\n              </div>\n\n              <!-- Urgency Countdown Bar -->\n              <div\n                class=\"border-warning/20 bg-warning/10 text-foreground text-warning flex items-center justify-between gap-2 rounded-lg border px-3.5 py-2 text-xs\"\n              >\n                <div class=\"flex items-center gap-2\">\n                  <lucide-icon [img]=\"Clock\" class=\"text-warning size-4 shrink-0\" />\n                  <span class=\"font-medium\"\n                    >Claim your {{ discountPercent }}% discount code before the timer expires:</span\n                  >\n                </div>\n                <span\n                  class=\"bg-warning/20 text-foreground dark:text-foreground rounded px-2 py-0.5 font-mono text-xs font-bold tabular-nums\"\n                >\n                  {{ formattedTime() }}\n                </span>\n              </div>\n\n              <!-- Headline & Subtitle -->\n              <div class=\"space-y-2\">\n                <h2 class=\"text-foreground text-2xl font-bold tracking-tight sm:text-3xl\">\n                  {{ headline }}\n                </h2>\n                <p class=\"text-muted-foreground text-sm leading-relaxed\">\n                  {{ subtitle }}\n                </p>\n              </div>\n\n              <!-- Value Bullet Points (3 items with success checkmarks) -->\n              <ul class=\"space-y-2.5\" role=\"list\">\n                <li class=\"text-muted-foreground flex items-center gap-2.5 text-xs sm:text-sm\">\n                  <span\n                    class=\"bg-success/15 text-success flex size-4 shrink-0 items-center justify-center rounded-full\"\n                  >\n                    <lucide-icon [img]=\"Check\" class=\"size-2.5 stroke-[3]\" />\n                  </span>\n                  <span>No spam ever &mdash; high-signal engineering teardowns</span>\n                </li>\n                <li class=\"text-muted-foreground flex items-center gap-2.5 text-xs sm:text-sm\">\n                  <span\n                    class=\"bg-success/15 text-success flex size-4 shrink-0 items-center justify-center rounded-full\"\n                  >\n                    <lucide-icon [img]=\"Check\" class=\"size-2.5 stroke-[3]\" />\n                  </span>\n                  <span>1-click unsubscribe anytime with zero friction</span>\n                </li>\n                <li class=\"text-muted-foreground flex items-center gap-2.5 text-xs sm:text-sm\">\n                  <span\n                    class=\"bg-success/15 text-success flex size-4 shrink-0 items-center justify-center rounded-full\"\n                  >\n                    <lucide-icon [img]=\"Check\" class=\"size-2.5 stroke-[3]\" />\n                  </span>\n                  <span>Instant coupon delivery straight to your screen &amp; inbox</span>\n                </li>\n              </ul>\n\n              <!-- Email Capture Form -->\n              <form class=\"space-y-3 pt-1\" (submit)=\"handleSubmit($event)\">\n                <ui-input\n                  [value]=\"email()\"\n                  (valueChange)=\"email.set($event)\"\n                  type=\"email\"\n                  placeholder=\"engineer@company.com\"\n                  required\n                  autoComplete=\"email\"\n                  aria-label=\"Email address\"\n                  class=\"border-border bg-background focus-visible:ring-primary h-11 text-sm shadow-xs focus-visible:ring-2\"\n                />\n\n                <button\n                  ui-button\n                  type=\"submit\"\n                  size=\"lg\"\n                  class=\"h-11 w-full justify-center gap-2 text-sm font-semibold shadow-xs\"\n                >\n                  Claim My {{ discountPercent }}% Discount\n                  <lucide-icon [img]=\"ArrowRight\" class=\"size-4\" />\n                </button>\n              </form>\n\n              <!-- Social Proof Line -->\n              <div class=\"text-muted-foreground flex items-center justify-center gap-1.5 text-xs\">\n                <div class=\"text-warning flex items-center gap-0.5\" aria-hidden=\"true\">\n                  <lucide-icon [img]=\"Star\" class=\"size-3.5 fill-current\" />\n                  <lucide-icon [img]=\"Star\" class=\"size-3.5 fill-current\" />\n                  <lucide-icon [img]=\"Star\" class=\"size-3.5 fill-current\" />\n                  <lucide-icon [img]=\"Star\" class=\"size-3.5 fill-current\" />\n                  <lucide-icon [img]=\"Star\" class=\"size-3.5 fill-current\" />\n                </div>\n                <span class=\"text-foreground font-medium\">{{ socialProofRating }}</span>\n                <span>rating by {{ socialProofCount }}</span>\n              </div>\n\n              <!-- Dismiss / Decline link -->\n              <div class=\"text-center\">\n                <button\n                  type=\"button\"\n                  class=\"text-muted-foreground hover:text-foreground focus-visible:ring-ring min-h-6 rounded text-xs underline underline-offset-4 transition-colors focus-visible:ring-2 focus-visible:outline-hidden\"\n                  (click)=\"handleDismiss()\"\n                >\n                  No thanks, I prefer paying full price\n                </button>\n              </div>\n            </div>\n          } @else {\n            <!-- SUCCESS STATE -->\n            <div class=\"relative z-10 space-y-5 text-center\">\n              <div class=\"bg-success/10 text-success mx-auto flex size-12 items-center justify-center rounded-full\">\n                <lucide-icon [img]=\"CheckCircle2\" class=\"size-6\" />\n              </div>\n\n              <div class=\"space-y-1.5\">\n                <span ui-badge variant=\"outline\" class=\"border-success/30 bg-success/10 text-success font-medium\">\n                  {{ discountPercent }}% Discount Unlocked\n                </span>\n                <h3 class=\"text-foreground text-2xl font-bold tracking-tight sm:text-3xl\">You&rsquo;re all set!</h3>\n                <p class=\"text-muted-foreground text-xs sm:text-sm\">\n                  We&rsquo;ve dispatched your code and welcome gift to\n                  <span class=\"text-foreground font-medium\">{{ email() || 'engineer@company.com' }}</span\n                  >.\n                </p>\n              </div>\n\n              <!-- Coupon Card Box -->\n              <div class=\"border-border bg-muted/40 relative space-y-3 rounded-xl border-2 border-dashed p-4\">\n                <span class=\"text-muted-foreground text-xs font-semibold tracking-wider uppercase\">\n                  Your Exclusive Coupon Code\n                </span>\n                <div class=\"flex items-center justify-center gap-2\">\n                  <code\n                    class=\"border-border bg-background text-foreground rounded-lg border px-3 py-1.5 font-mono text-xl font-bold tracking-widest sm:text-2xl\"\n                  >\n                    {{ discountCode }}\n                  </code>\n                  <button\n                    ui-button\n                    variant=\"secondary\"\n                    size=\"sm\"\n                    class=\"gap-1.5 shadow-xs\"\n                    [attr.aria-label]=\"copied() ? 'Copied code' : 'Copy discount code'\"\n                    (click)=\"copyCoupon()\"\n                  >\n                    @if (copied()) {\n                      <lucide-icon [img]=\"Check\" class=\"text-success size-3.5\" />\n                    } @else {\n                      <lucide-icon [img]=\"Copy\" class=\"size-3.5\" />\n                    }\n                    <span>{{ copied() ? 'Copied!' : 'Copy Code' }}</span>\n                  </button>\n                </div>\n                <p class=\"text-muted-foreground text-xs\">\n                  Valid for the next <span class=\"font-mono font-medium\">{{ formattedTime() }}</span> at checkout.\n                </p>\n              </div>\n\n              <div class=\"space-y-2 pt-2\">\n                <button\n                  ui-button\n                  class=\"h-11 w-full justify-center gap-2 text-sm font-semibold shadow-xs\"\n                  (click)=\"handleDismiss()\"\n                >\n                  Start Exploring Components\n                  <lucide-icon [img]=\"ArrowRight\" class=\"size-4\" />\n                </button>\n                <button\n                  type=\"button\"\n                  class=\"text-muted-foreground hover:text-foreground focus-visible:ring-ring min-h-6 rounded text-xs underline underline-offset-4 transition-colors focus-visible:ring-2 focus-visible:outline-hidden\"\n                  (click)=\"handleReset()\"\n                >\n                  Enter a different email\n                </button>\n              </div>\n            </div>\n          }\n        </div>\n      </div>\n    } @else {\n      <!-- Reopen trigger fallback when dismissed -->\n      <div class=\"flex flex-col items-center justify-center p-8 text-center\" data-slot=\"lead-capture-popup-dismissed\">\n        <p class=\"text-muted-foreground text-sm\">Popup was dismissed.</p>\n        <button ui-button variant=\"outline\" size=\"sm\" class=\"mt-3 gap-2\" (click)=\"handleReset()\">\n          <lucide-icon [img]=\"RotateCcw\" class=\"text-primary size-3.5\" />\n          Reopen Welcome Popup\n        </button>\n      </div>\n    }\n  `,\n})\nexport class UiLeadCapturePopupComponent implements OnInit, OnDestroy {\n  protected readonly ArrowRight = ArrowRight\n  protected readonly Check = Check\n  protected readonly CheckCircle2 = CheckCircle2\n  protected readonly Clock = Clock\n  protected readonly Copy = Copy\n  protected readonly Gift = Gift\n  protected readonly RotateCcw = RotateCcw\n  protected readonly Star = Star\n  protected readonly X = X\n\n  @Input() headline = 'Unlock 20% Off Your First Order'\n  @Input() subtitle =\n    'Join 45,000+ engineers receiving our weekly curated component teardowns and architectural breakdowns.'\n  @Input() discountCode = 'WELCOME20'\n  @Input() discountPercent = 20\n  @Input() initialSeconds = 599\n  @Input() socialProofRating = '4.9/5'\n  @Input() socialProofCount = '1,200+ developers'\n  @Input() initialSubmitted = false\n  @Input('class') className?: string\n\n  @Output() readonly submit = new EventEmitter<{ email: string; discountCode: string }>()\n  @Output() readonly dismiss = new EventEmitter<void>()\n  @Output() readonly copy = new EventEmitter<string>()\n  @Output('reset') readonly resetEmitter = new EventEmitter<void>()\n\n  readonly email = signal('')\n  readonly isSubmitted = signal(false)\n  readonly isDismissed = signal(false)\n  readonly copied = signal(false)\n  readonly timeLeft = signal(599)\n\n  private timer: ReturnType<typeof setInterval> | null = null\n  private copyTimer: ReturnType<typeof setTimeout> | null = null\n\n  ngOnInit(): void {\n    this.isSubmitted.set(this.initialSubmitted)\n    this.timeLeft.set(this.initialSeconds)\n    this.timer = setInterval(() => {\n      if (this.timeLeft() > 0) this.timeLeft.update((v) => v - 1)\n      else if (this.timer) clearInterval(this.timer)\n    }, 1000)\n  }\n\n  ngOnDestroy(): void {\n    if (this.timer) clearInterval(this.timer)\n    if (this.copyTimer) clearTimeout(this.copyTimer)\n  }\n\n  get rootClass(): string {\n    return cn('w-full', this.className)\n  }\n\n  formattedTime(): string {\n    const mins = Math.floor(this.timeLeft() / 60)\n    const secs = this.timeLeft() % 60\n    return `${String(mins).padStart(2, '0')}:${String(secs).padStart(2, '0')}`\n  }\n\n  handleSubmit(event?: Event): void {\n    event?.preventDefault()\n    const value = this.email()\n    if (!value || !value.includes('@')) return\n    this.isSubmitted.set(true)\n    this.submit.emit({ email: value, discountCode: this.discountCode })\n  }\n\n  handleDismiss(): void {\n    this.isDismissed.set(true)\n    this.dismiss.emit()\n  }\n\n  handleReset(): void {\n    this.isSubmitted.set(false)\n    this.isDismissed.set(false)\n    this.email.set('')\n    this.copied.set(false)\n    this.timeLeft.set(this.initialSeconds)\n    this.resetEmitter.emit()\n  }\n\n  open(): void {\n    this.isDismissed.set(false)\n  }\n\n  reset(): void {\n    this.handleReset()\n  }\n\n  copyCoupon(): void {\n    try {\n      void navigator.clipboard?.writeText(this.discountCode)\n    } catch {\n      // Clipboard fallback\n    }\n    this.copied.set(true)\n    this.copy.emit(this.discountCode)\n    if (this.copyTimer) clearTimeout(this.copyTimer)\n    this.copyTimer = setTimeout(() => this.copied.set(false), 2000)\n  }\n}\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/lead-capture-popup/lead-capture-popup.component.ts"
    },
    {
      "path": "packages/registry-angular/blocks/lead-capture-popup/index.ts",
      "content": "export { UiLeadCapturePopupComponent } from './lead-capture-popup.component'\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/lead-capture-popup/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/input.json"
  ],
  "description": "High-conversion exit-intent discount popup and newsletter lead generator with live ticking countdown timer, emerald value props, star rating social proof, and coupon code reveal.",
  "categories": [
    "marketing"
  ]
}