{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "auth-mfa",
  "title": "Auth Mfa",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-react/blocks/auth-mfa/AuthMfa.tsx",
      "content": "'use client'\n\nimport * as React from 'react'\nimport { ShieldCheck, RotateCw } from 'lucide-react'\nimport { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card'\nimport { Button } from '@/components/ui/button'\nimport { PinInput, PinInputGroup, PinInputSlot } from '@/components/ui/pin-input'\n\nexport interface AuthMfaProps {\n  title?: string\n  description?: string\n  continueHref?: string\n  recoveryHref?: string\n  demoCode?: string\n  onVerify?: (code: string) => void\n  onResend?: () => void\n  onContinue?: () => void\n}\n\nexport function AuthMfa({\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) {\n  const [code, setCode] = React.useState('')\n  const [verifying, setVerifying] = React.useState(false)\n  const [verified, setVerified] = React.useState(false)\n  const [error, setError] = React.useState('')\n  const [resendIn, setResendIn] = React.useState(0)\n\n  React.useEffect(() => {\n    if (code.length === 6) {\n      setError('')\n      setVerifying(true)\n      onVerify?.(code)\n      const timer = setTimeout(() => {\n        setVerifying(false)\n        if (code === demoCode) setVerified(true)\n        else {\n          setError(`Invalid code. Try ${demoCode} for the demo.`)\n          setCode('')\n        }\n      }, 700)\n      return () => clearTimeout(timer)\n    }\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, [code])\n\n  function startResendCooldown() {\n    setResendIn(30)\n    onResend?.()\n    const t = setInterval(() => {\n      setResendIn((prev) => {\n        if (prev <= 1) {\n          clearInterval(t)\n          return 0\n        }\n        return prev - 1\n      })\n    }, 1000)\n  }\n\n  return (\n    <div className=\"bg-background flex min-h-svh items-center justify-center p-6\">\n      <Card className=\"w-full max-w-sm\">\n        {!verified ? (\n          <>\n            <CardHeader className=\"text-center\">\n              <div className=\"bg-primary/10 text-primary mx-auto mb-2 flex size-12 items-center justify-center rounded-full\">\n                <ShieldCheck className=\"size-6\" />\n              </div>\n              <CardTitle className=\"text-2xl\">{title}</CardTitle>\n              <CardDescription>{description}</CardDescription>\n            </CardHeader>\n            <CardContent className=\"space-y-4\">\n              <div className=\"flex justify-center\">\n                <PinInput value={code} onChange={setCode} disabled={verifying}>\n                  <PinInputGroup>\n                    {Array.from({ length: 6 }).map((_, i) => (\n                      <PinInputSlot key={i} index={i} />\n                    ))}\n                  </PinInputGroup>\n                </PinInput>\n              </div>\n              {verifying && <p className=\"text-muted-foreground text-center text-sm\">Verifying…</p>}\n              {error && <p className=\"text-destructive text-center text-sm\">{error}</p>}\n              <div className=\"text-center\">\n                {resendIn === 0 ? (\n                  <button\n                    type=\"button\"\n                    className=\"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 className=\"size-3\" />Resend code\n                  </button>\n                ) : (\n                  <p className=\"text-muted-foreground text-xs\">Resend available in {resendIn}s</p>\n                )}\n              </div>\n            </CardContent>\n            <CardFooter className=\"justify-center\">\n              <p className=\"text-muted-foreground text-xs\">\n                Lost your device?{' '}\n                <a href={recoveryHref} className=\"text-foreground underline-offset-4 hover:underline\">\n                  Use a recovery code\n                </a>\n              </p>\n            </CardFooter>\n          </>\n        ) : (\n          <CardContent className=\"space-y-4 pt-6 text-center\">\n            <div className=\"bg-success/10 text-success mx-auto flex size-12 items-center justify-center rounded-full\">\n              <ShieldCheck className=\"size-6\" />\n            </div>\n            <div className=\"space-y-1\">\n              <h3 className=\"text-lg font-semibold\">Verified</h3>\n              <p className=\"text-muted-foreground text-sm\">You're all set. Continuing to your dashboard…</p>\n            </div>\n            <a href={continueHref} onClick={() => onContinue?.()}>\n              <Button className=\"w-full\">Continue</Button>\n            </a>\n          </CardContent>\n        )}\n      </Card>\n    </div>\n  )\n}\n",
      "type": "registry:block",
      "target": "~/components/blocks/AuthMfa.tsx"
    }
  ],
  "dependencies": [
    "lucide-react"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/react/card.json",
    "https://uipkge.dev/r/react/button.json",
    "https://uipkge.dev/r/react/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. Emits `verify` (code), `resend`, and `continue`. `demoCode` prop controls the value the built-in mock validator accepts.",
  "categories": [
    "auth"
  ]
}