{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "typed-wizard",
  "type": "registry:component",
  "title": "Typed Wizard",
  "description": "An exhaustive stepper.match() over every step id — add or remove a step and the match becomes a compile error until you handle it.",
  "author": "Stepperize",
  "dependencies": [
    "@stepperize/react"
  ],
  "registryDependencies": [],
  "categories": [
    "flow-control"
  ],
  "meta": {
    "capabilities": [
      "type-safe"
    ],
    "level": "advanced",
    "tags": [
      "type-safe",
      "match",
      "exhaustive",
      "typescript"
    ]
  },
  "files": [
    {
      "path": "components/stepperize/typed-wizard.tsx",
      "type": "registry:component",
      "target": "components/stepperize/typed-wizard.tsx",
      "content": "\"use client\";\n\nimport { defineStepper } from \"@stepperize/react\";\nimport { useState } from \"react\";\n\nconst { Stepper } = defineStepper([\n\t{ id: \"plan\", title: \"Plan\", price: 0 },\n\t{ id: \"payment\", title: \"Payment\", price: 29 },\n\t{ id: \"confirm\", title: \"Confirm\", price: 29 },\n]);\n\nexport function TypedWizardBlock() {\n\tconst [subscribed, setSubscribed] = useState(false);\n\n\treturn (\n\t\t<Stepper.Root\n\t\t\tlinear\n\t\t\tclassName=\"w-full max-w-md rounded-xl border bg-background p-6 shadow-sm\"\n\t\t>\n\t\t\t{({ stepper }) => (\n\t\t\t\t<>\n\t\t\t\t\t<Stepper.List className=\"mb-5 flex gap-2\">\n\t\t\t\t\t\t<Stepper.Items>\n\t\t\t\t\t\t\t{(step) => (\n\t\t\t\t\t\t\t\t<Stepper.Item key={step.id} step={step.id} className=\"flex-1\">\n\t\t\t\t\t\t\t\t\t<Stepper.Indicator className=\"h-1.5 w-full rounded-full bg-muted transition-colors data-[status=active]:bg-primary data-[status=previous]:bg-primary\" />\n\t\t\t\t\t\t\t\t</Stepper.Item>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</Stepper.Items>\n\t\t\t\t\t</Stepper.List>\n\n\t\t\t\t\t{/*\n            Exhaustive rendering: `stepper.match` requires a handler for EVERY\n            step id. Add a step above and this object is a compile error until\n            you handle it — the type system guarantees no screen is forgotten.\n            Each handler also receives the fully-typed step (note `step.price`).\n          */}\n\t\t\t\t\t<div className=\"min-h-24 rounded-lg border bg-muted/30 p-4 text-sm\">\n\t\t\t\t\t\t{subscribed ? (\n\t\t\t\t\t\t\t<div className=\"text-center\">\n\t\t\t\t\t\t\t\t<p className=\"font-medium\">Subscription active</p>\n\t\t\t\t\t\t\t\t<p className=\"mt-1 text-muted-foreground\">\n\t\t\t\t\t\t\t\t\tThe $29/mo plan is confirmed and ready to use.\n\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t</div>\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\tstepper.match({\n\t\t\t\t\t\t\t\tplan: (step) => (\n\t\t\t\t\t\t\t\t\t<p>\n\t\t\t\t\t\t\t\t\t\tChoose a plan. Selected tier costs{\" \"}\n\t\t\t\t\t\t\t\t\t\t<span className=\"font-medium\">${step.price}/mo</span>.\n\t\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\tpayment: (step) => (\n\t\t\t\t\t\t\t\t\t<p>\n\t\t\t\t\t\t\t\t\t\tEnter payment details for the{\" \"}\n\t\t\t\t\t\t\t\t\t\t<span className=\"font-medium\">${step.price}/mo</span> plan.\n\t\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t\tconfirm: (step) => (\n\t\t\t\t\t\t\t\t\t<p>\n\t\t\t\t\t\t\t\t\t\tConfirm your subscription:{\" \"}\n\t\t\t\t\t\t\t\t\t\t<span className=\"font-medium\">${step.price}/mo</span>,\n\t\t\t\t\t\t\t\t\t\tbilled monthly.\n\t\t\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t)}\n\t\t\t\t\t</div>\n\n\t\t\t\t\t<Stepper.Actions className=\"mt-5 flex gap-2\">\n\t\t\t\t\t\t<Stepper.Prev className=\"inline-flex h-9 items-center rounded-lg border bg-background px-4 text-sm font-medium transition-colors hover:bg-muted disabled:pointer-events-none disabled:opacity-50\">\n\t\t\t\t\t\t\tBack\n\t\t\t\t\t\t</Stepper.Prev>\n\t\t\t\t\t\t{subscribed ? (\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tonClick={() => {\n\t\t\t\t\t\t\t\t\tsetSubscribed(false);\n\t\t\t\t\t\t\t\t\tstepper.reset();\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\tclassName=\"inline-flex h-9 flex-1 items-center justify-center rounded-lg bg-primary px-4 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\tRestart flow\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t) : stepper.isLast ? (\n\t\t\t\t\t\t\t<button\n\t\t\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\t\t\tonClick={() => setSubscribed(true)}\n\t\t\t\t\t\t\t\tclassName=\"inline-flex h-9 flex-1 items-center justify-center rounded-lg bg-primary px-4 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\tSubscribe\n\t\t\t\t\t\t\t</button>\n\t\t\t\t\t\t) : (\n\t\t\t\t\t\t\t<Stepper.Next className=\"inline-flex h-9 flex-1 items-center justify-center rounded-lg bg-primary px-4 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90 disabled:pointer-events-none disabled:opacity-50\">\n\t\t\t\t\t\t\t\tContinue\n\t\t\t\t\t\t\t</Stepper.Next>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</Stepper.Actions>\n\t\t\t\t</>\n\t\t\t)}\n\t\t</Stepper.Root>\n\t);\n}\n\nexport default TypedWizardBlock;\n"
    }
  ]
}
