{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "auth-mfa",
  "title": "Auth Mfa",
  "type": "registry:page",
  "files": [
    {
      "path": "packages/registry-svelte/blocks/auth-mfa/AuthMfa.svelte",
      "content": "<script lang=\"ts\" module>\n  export interface AuthMfaProps {\n    title?: string\n    description?: string\n    continueHref?: string\n    recoveryHref?: string\n    /** Value the built-in mock validator accepts. */\n    demoCode?: string\n    onVerify?: (code: string) => void\n    onResend?: () => void\n    onContinue?: () => void\n  }\n</script>\n\n<script lang=\"ts\">\n  import { ShieldCheck, RotateCw } from '@lucide/svelte'\n  import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '$lib/components/ui/card'\n  import { Button } from '$lib/components/ui/button'\n  import { PinInput, PinInputGroup, PinInputSlot } from '$lib/components/ui/pin-input'\n\n  let {\n    title = 'Two-step verification',\n    description = 'Enter the 6-digit code from your authenticator app.',\n    continueHref = '/',\n    recoveryHref = '#',\n    demoCode = '123456',\n    onVerify,\n    onResend,\n    onContinue,\n  }: AuthMfaProps = $props()\n\n  let code = $state<string[]>([])\n  let verifying = $state(false)\n  let verified = $state(false)\n  let error = $state('')\n  let resendIn = $state(0)\n\n  $effect(() => {\n    const val = code.join('')\n    if (val.length === 6 && !verifying && !verified) {\n      error = ''\n      verifying = true\n      onVerify?.(val)\n      setTimeout(() => {\n        verifying = false\n        if (val === demoCode) verified = true\n        else {\n          error = `Invalid code. Try ${demoCode} for the demo.`\n          code = []\n        }\n      }, 700)\n    }\n  })\n\n  function startResendCooldown() {\n    resendIn = 30\n    onResend?.()\n    const t = setInterval(() => {\n      resendIn -= 1\n      if (resendIn <= 0) clearInterval(t)\n    }, 1000)\n  }\n</script>\n\n<div data-slot=\"auth-mfa\" class=\"bg-background flex min-h-svh items-center justify-center p-6\">\n  <Card class=\"w-full max-w-sm\">\n    {#if !verified}\n      <CardHeader class=\"text-center\">\n        <div class=\"bg-primary/10 text-primary mx-auto mb-2 flex size-12 items-center justify-center rounded-full\">\n          <ShieldCheck class=\"size-6\" />\n        </div>\n        <CardTitle class=\"text-2xl\">{title}</CardTitle>\n        <CardDescription>{description}</CardDescription>\n      </CardHeader>\n      <CardContent class=\"space-y-4\">\n        <div class=\"flex justify-center\">\n          <PinInput bind:value={code} otp disabled={verifying}>\n            <PinInputGroup>\n              {#each Array.from({ length: 6 }, (_, i) => i) as i (i)}\n                <PinInputSlot index={i} />\n              {/each}\n            </PinInputGroup>\n          </PinInput>\n        </div>\n        {#if verifying}\n          <p class=\"text-muted-foreground text-center text-sm\">Verifying…</p>\n        {/if}\n        {#if error}\n          <p class=\"text-destructive text-center text-sm\">{error}</p>\n        {/if}\n        <div class=\"text-center\">\n          {#if resendIn === 0}\n            <button\n              type=\"button\"\n              class=\"text-muted-foreground hover:text-foreground inline-flex items-center gap-1 text-xs underline-offset-4 hover:underline\"\n              onclick={startResendCooldown}\n            >\n              <RotateCw class=\"size-3\" />Resend code\n            </button>\n          {:else}\n            <p class=\"text-muted-foreground text-xs\">Resend available in {resendIn}s</p>\n          {/if}\n        </div>\n      </CardContent>\n      <CardFooter class=\"justify-center\">\n        <p class=\"text-muted-foreground text-xs\">\n          Lost your device?\n          <a href={recoveryHref} class=\"text-foreground underline-offset-4 hover:underline\">Use a recovery code</a>\n        </p>\n      </CardFooter>\n    {:else}\n      <CardContent class=\"space-y-4 pt-6 text-center\">\n        <div class=\"bg-success/10 text-success mx-auto flex size-12 items-center justify-center rounded-full\">\n          <ShieldCheck class=\"size-6\" />\n        </div>\n        <div class=\"space-y-1\">\n          <h3 class=\"text-lg font-semibold\">Verified</h3>\n          <p class=\"text-muted-foreground text-sm\">You're all set. Continuing to your dashboard…</p>\n        </div>\n        <a href={continueHref} onclick={() => onContinue?.()}><Button class=\"w-full\">Continue</Button></a>\n      </CardContent>\n    {/if}\n  </Card>\n</div>\n",
      "type": "registry:page",
      "target": "~/src/lib/components/blocks/auth-mfa/AuthMfa.svelte"
    }
  ],
  "dependencies": [
    "@lucide/svelte"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/svelte/card.json",
    "https://uipkge.dev/r/svelte/button.json",
    "https://uipkge.dev/r/svelte/pin-input.json"
  ],
  "description": "Two-step verification surface. 6-digit OTP pin input auto-submits on entry, shows verifying state and an inline error on mismatch, has a 30-second resend cooldown, and swaps to a Verified card with a Continue button on success. `onVerify` (code), `onResend`, and `onContinue` callbacks. `demoCode` prop controls the value the built-in mock validator accepts.",
  "categories": [
    "auth"
  ]
}