{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "invoice-creator-wizard",
  "title": "Invoice Creator Wizard",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-angular/blocks/invoice-creator-wizard/invoice-creator-wizard.component.ts",
      "content": "import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnInit, Output, computed, signal } from '@angular/core'\nimport {\n  Building2,\n  CheckCircle2,\n  CreditCard,\n  Eye,\n  FileText,\n  LucideAngularModule,\n  Percent,\n  Plus,\n  Receipt,\n  Save,\n  Send,\n  Trash2,\n} from 'lucide-angular'\nimport { cn } from '@/lib/utils'\nimport { UiBadgeComponent } from '@/ui/badge/badge.component'\nimport { UiButtonComponent } from '@/ui/button/button.component'\nimport {\n  UiCardComponent,\n  UiCardContentComponent,\n  UiCardDescriptionComponent,\n  UiCardHeaderComponent,\n  UiCardTitleComponent,\n} from '@/ui/card/card.component'\nimport { UiInputComponent } from '@/ui/input/input.component'\nimport {\n  UiSelectComponent,\n  UiSelectContentComponent,\n  UiSelectItemComponent,\n  UiSelectTriggerComponent,\n  UiSelectValueComponent,\n} from '@/ui/select/select.component'\nimport { UiSeparatorComponent } from '@/ui/separator/separator.component'\nimport { UiTextareaComponent } from '@/ui/textarea/textarea.component'\n\nexport interface InvoiceLineItem {\n  id: string\n  description: string\n  quantity: number\n  unitPrice: number\n}\n\nexport interface ClientPreset {\n  id: string\n  name: string\n  company: string\n  email: string\n  address: string\n}\n\nconst CLIENT_PRESETS: ClientPreset[] = [\n  {\n    id: 'c1',\n    name: 'Sarah Jenkins',\n    company: 'Apex Digital Inc.',\n    email: 'sarah.jenkins@apexdigital.com',\n    address: '742 Evergreen Terrace, Springfield, OR 97477',\n  },\n  {\n    id: 'c2',\n    name: 'Marcus Vance',\n    company: 'Northwind Global Corp.',\n    email: 'marcus.vance@northwind.io',\n    address: '452 Broadway, 8th Floor, New York, NY 10013',\n  },\n  {\n    id: 'c3',\n    name: 'Elena Rostova',\n    company: 'Hyperion Robotics',\n    email: 'elena@hyperion-robotics.ai',\n    address: '10 Tech Parkway, Suite 300, Boston, MA 02115',\n  },\n]\n\nconst DEFAULT_LINE_ITEMS: InvoiceLineItem[] = [\n  { id: 'item-1', description: 'Design System Architecture & Component Registry', quantity: 1, unitPrice: 3200 },\n  { id: 'item-2', description: 'Frontend Implementation (Vue 3 + React Mirror)', quantity: 35, unitPrice: 120 },\n  { id: 'item-3', description: 'Accessibility & WCAG AA Compliance Audit', quantity: 1, unitPrice: 850 },\n]\n\nconst PAYMENT_TERMS_MAP: Record<string, string> = {\n  receipt: 'Due on Receipt',\n  net15: 'Net 15 (Due in 15 days)',\n  net30: 'Net 30 (Due in 30 days)',\n  net60: 'Net 60 (Due in 60 days)',\n}\n\n/**\n * InvoiceCreatorWizard -- the React block, 1:1: a Square/Stripe-style interactive invoice\n * builder with a business/client details card, client presets, invoice timing + currency\n * selects, a dynamic line-items table, tax/discount adjustments, notes, a live paper\n * document preview, and Preview PDF / Save Draft / Send Invoice actions with a banner.\n */\n@Component({\n  changeDetection: ChangeDetectionStrategy.Eager,\n  selector: 'ui-invoice-creator-wizard, [ui-invoice-creator-wizard]',\n  standalone: true,\n  // React renders the root <div> itself: the host stays out of layout and `class` goes to the root.\n  host: { '[attr.class]': '\"contents\"' },\n  imports: [\n    LucideAngularModule,\n    UiBadgeComponent,\n    UiButtonComponent,\n    UiCardComponent,\n    UiCardContentComponent,\n    UiCardDescriptionComponent,\n    UiCardHeaderComponent,\n    UiCardTitleComponent,\n    UiInputComponent,\n    UiSelectComponent,\n    UiSelectContentComponent,\n    UiSelectItemComponent,\n    UiSelectTriggerComponent,\n    UiSelectValueComponent,\n    UiSeparatorComponent,\n    UiTextareaComponent,\n  ],\n  template: `\n    <div data-slot=\"invoice-creator-wizard\" [class]=\"rootClass\">\n      <!-- Top Action Header -->\n      <div class=\"border-border flex flex-col gap-4 border-b pb-5 sm:flex-row sm:items-center sm:justify-between\">\n        <div class=\"space-y-1\">\n          <div class=\"flex items-center gap-3\">\n            <h1 class=\"text-foreground text-xl font-bold tracking-tight sm:text-2xl\">Create New Invoice</h1>\n            <span ui-badge wrap variant=\"outline\" class=\"px-2 py-0.5 font-mono text-xs font-semibold\">\n              {{ invoiceNumber() }}\n            </span>\n            <span ui-badge wrap variant=\"secondary\" class=\"text-xs\">Draft</span>\n          </div>\n          <p class=\"text-muted-foreground text-xs sm:text-sm\">\n            Build itemized invoices with live calculation, instant document preview, and client presets.\n          </p>\n        </div>\n\n        <!-- Action Buttons -->\n        <div class=\"flex flex-wrap items-center gap-2\">\n          <button ui-button variant=\"outline\" size=\"sm\" class=\"gap-1.5 text-xs\" (click)=\"handlePreviewPdf()\">\n            <lucide-icon [img]=\"FileText\" class=\"size-3.5\" />\n            Preview PDF\n          </button>\n          <button ui-button variant=\"outline\" size=\"sm\" class=\"gap-1.5 text-xs\" (click)=\"handleSaveDraft()\">\n            <lucide-icon [img]=\"Save\" class=\"size-3.5\" />\n            Save Draft\n          </button>\n          <button ui-button size=\"sm\" class=\"gap-1.5 text-xs font-medium\" (click)=\"handleSendInvoice()\">\n            <lucide-icon [img]=\"Send\" class=\"size-3.5\" />\n            Send Invoice\n          </button>\n        </div>\n      </div>\n\n      <!-- Notification Toast / Alert Banner -->\n      @if (notification(); as note) {\n        <div\n          [class]=\"\n            cn(\n              'flex flex-wrap items-center justify-between rounded-lg border px-4 py-2.5 text-xs transition-colors sm:text-sm',\n              note.type === 'success'\n                ? 'border-success/30 bg-success/10 text-success'\n                : 'border-primary/30 bg-primary/10 text-primary'\n            )\n          \"\n          role=\"status\"\n        >\n          <div class=\"flex flex-wrap items-center gap-2\">\n            <lucide-icon [img]=\"CheckCircle2\" class=\"size-4 shrink-0\" />\n            <span>{{ note.message }}</span>\n          </div>\n          <button\n            type=\"button\"\n            class=\"min-h-6 text-xs font-semibold underline-offset-2 opacity-80 hover:underline hover:opacity-100\"\n            (click)=\"notification.set(null)\"\n          >\n            Dismiss\n          </button>\n        </div>\n      }\n\n      <!-- 2-Column Invoice Builder Layout -->\n      <div class=\"grid grid-cols-1 items-start gap-8 lg:grid-cols-12\">\n        <!-- Left Column: Form Builder -->\n        <div class=\"space-y-6 lg:col-span-7\">\n          <!-- Section 1: Business & Client Details -->\n          <div ui-card>\n            <div ui-card-header class=\"pb-4\">\n              <div class=\"flex flex-wrap items-center gap-2\">\n                <lucide-icon [img]=\"Building2\" class=\"text-primary size-4\" />\n                <h3 ui-card-title class=\"text-base font-semibold\">Business & Client Details</h3>\n              </div>\n              <p ui-card-description class=\"text-xs\">\n                Configure your issuing entity information and bill-to client contact.\n              </p>\n            </div>\n            <div ui-card-content class=\"space-y-5\">\n              <!-- Issuer Details -->\n              <div class=\"space-y-3\">\n                <div class=\"flex flex-wrap items-center justify-between\">\n                  <span class=\"text-muted-foreground text-xs font-semibold tracking-wider uppercase\"\n                    >From (Issuer)</span\n                  >\n                  <span class=\"text-muted-foreground font-mono text-xs\">ID: {{ invoiceNumber() }}</span>\n                </div>\n                <div class=\"grid gap-3 sm:grid-cols-2\">\n                  <div class=\"space-y-1.5 sm:col-span-2\">\n                    <label for=\"icn-issuer-name\" class=\"text-foreground text-xs font-medium\">\n                      Business / Organization Name\n                    </label>\n                    <ui-input\n                      id=\"icn-issuer-name\"\n                      [value]=\"issuerName()\"\n                      (valueChange)=\"issuerName.set($event)\"\n                      placeholder=\"Business name\"\n                      size=\"small\"\n                    />\n                  </div>\n                  <div class=\"space-y-1.5\">\n                    <label for=\"icn-issuer-email\" class=\"text-foreground text-xs font-medium\">Billing Email</label>\n                    <ui-input\n                      id=\"icn-issuer-email\"\n                      [value]=\"issuerEmail()\"\n                      (valueChange)=\"issuerEmail.set($event)\"\n                      type=\"email\"\n                      placeholder=\"billing@company.com\"\n                      size=\"small\"\n                    />\n                  </div>\n                  <div class=\"space-y-1.5\">\n                    <label for=\"icn-issuer-tax\" class=\"text-foreground text-xs font-medium\"\n                      >Tax ID / VAT Registration</label\n                    >\n                    <ui-input\n                      id=\"icn-issuer-tax\"\n                      [value]=\"issuerTaxId()\"\n                      (valueChange)=\"issuerTaxId.set($event)\"\n                      placeholder=\"Tax ID / EIN\"\n                      size=\"small\"\n                    />\n                  </div>\n                  <div class=\"space-y-1.5 sm:col-span-2\">\n                    <label for=\"icn-issuer-address\" class=\"text-foreground text-xs font-medium\">Business Address</label>\n                    <ui-input\n                      id=\"icn-issuer-address\"\n                      [value]=\"issuerAddress()\"\n                      (valueChange)=\"issuerAddress.set($event)\"\n                      placeholder=\"Street, City, State, ZIP\"\n                      size=\"small\"\n                    />\n                  </div>\n                </div>\n              </div>\n\n              <div ui-separator></div>\n\n              <!-- Client Details -->\n              <div class=\"space-y-3\">\n                <div class=\"flex flex-wrap items-center justify-between\">\n                  <span class=\"text-muted-foreground text-xs font-semibold tracking-wider uppercase\"\n                    >Bill To (Client)</span\n                  >\n                  <div class=\"flex flex-wrap items-center gap-2\">\n                    <span class=\"text-muted-foreground text-xs\">Quick Preset:</span>\n                    <div class=\"w-48\">\n                      <ui-select [value]=\"selectedPreset()\" (valueChange)=\"handlePresetChange($event)\">\n                        <button ui-select-trigger class=\"h-7 text-xs\">\n                          <ui-select-value placeholder=\"Select client\" />\n                        </button>\n                        <ui-select-content>\n                          @for (preset of clientPresets; track preset.id) {\n                            <ui-select-item [value]=\"preset.id\">{{ preset.company }}</ui-select-item>\n                          }\n                          <ui-select-item value=\"custom\">Custom Client</ui-select-item>\n                        </ui-select-content>\n                      </ui-select>\n                    </div>\n                  </div>\n                </div>\n\n                <div class=\"grid gap-3 sm:grid-cols-2\">\n                  <div class=\"space-y-1.5\">\n                    <label for=\"icn-client-name\" class=\"text-foreground text-xs font-medium\">Contact Name</label>\n                    <ui-input\n                      id=\"icn-client-name\"\n                      [value]=\"clientName()\"\n                      (valueChange)=\"clientName.set($event)\"\n                      placeholder=\"Client contact name\"\n                      size=\"small\"\n                    />\n                  </div>\n                  <div class=\"space-y-1.5\">\n                    <label for=\"icn-client-company\" class=\"text-foreground text-xs font-medium\">Company Name</label>\n                    <ui-input\n                      id=\"icn-client-company\"\n                      [value]=\"clientCompany()\"\n                      (valueChange)=\"clientCompany.set($event)\"\n                      placeholder=\"Client company name\"\n                      size=\"small\"\n                    />\n                  </div>\n                  <div class=\"space-y-1.5\">\n                    <label for=\"icn-client-email\" class=\"text-foreground text-xs font-medium\">Client Email</label>\n                    <ui-input\n                      id=\"icn-client-email\"\n                      [value]=\"clientEmail()\"\n                      (valueChange)=\"clientEmail.set($event)\"\n                      type=\"email\"\n                      placeholder=\"client@company.com\"\n                      size=\"small\"\n                    />\n                  </div>\n                  <div class=\"space-y-1.5\">\n                    <label for=\"icn-client-address\" class=\"text-foreground text-xs font-medium\">Client Address</label>\n                    <ui-input\n                      id=\"icn-client-address\"\n                      [value]=\"clientAddress()\"\n                      (valueChange)=\"clientAddress.set($event)\"\n                      placeholder=\"Street, City, Postal Code\"\n                      size=\"small\"\n                    />\n                  </div>\n                </div>\n              </div>\n\n              <div ui-separator></div>\n\n              <!-- Invoice Timing & Currency -->\n              <div class=\"grid gap-3 sm:grid-cols-4\">\n                <div class=\"space-y-1.5\">\n                  <label for=\"icn-invoice-date\" class=\"text-foreground text-xs font-medium\">Invoice Date</label>\n                  <ui-input\n                    id=\"icn-invoice-date\"\n                    [value]=\"invoiceDate()\"\n                    (valueChange)=\"invoiceDate.set($event)\"\n                    type=\"date\"\n                    size=\"small\"\n                  />\n                </div>\n                <div class=\"space-y-1.5\">\n                  <label for=\"icn-due-date\" class=\"text-foreground text-xs font-medium\">Due Date</label>\n                  <ui-input\n                    id=\"icn-due-date\"\n                    [value]=\"dueDate()\"\n                    (valueChange)=\"dueDate.set($event)\"\n                    type=\"date\"\n                    size=\"small\"\n                  />\n                </div>\n                <div class=\"space-y-1.5\">\n                  <label for=\"icn-payment-terms\" class=\"text-foreground text-xs font-medium\">Payment Terms</label>\n                  <ui-select [value]=\"paymentTerms()\" (valueChange)=\"paymentTerms.set($event)\">\n                    <button ui-select-trigger id=\"icn-payment-terms\" class=\"h-8 text-xs\">\n                      <ui-select-value placeholder=\"Terms\" />\n                    </button>\n                    <ui-select-content>\n                      <ui-select-item value=\"receipt\">Due on Receipt</ui-select-item>\n                      <ui-select-item value=\"net15\">Net 15</ui-select-item>\n                      <ui-select-item value=\"net30\">Net 30</ui-select-item>\n                      <ui-select-item value=\"net60\">Net 60</ui-select-item>\n                    </ui-select-content>\n                  </ui-select>\n                </div>\n                <div class=\"space-y-1.5\">\n                  <label for=\"icn-currency\" class=\"text-foreground text-xs font-medium\">Currency</label>\n                  <ui-select [value]=\"currency()\" (valueChange)=\"currency.set($event)\">\n                    <button ui-select-trigger id=\"icn-currency\" class=\"h-8 text-xs\">\n                      <ui-select-value placeholder=\"Currency\" />\n                    </button>\n                    <ui-select-content>\n                      <ui-select-item value=\"USD\">USD ($)</ui-select-item>\n                      <ui-select-item value=\"EUR\">EUR (€)</ui-select-item>\n                      <ui-select-item value=\"GBP\">GBP (£)</ui-select-item>\n                      <ui-select-item value=\"CAD\">CAD ($)</ui-select-item>\n                      <ui-select-item value=\"AUD\">AUD ($)</ui-select-item>\n                    </ui-select-content>\n                  </ui-select>\n                </div>\n              </div>\n            </div>\n          </div>\n\n          <!-- Section 2: Interactive Line Items -->\n          <div ui-card>\n            <div ui-card-header class=\"pb-3\">\n              <div class=\"flex flex-wrap items-center justify-between\">\n                <div class=\"flex flex-wrap items-center gap-2\">\n                  <lucide-icon [img]=\"Receipt\" class=\"text-primary size-4\" />\n                  <h3 ui-card-title class=\"text-base font-semibold\">Line Items</h3>\n                </div>\n                <span ui-badge wrap variant=\"secondary\" class=\"font-mono text-xs tabular-nums\">\n                  {{ items().length }} {{ items().length === 1 ? 'item' : 'items' }}\n                </span>\n              </div>\n              <p ui-card-description class=\"text-xs\">\n                Itemize deliverables, billable hours, software licenses, or custom services.\n              </p>\n            </div>\n            <div ui-card-content class=\"space-y-4\">\n              <div class=\"overflow-x-auto\">\n                <table class=\"w-full text-left text-xs\">\n                  <thead>\n                    <tr class=\"border-border text-muted-foreground border-b\">\n                      <th class=\"pb-2 font-medium\">Description</th>\n                      <th class=\"w-20 pb-2 text-right font-medium\">Qty</th>\n                      <th class=\"w-28 pb-2 text-right font-medium\">Unit Price</th>\n                      <th class=\"w-24 pb-2 text-right font-medium\">Line Total</th>\n                      <th class=\"w-10 pb-2 text-center font-medium\"></th>\n                    </tr>\n                  </thead>\n                  <tbody class=\"divide-border/60 divide-y\">\n                    @for (item of items(); track item.id) {\n                      <tr class=\"group\">\n                        <td class=\"py-2.5 pr-2\">\n                          <ui-input\n                            [value]=\"item.description\"\n                            (valueChange)=\"updateItem(item.id, { description: $event })\"\n                            placeholder=\"Service or product description...\"\n                            size=\"small\"\n                            class=\"w-full\"\n                          />\n                        </td>\n                        <td class=\"px-2 py-2.5\">\n                          <ui-input\n                            [value]=\"item.quantity\"\n                            (valueChange)=\"updateItem(item.id, { quantity: toNumber($event) })\"\n                            type=\"number\"\n                            size=\"small\"\n                            class=\"w-20 text-right tabular-nums\"\n                          />\n                        </td>\n                        <td class=\"px-2 py-2.5\">\n                          <ui-input\n                            [value]=\"item.unitPrice\"\n                            (valueChange)=\"updateItem(item.id, { unitPrice: toNumber($event) })\"\n                            type=\"number\"\n                            size=\"small\"\n                            class=\"w-28 text-right tabular-nums\"\n                          />\n                        </td>\n                        <td class=\"text-foreground py-2.5 pl-2 text-right font-medium whitespace-nowrap tabular-nums\">\n                          {{ formatCurrency((toNum(item.quantity) || 0) * (toNum(item.unitPrice) || 0)) }}\n                        </td>\n                        <td class=\"py-2.5 pl-1 text-center\">\n                          <button\n                            type=\"button\"\n                            ui-button\n                            variant=\"ghost\"\n                            size=\"icon\"\n                            class=\"text-muted-foreground hover:text-destructive size-7 disabled:opacity-30\"\n                            [disabled]=\"items().length <= 1\"\n                            aria-label=\"Remove item\"\n                            (click)=\"removeLineItem(item.id)\"\n                          >\n                            <lucide-icon [img]=\"Trash2\" class=\"size-3.5\" />\n                          </button>\n                        </td>\n                      </tr>\n                    }\n                  </tbody>\n                </table>\n              </div>\n\n              <div class=\"flex flex-wrap items-center justify-between pt-2\">\n                <button\n                  type=\"button\"\n                  ui-button\n                  variant=\"outline\"\n                  size=\"sm\"\n                  class=\"gap-1 text-xs\"\n                  (click)=\"addLineItem()\"\n                >\n                  <lucide-icon [img]=\"Plus\" class=\"size-3.5\" />\n                  Add Line Item\n                </button>\n                <div class=\"text-muted-foreground text-xs\">\n                  Subtotal:\n                  <span class=\"text-foreground font-semibold tabular-nums\">{{ formatCurrency(subtotal()) }}</span>\n                </div>\n              </div>\n            </div>\n          </div>\n\n          <!-- Section 3: Adjustments & Payment Terms -->\n          <div ui-card>\n            <div ui-card-header class=\"pb-3\">\n              <div class=\"flex flex-wrap items-center gap-2\">\n                <lucide-icon [img]=\"Percent\" class=\"text-primary size-4\" />\n                <h3 ui-card-title class=\"text-base font-semibold\">Adjustments & Notes</h3>\n              </div>\n              <p ui-card-description class=\"text-xs\">\n                Itemize tax rates, discount subtractions, and client payment instructions.\n              </p>\n            </div>\n            <div ui-card-content class=\"space-y-4\">\n              <div class=\"grid gap-4 sm:grid-cols-2\">\n                <!-- Tax percentage -->\n                <div class=\"space-y-1.5\">\n                  <div class=\"flex flex-wrap items-center justify-between\">\n                    <label for=\"icn-tax-rate\" class=\"text-foreground text-xs font-medium\">Tax Rate (%)</label>\n                    <span class=\"text-muted-foreground text-xs tabular-nums\">+{{ formatCurrency(taxAmount()) }}</span>\n                  </div>\n                  <ui-input\n                    id=\"icn-tax-rate\"\n                    [value]=\"taxRate()\"\n                    (valueChange)=\"taxRate.set(toNumber($event))\"\n                    type=\"number\"\n                    placeholder=\"8.5\"\n                    size=\"small\"\n                  />\n                </div>\n\n                <!-- Discount -->\n                <div class=\"space-y-1.5\">\n                  <div class=\"flex flex-wrap items-center justify-between\">\n                    <label for=\"icn-discount-val\" class=\"text-foreground text-xs font-medium\">Discount</label>\n                    <div class=\"flex items-center gap-1\">\n                      <button\n                        type=\"button\"\n                        [class]=\"\n                          cn(\n                            'min-h-6 rounded px-1.5 py-0.5 text-xs font-medium transition-colors',\n                            discountType() === 'fixed'\n                              ? 'bg-primary text-primary-foreground'\n                              : 'bg-muted text-muted-foreground hover:text-foreground'\n                          )\n                        \"\n                        (click)=\"discountType.set('fixed')\"\n                      >\n                        Fixed ($)\n                      </button>\n                      <button\n                        type=\"button\"\n                        [class]=\"\n                          cn(\n                            'min-h-6 rounded px-1.5 py-0.5 text-xs font-medium transition-colors',\n                            discountType() === 'percent'\n                              ? 'bg-primary text-primary-foreground'\n                              : 'bg-muted text-muted-foreground hover:text-foreground'\n                          )\n                        \"\n                        (click)=\"discountType.set('percent')\"\n                      >\n                        Percent (%)\n                      </button>\n                    </div>\n                  </div>\n                  <div class=\"flex flex-wrap items-center gap-2\">\n                    <ui-input\n                      id=\"icn-discount-val\"\n                      [value]=\"discountValue()\"\n                      (valueChange)=\"discountValue.set(toNumber($event))\"\n                      type=\"number\"\n                      placeholder=\"0\"\n                      size=\"small\"\n                      class=\"w-full\"\n                    />\n                    <span class=\"text-success text-success text-xs font-medium whitespace-nowrap tabular-nums\">\n                      -{{ formatCurrency(effectiveDiscount()) }}\n                    </span>\n                  </div>\n                </div>\n              </div>\n\n              <!-- Notes / Terms -->\n              <div class=\"space-y-1.5\">\n                <label for=\"icn-notes\" class=\"text-foreground text-xs font-medium\">Notes & Terms for Client</label>\n                <ui-textarea\n                  id=\"icn-notes\"\n                  [value]=\"notes()\"\n                  (valueChange)=\"notes.set($event)\"\n                  [rows]=\"3\"\n                  placeholder=\"Payment instructions, bank wire info, or a personal thank you note...\"\n                  class=\"text-xs\"\n                />\n              </div>\n            </div>\n          </div>\n        </div>\n\n        <!-- Right Column: Live Paper Document Preview -->\n        <div class=\"space-y-4 lg:sticky lg:top-6 lg:col-span-5\">\n          <div class=\"flex flex-wrap items-center justify-between px-1\">\n            <div class=\"flex flex-wrap items-center gap-2\">\n              <span class=\"relative flex size-2\">\n                <span class=\"bg-success absolute inline-flex h-full w-full rounded-full opacity-75\"></span>\n                <span class=\"bg-success relative inline-flex size-2 rounded-full\"></span>\n              </span>\n              <span class=\"text-muted-foreground flex items-center gap-1 text-xs font-medium\">\n                <lucide-icon [img]=\"Eye\" class=\"size-3.5\" />\n                Live Document Preview\n              </span>\n            </div>\n            <span class=\"text-muted-foreground font-mono text-xs\">Printable A4</span>\n          </div>\n\n          <!-- Paper Invoice Card -->\n          <div\n            class=\"bg-card text-card-foreground border-border/80 relative space-y-6 overflow-hidden rounded-xl border p-6 shadow-md transition-colors sm:p-7\"\n          >\n            <!-- Document Header -->\n            <div class=\"flex items-start justify-between gap-4\">\n              <div class=\"space-y-1\">\n                <div class=\"flex flex-wrap items-center gap-2\">\n                  <div\n                    class=\"bg-primary/10 text-primary border-primary/20 flex size-8 items-center justify-center rounded border text-xs font-bold\"\n                  >\n                    AS\n                  </div>\n                  <div class=\"text-foreground text-sm leading-tight font-bold sm:text-base\">\n                    {{ issuerName() || 'Business Name' }}\n                  </div>\n                </div>\n                <p class=\"text-muted-foreground max-w-[200px] text-xs leading-relaxed\">\n                  {{ issuerAddress() || 'Address not set' }}\n                </p>\n                <p class=\"text-muted-foreground font-mono text-xs\">\n                  {{ issuerEmail() || 'billing@domain.com' }}\n                </p>\n                @if (issuerTaxId()) {\n                  <p class=\"text-muted-foreground/80 font-mono text-xs\">Tax: {{ issuerTaxId() }}</p>\n                }\n              </div>\n\n              <div class=\"shrink-0 space-y-1 text-right\">\n                <span class=\"text-muted-foreground text-xs font-bold tracking-wider uppercase\">Invoice</span>\n                <div class=\"text-foreground font-mono text-xs font-bold sm:text-sm\">{{ invoiceNumber() }}</div>\n                <span\n                  ui-badge\n                  wrap\n                  variant=\"outline\"\n                  class=\"border-success/30 bg-success/10 text-success text-xs font-medium\"\n                >\n                  Ready to Send\n                </span>\n              </div>\n            </div>\n\n            <div ui-separator class=\"opacity-60\"></div>\n\n            <!-- Invoice Details: Bill To & Dates -->\n            <div class=\"grid grid-cols-2 gap-4 text-xs\">\n              <div class=\"space-y-1\">\n                <span class=\"text-muted-foreground text-xs font-semibold tracking-wider uppercase\">Billed To</span>\n                <p class=\"text-foreground font-semibold\">{{ clientName() || 'Client Name' }}</p>\n                @if (clientCompany()) {\n                  <p class=\"text-muted-foreground font-medium\">{{ clientCompany() }}</p>\n                }\n                <p class=\"text-muted-foreground leading-relaxed\">{{ clientAddress() || 'No address provided' }}</p>\n                <p class=\"text-muted-foreground font-mono\">{{ clientEmail() || 'client@email.com' }}</p>\n              </div>\n\n              <div class=\"space-y-1 text-right\">\n                <span class=\"text-muted-foreground text-xs font-semibold tracking-wider uppercase\"\n                  >Invoice Details</span\n                >\n                <div class=\"space-y-0.5\">\n                  <div class=\"text-muted-foreground flex justify-between gap-2 sm:justify-end\">\n                    <span>Issued:</span>\n                    <span class=\"text-foreground font-medium tabular-nums\">{{ formatDate(invoiceDate()) }}</span>\n                  </div>\n                  <div class=\"text-muted-foreground flex justify-between gap-2 sm:justify-end\">\n                    <span>Due:</span>\n                    <span class=\"text-foreground font-medium tabular-nums\">{{ formatDate(dueDate()) }}</span>\n                  </div>\n                  <div class=\"text-muted-foreground flex justify-between gap-2 sm:justify-end\">\n                    <span>Terms:</span>\n                    <span class=\"text-foreground font-medium\">{{ termsLabel() }}</span>\n                  </div>\n                </div>\n              </div>\n            </div>\n\n            <div ui-separator class=\"opacity-60\"></div>\n\n            <!-- Line Items Table -->\n            <div class=\"space-y-2\">\n              <div class=\"overflow-x-auto\">\n                <table class=\"w-full text-xs\">\n                  <thead>\n                    <tr class=\"border-border/80 text-muted-foreground border-b font-medium\">\n                      <th class=\"pb-2 text-left\">Item & Description</th>\n                      <th class=\"w-12 pb-2 text-center\">Qty</th>\n                      <th class=\"w-16 pb-2 text-right\">Rate</th>\n                      <th class=\"w-20 pb-2 text-right\">Amount</th>\n                    </tr>\n                  </thead>\n                  <tbody class=\"divide-border/40 divide-y\">\n                    @for (item of items(); track item.id) {\n                      <tr class=\"text-foreground\">\n                        <td class=\"py-2 pr-2\">\n                          <p class=\"leading-snug font-medium\">{{ item.description || 'Custom Deliverable' }}</p>\n                        </td>\n                        <td class=\"text-muted-foreground px-1 py-2 text-center tabular-nums\">{{ item.quantity }}</td>\n                        <td class=\"text-muted-foreground px-1 py-2 text-right tabular-nums\">\n                          {{ formatCurrency(toNum(item.unitPrice) || 0) }}\n                        </td>\n                        <td class=\"py-2 pl-2 text-right font-medium tabular-nums\">\n                          {{ formatCurrency((toNum(item.quantity) || 0) * (toNum(item.unitPrice) || 0)) }}\n                        </td>\n                      </tr>\n                    }\n                  </tbody>\n                </table>\n              </div>\n            </div>\n\n            <div ui-separator class=\"opacity-60\"></div>\n\n            <!-- Calculations Summary -->\n            <div class=\"space-y-2 text-xs\">\n              <div class=\"text-muted-foreground flex justify-between\">\n                <span>Subtotal</span>\n                <span class=\"text-foreground font-medium tabular-nums\">{{ formatCurrency(subtotal()) }}</span>\n              </div>\n\n              @if (effectiveDiscount() > 0) {\n                <div class=\"text-success flex justify-between font-medium\">\n                  <span>\n                    Discount\n                    @if (discountType() === 'percent') {\n                      ({{ discountValue() }}%)\n                    }\n                  </span>\n                  <span class=\"tabular-nums\">-{{ formatCurrency(effectiveDiscount()) }}</span>\n                </div>\n              }\n\n              @if (taxRate() > 0) {\n                <div class=\"text-muted-foreground flex justify-between\">\n                  <span>Tax ({{ taxRate() }}%)</span>\n                  <span class=\"text-foreground font-medium tabular-nums\">+{{ formatCurrency(taxAmount()) }}</span>\n                </div>\n              }\n\n              <div ui-separator class=\"my-1.5 opacity-80\"></div>\n\n              <div class=\"flex flex-wrap items-baseline justify-between gap-x-2 gap-y-0.5 pt-1\">\n                <span class=\"text-foreground text-sm font-bold\">Total Due</span>\n                <span class=\"text-foreground text-lg font-bold tabular-nums\">{{ formatCurrency(totalDue()) }}</span>\n              </div>\n            </div>\n\n            <!-- Notes / Payment Info Callout -->\n            <div class=\"bg-muted/50 border-border/70 space-y-2 rounded-lg border p-3.5 text-xs\">\n              <div class=\"text-foreground flex items-center gap-1.5 font-medium\">\n                <lucide-icon [img]=\"CreditCard\" class=\"text-primary size-3.5\" />\n                <span>Payment Instructions</span>\n              </div>\n              @if (notes()) {\n                <p class=\"text-muted-foreground leading-relaxed\">{{ notes() }}</p>\n              }\n              <div\n                class=\"border-border/50 text-muted-foreground flex flex-wrap items-center justify-between gap-2 border-t pt-1.5 font-mono text-xs\"\n              >\n                <span>ACH / Wire: **** 9104</span>\n                <span>Routing: **** 4892</span>\n              </div>\n            </div>\n          </div>\n        </div>\n      </div>\n    </div>\n  `,\n})\nexport class UiInvoiceCreatorWizardComponent implements OnInit {\n  protected readonly Building2 = Building2\n  protected readonly CheckCircle2 = CheckCircle2\n  protected readonly CreditCard = CreditCard\n  protected readonly Eye = Eye\n  protected readonly FileText = FileText\n  protected readonly Percent = Percent\n  protected readonly Plus = Plus\n  protected readonly Receipt = Receipt\n  protected readonly Save = Save\n  protected readonly Send = Send\n  protected readonly Trash2 = Trash2\n\n  protected readonly clientPresets = CLIENT_PRESETS\n  protected readonly cn = cn\n\n  @Input() initialInvoiceNumber = 'INV-2026-0042'\n  @Input() initialIssuerName = 'Acme Design & Engineering Studio'\n  @Input() initialIssuerEmail = 'billing@acmestudio.io'\n  @Input() initialIssuerAddress = '100 Montgomery St, Suite 1400, San Francisco, CA 94104'\n  @Input() initialIssuerTaxId = 'US-EIN-94-2819034'\n  @Input() initialClientName = 'Sarah Jenkins'\n  @Input() initialClientCompany = 'Apex Digital Inc.'\n  @Input() initialClientEmail = 'sarah.jenkins@apexdigital.com'\n  @Input() initialClientAddress = '742 Evergreen Terrace, Springfield, OR 97477'\n  @Input() initialInvoiceDate = '2026-08-21'\n  @Input() initialDueDate = '2026-09-20'\n  @Input() initialPaymentTerms = 'net30'\n  @Input() initialCurrency = 'USD'\n  @Input() initialItems?: InvoiceLineItem[]\n  @Input() initialTaxRate = 8.5\n  @Input() initialDiscountType: 'fixed' | 'percent' = 'fixed'\n  @Input() initialDiscountValue = 150\n  @Input() initialNotes =\n    'Thank you for your partnership! Please remit payment via wire transfer or online payment link within 30 days. Contact billing@acmestudio.io for any questions.'\n  @Input('class') className?: string\n\n  @Output() readonly saveDraft = new EventEmitter<Record<string, unknown>>()\n  @Output() readonly sendInvoice = new EventEmitter<Record<string, unknown>>()\n  @Output() readonly previewPdf = new EventEmitter<void>()\n\n  readonly invoiceNumber = signal('INV-2026-0042')\n  readonly issuerName = signal('Acme Design & Engineering Studio')\n  readonly issuerEmail = signal('billing@acmestudio.io')\n  readonly issuerAddress = signal('100 Montgomery St, Suite 1400, San Francisco, CA 94104')\n  readonly issuerTaxId = signal('US-EIN-94-2819034')\n\n  readonly selectedPreset = signal('c1')\n  readonly clientName = signal('Sarah Jenkins')\n  readonly clientCompany = signal('Apex Digital Inc.')\n  readonly clientEmail = signal('sarah.jenkins@apexdigital.com')\n  readonly clientAddress = signal('742 Evergreen Terrace, Springfield, OR 97477')\n\n  readonly invoiceDate = signal('2026-08-21')\n  readonly dueDate = signal('2026-09-20')\n  readonly paymentTerms = signal('net30')\n  readonly currency = signal('USD')\n\n  readonly items = signal<InvoiceLineItem[]>(DEFAULT_LINE_ITEMS.map((i) => ({ ...i })))\n\n  readonly taxRate = signal(8.5)\n  readonly discountType = signal<'fixed' | 'percent'>('fixed')\n  readonly discountValue = signal(150)\n  readonly notes = signal(\n    'Thank you for your partnership! Please remit payment via wire transfer or online payment link within 30 days. Contact billing@acmestudio.io for any questions.',\n  )\n\n  readonly notification = signal<{ type: 'success' | 'info'; message: string } | null>(null)\n  private notifTimeout: ReturnType<typeof setTimeout> | null = null\n\n  ngOnInit(): void {\n    this.invoiceNumber.set(this.initialInvoiceNumber)\n    this.issuerName.set(this.initialIssuerName)\n    this.issuerEmail.set(this.initialIssuerEmail)\n    this.issuerAddress.set(this.initialIssuerAddress)\n    this.issuerTaxId.set(this.initialIssuerTaxId)\n    this.clientName.set(this.initialClientName)\n    this.clientCompany.set(this.initialClientCompany)\n    this.clientEmail.set(this.initialClientEmail)\n    this.clientAddress.set(this.initialClientAddress)\n    this.invoiceDate.set(this.initialInvoiceDate)\n    this.dueDate.set(this.initialDueDate)\n    this.paymentTerms.set(this.initialPaymentTerms)\n    this.currency.set(this.initialCurrency)\n    this.items.set(\n      this.initialItems && this.initialItems.length > 0\n        ? this.initialItems.map((i) => ({ ...i }))\n        : DEFAULT_LINE_ITEMS.map((i) => ({ ...i })),\n    )\n    this.taxRate.set(this.initialTaxRate)\n    this.discountType.set(this.initialDiscountType)\n    this.discountValue.set(this.initialDiscountValue)\n    this.notes.set(this.initialNotes)\n  }\n\n  readonly subtotal = computed(() => {\n    return this.items().reduce((acc, item) => {\n      const qty = Number(item.quantity) || 0\n      const price = Number(item.unitPrice) || 0\n      return acc + qty * price\n    }, 0)\n  })\n\n  readonly discountAmount = computed(() => {\n    const val = Number(this.discountValue()) || 0\n    if (this.discountType() === 'percent') return this.subtotal() * (val / 100)\n    return val\n  })\n\n  readonly effectiveDiscount = computed(() => {\n    return Math.min(this.subtotal(), Math.max(0, this.discountAmount()))\n  })\n\n  readonly taxableAmount = computed(() => Math.max(0, this.subtotal() - this.effectiveDiscount()))\n\n  readonly taxAmount = computed(() => {\n    const rate = Number(this.taxRate()) || 0\n    return this.taxableAmount() * (rate / 100)\n  })\n\n  readonly totalDue = computed(() => this.taxableAmount() + this.taxAmount())\n\n  get rootClass(): string {\n    return cn('mx-auto w-full max-w-7xl space-y-6', this.className)\n  }\n\n  toNumber(raw: string): number {\n    return Number(raw) || 0\n  }\n\n  toNum(value: number | string): number {\n    return Number(value) || 0\n  }\n\n  termsLabel(): string {\n    return PAYMENT_TERMS_MAP[this.paymentTerms()] ?? this.paymentTerms()\n  }\n\n  formatCurrency(amount: number, curr: string = this.currency()): string {\n    try {\n      return new Intl.NumberFormat('en-US', {\n        style: 'currency',\n        currency: curr,\n        minimumFractionDigits: 2,\n        maximumFractionDigits: 2,\n      }).format(amount)\n    } catch {\n      const symbols: Record<string, string> = { USD: '$', EUR: '€', GBP: '£', CAD: 'CA$', AUD: 'AU$' }\n      const s = symbols[curr] || '$'\n      return `${s}${amount.toFixed(2)}`\n    }\n  }\n\n  formatDate(dateStr: string): string {\n    if (!dateStr) return '—'\n    try {\n      const [y, m, d] = dateStr.split('-').map(Number)\n      if (!y || !m || !d) return dateStr\n      const date = new Date(y, m - 1, d)\n      return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })\n    } catch {\n      return dateStr\n    }\n  }\n\n  private showNotification(message: string, type: 'success' | 'info' = 'success'): void {\n    if (this.notifTimeout) clearTimeout(this.notifTimeout)\n    this.notification.set({ message, type })\n    this.notifTimeout = setTimeout(() => this.notification.set(null), 4000)\n  }\n\n  handlePresetChange(presetId: string): void {\n    const id = String(presetId)\n    this.selectedPreset.set(id)\n    if (id === 'custom') return\n    const preset = CLIENT_PRESETS.find((c) => c.id === id)\n    if (preset) {\n      this.clientName.set(preset.name)\n      this.clientCompany.set(preset.company)\n      this.clientEmail.set(preset.email)\n      this.clientAddress.set(preset.address)\n    }\n  }\n\n  addLineItem(): void {\n    const newId = `item-${Date.now()}`\n    this.items.update((prev) => [...prev, { id: newId, description: '', quantity: 1, unitPrice: 0 }])\n  }\n\n  removeLineItem(id: string): void {\n    if (this.items().length > 1) this.items.update((prev) => prev.filter((i) => i.id !== id))\n  }\n\n  updateItem(id: string, patch: Partial<InvoiceLineItem>): void {\n    this.items.update((prev) => prev.map((i) => (i.id === id ? { ...i, ...patch } : i)))\n  }\n\n  getPayload(): Record<string, unknown> {\n    return {\n      invoiceNumber: this.invoiceNumber(),\n      issuer: {\n        name: this.issuerName(),\n        email: this.issuerEmail(),\n        address: this.issuerAddress(),\n        taxId: this.issuerTaxId(),\n      },\n      client: {\n        name: this.clientName(),\n        company: this.clientCompany(),\n        email: this.clientEmail(),\n        address: this.clientAddress(),\n      },\n      dates: {\n        issued: this.invoiceDate(),\n        due: this.dueDate(),\n        terms: this.paymentTerms(),\n      },\n      currency: this.currency(),\n      items: this.items(),\n      calculations: {\n        subtotal: this.subtotal(),\n        discount: this.effectiveDiscount(),\n        tax: this.taxAmount(),\n        total: this.totalDue(),\n      },\n      notes: this.notes(),\n    }\n  }\n\n  handleSaveDraft(): void {\n    this.saveDraft.emit(this.getPayload())\n    this.showNotification(`Draft invoice ${this.invoiceNumber()} saved successfully.`, 'info')\n  }\n\n  handleSendInvoice(): void {\n    this.sendInvoice.emit(this.getPayload())\n    this.showNotification(`Invoice ${this.invoiceNumber()} sent to ${this.clientEmail() || 'client'}.`, 'success')\n  }\n\n  handlePreviewPdf(): void {\n    this.previewPdf.emit()\n    this.showNotification(`Generating printable PDF preview for ${this.invoiceNumber()}...`, 'info')\n  }\n}\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/invoice-creator-wizard/invoice-creator-wizard.component.ts"
    },
    {
      "path": "packages/registry-angular/blocks/invoice-creator-wizard/index.ts",
      "content": "export {\n  UiInvoiceCreatorWizardComponent,\n  type ClientPreset,\n  type InvoiceLineItem,\n} from './invoice-creator-wizard.component'\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/invoice-creator-wizard/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/input.json",
    "https://uipkge.dev/r/angular/select.json",
    "https://uipkge.dev/r/angular/separator.json",
    "https://uipkge.dev/r/angular/textarea.json"
  ],
  "description": "Square/Stripe-style interactive invoice builder with itemized tax, discount calculation, dynamic line items, client presets, and a real-time paper document preview.",
  "categories": [
    "finance",
    "app",
    "billing",
    "form"
  ]
}