{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "conversion-funnel",
  "title": "Conversion Funnel",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-angular/blocks/conversion-funnel/conversion-funnel.component.ts",
      "content": "/**\n * Conversion funnel: SmoothFunnel chart with count strip above and\n * stage-name + retention-from-previous strip below.\n *\n * Works for any drop-off flow with 3-6 stages: hiring (applied ->\n * hired), e-commerce (sessions -> purchases), onboarding (signed up\n * -> activated), etc. Reads as a single horizontal \"flow\":\n *\n *   72K        38.2K       16.8K       5.6K\n *   ╔══════╗╔════════╗╔══════════╗╔══════════╗\n *   ║ 100% ║║  53%   ║║   23%    ║║    8%    ║\n *   ╚══════╝╚════════╝╚══════════╝╚══════════╝\n *   Views      Cart        Checkout    Purchase\n *              -> 53%       -> 44%      -> 33%\n *\n * The middle pill (inside each band) shows the share OF THE TOP\n * stage (100%, 53%, 23%, ...). The bottom retention number shows the\n * stage-to-stage conversion -- usually the more actionable signal.\n */\nimport { Component, Input, ChangeDetectionStrategy } from '@angular/core'\nimport { cn } from '@/lib/utils'\nimport { UiSmoothFunnelComponent } from '@/ui/charts/smooth-funnel/smooth-funnel.component'\n\nexport interface ConversionFunnelStage {\n  name: string\n  value: number\n}\n\nconst DEFAULT_PALETTE = [\n  'var(--chart-1)',\n  'var(--chart-2)',\n  'var(--chart-3)',\n  'var(--chart-4)',\n  'var(--chart-5)',\n  'var(--chart-1)',\n]\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.Eager,\n  selector: 'ui-conversion-funnel, [ui-conversion-funnel]',\n  standalone: true,\n  imports: [UiSmoothFunnelComponent],\n  host: {\n    'data-uipkge': '',\n    'data-slot': 'conversion-funnel',\n    '[class]': 'hostClass',\n  },\n  template: `\n    <!-- Top: per-stage count -->\n    <div class=\"grid px-2 text-center\" [style.grid-template-columns]=\"gridColumns\">\n      @for (stage of data; track 'top-' + stage.name) {\n        <div class=\"text-foreground text-base font-bold tabular-nums\">{{ fmt(stage.value) }}</div>\n      }\n    </div>\n\n    <!-- Funnel SVG -->\n    <ui-smooth-funnel [data]=\"data\" [height]=\"height\" [colors]=\"palette\" />\n\n    <!-- Bottom: stage name + retention from previous -->\n    <div class=\"grid px-2 text-center\" [style.grid-template-columns]=\"gridColumns\">\n      @for (stage of data; track 'bot-' + stage.name; let i = $index) {\n        <div class=\"space-y-0.5\">\n          <p class=\"text-muted-foreground text-xs\">{{ stage.name }}</p>\n          @if (!hideRetention && retention(i) !== null) {\n            <p class=\"text-info text-xs font-semibold tabular-nums\">→ {{ retention(i) }}% retained</p>\n          }\n        </div>\n      }\n    </div>\n  `,\n})\nexport class UiConversionFunnelComponent {\n  @Input() data: ConversionFunnelStage[] = []\n  /** SmoothFunnel container height. Defaults to 180. */\n  @Input() height: number | string = 180\n  /** Override colour palette. Defaults to the registry's chart-1..N\n   *  OKLCH tokens via CSS variables (so light/dark + theme-customizer\n   *  flips ripple through without any JS). Pass a literal hex array to\n   *  override. */\n  @Input() colors?: string[]\n  /** Compact number formatter for the count strip (default toLocaleString). */\n  @Input() format?: (n: number) => string\n  /** Hide the retention-from-previous footer on each non-first stage. */\n  @Input() hideRetention = false\n  @Input('class') className?: string\n\n  get hostClass(): string {\n    return cn('block space-y-2', this.className)\n  }\n\n  get palette(): string[] {\n    return this.colors ?? DEFAULT_PALETTE\n  }\n\n  get gridColumns(): string {\n    return `repeat(${this.data.length}, minmax(0, 1fr))`\n  }\n\n  fmt(v: number): string {\n    return this.format ? this.format(v) : v.toLocaleString()\n  }\n\n  retention(i: number): number | null {\n    if (i === 0) return null\n    const prev = this.data[i - 1]?.value ?? 1\n    return Math.round((this.data[i]!.value / prev) * 100)\n  }\n}\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/conversion-funnel/conversion-funnel.component.ts"
    },
    {
      "path": "packages/registry-angular/blocks/conversion-funnel/index.ts",
      "content": "export { UiConversionFunnelComponent, type ConversionFunnelStage } from './conversion-funnel.component'\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/conversion-funnel/index.ts"
    }
  ],
  "dependencies": [],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/angular/smooth-funnel.json"
  ],
  "description": "Horizontal conversion funnel with count strip above the SmoothFunnel chart and a stage-name + retention-from-previous footer below. Works for hiring (applied → hired), e-commerce (sessions → purchases), onboarding (signed up → activated). 3-6 stages. Theme-aware via OKLCH chart tokens.",
  "categories": [
    "analytics",
    "dashboard"
  ]
}