{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "two-factor",
  "type": "registry:component",
  "title": "Two-Factor Setup",
  "description": "Pick a method, verify a code, save backup codes.",
  "author": "Stepperize",
  "dependencies": [
    "@stepperize/react",
    "lucide-react"
  ],
  "registryDependencies": [
    "button",
    "input-otp",
    "label",
    "radio-group"
  ],
  "categories": [
    "auth"
  ],
  "meta": {
    "capabilities": [
      "validation"
    ],
    "level": "intermediate",
    "tags": [
      "2fa",
      "mfa",
      "otp",
      "security",
      "verification"
    ]
  },
  "files": [
    {
      "path": "components/stepperize/two-factor.tsx",
      "type": "registry:component",
      "target": "components/stepperize/two-factor.tsx",
      "content": "\"use client\";\n\nimport { defineStepper } from \"@stepperize/react\";\nimport { ShieldCheck, Smartphone } from \"lucide-react\";\nimport { useState } from \"react\";\nimport { buttonVariants } from \"@/components/ui/button\";\nimport {\n  InputOTP,\n  InputOTPGroup,\n  InputOTPSlot,\n} from \"@/components/ui/input-otp\";\nimport { Label } from \"@/components/ui/label\";\nimport { RadioGroup, RadioGroupItem } from \"@/components/ui/radio-group\";\n\nconst { Stepper } = defineStepper([\n  { id: \"method\", title: \"Choose a method\" },\n  { id: \"verify\", title: \"Enter the code\" },\n  { id: \"backup\", title: \"Save backup codes\" },\n]);\n\nexport function TwoFactorBlock() {\n  const [enabled, setEnabled] = useState(false);\n\n  return (\n    <Stepper.Root\n      linear\n      className=\"w-full max-w-sm rounded-xl border bg-background p-6 shadow-sm\"\n    >\n      {({ stepper }) => (\n        <>\n          <div className=\"mb-4 flex items-center justify-between\">\n            <span className=\"grid size-9 place-items-center rounded-lg bg-primary/10 text-primary\">\n              <ShieldCheck className=\"size-5\" />\n            </span>\n            <Stepper.List className=\"flex gap-1.5\">\n              <Stepper.Items>\n                {(step) => (\n                  <Stepper.Item key={step.id} step={step.id}>\n                    <Stepper.Indicator className=\"block h-1.5 w-6 rounded-full transition-colors data-[status=active]:bg-primary data-[status=previous]:bg-primary data-[status=upcoming]:bg-muted\" />\n                  </Stepper.Item>\n                )}\n              </Stepper.Items>\n            </Stepper.List>\n          </div>\n\n          <h3 className=\"text-base font-semibold\">{stepper.current.title}</h3>\n\n          <div className=\"mt-4 min-h-32\">\n            <Stepper.Content step=\"method\">\n              <RadioGroup defaultValue=\"app\">\n                <Method\n                  value=\"app\"\n                  icon={Smartphone}\n                  label=\"Authenticator app\"\n                  hint=\"Recommended\"\n                />\n                <Method\n                  value=\"sms\"\n                  icon={ShieldCheck}\n                  label=\"Text message\"\n                  hint=\"SMS code\"\n                />\n              </RadioGroup>\n            </Stepper.Content>\n\n            <Stepper.Content step=\"verify\" className=\"space-y-3\">\n              <p className=\"text-sm text-muted-foreground\">\n                Enter the 6-digit code from your app.\n              </p>\n              <InputOTP maxLength={6}>\n                <InputOTPGroup className=\"w-full justify-between\">\n                  {[0, 1, 2, 3, 4, 5].map((i) => (\n                    <InputOTPSlot\n                      key={i}\n                      index={i}\n                      className=\"size-11 text-lg\"\n                    />\n                  ))}\n                </InputOTPGroup>\n              </InputOTP>\n            </Stepper.Content>\n\n            <Stepper.Content step=\"backup\" className=\"space-y-3\">\n              <p className=\"text-sm text-muted-foreground\">\n                {enabled\n                  ? \"Two-factor authentication is enabled.\"\n                  : \"Store these somewhere safe.\"}\n              </p>\n              <div className=\"grid grid-cols-2 gap-2 rounded-lg border bg-muted/30 p-3 font-mono text-sm\">\n                {[\"9F2A-7C1B\", \"4E8D-22A9\", \"B0C3-9911\", \"77AF-DE02\"].map(\n                  (code) => (\n                    <span key={code}>{code}</span>\n                  ),\n                )}\n              </div>\n            </Stepper.Content>\n          </div>\n\n          <Stepper.Actions className=\"mt-6 flex justify-between\">\n            <Stepper.Prev className={buttonVariants({ variant: \"outline\" })}>\n              Back\n            </Stepper.Prev>\n            {enabled ? (\n              <button\n                type=\"button\"\n                onClick={() => {\n                  setEnabled(false);\n                  stepper.reset();\n                }}\n                className={buttonVariants()}\n              >\n                Start over\n              </button>\n            ) : stepper.isLast ? (\n              <button\n                type=\"button\"\n                onClick={() => setEnabled(true)}\n                className={buttonVariants()}\n              >\n                Enable 2FA\n              </button>\n            ) : (\n              <Stepper.Next className={buttonVariants()}>Continue</Stepper.Next>\n            )}\n          </Stepper.Actions>\n        </>\n      )}\n    </Stepper.Root>\n  );\n}\n\nfunction Method({\n  value,\n  icon: Icon,\n  label,\n  hint,\n}: {\n  value: string;\n  icon: React.ComponentType<{ className?: string }>;\n  label: string;\n  hint: string;\n}) {\n  return (\n    <Label className=\"flex cursor-pointer items-center gap-3 rounded-lg border p-3 text-sm font-normal transition-colors has-data-checked:border-primary has-data-checked:bg-primary/5\">\n      <RadioGroupItem value={value} />\n      <Icon className=\"size-5 text-muted-foreground\" />\n      <span className=\"font-medium\">{label}</span>\n      <span className=\"ml-auto text-xs text-muted-foreground\">{hint}</span>\n    </Label>\n  );\n}\n\nexport default TwoFactorBlock;\n"
    }
  ]
}
