{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "otp-code",
  "type": "registry:ui",
  "title": "OTP Code Dialog",
  "description": "A responsive OTP verification dialog with input validation - drawer on mobile, modal on desktop.",
  "dependencies": [
    "input-otp"
  ],
  "registryDependencies": [
    "button",
    "https://revola.sameerjs.com/r/revola.json"
  ],
  "files": [
    {
      "path": "registry/revola/examples/origin-ui/forms/authentication/otp-code.tsx",
      "content": "\"use client\";\n\nimport { useEffect, useRef, useState, type FormEvent } from \"react\";\nimport { OTPInput, type SlotProps } from \"input-otp\";\n\nimport { Button } from \"@/components/ui/button\";\nimport {\n  ResponsiveDialog,\n  ResponsiveDialogClose,\n  ResponsiveDialogContent,\n  ResponsiveDialogDescription,\n  ResponsiveDialogHeader,\n  ResponsiveDialogTitle,\n  ResponsiveDialogTrigger,\n} from \"@/components/ui/revola\";\nimport { cn } from \"@/lib/utils\";\n\nconst CORRECT_CODE = \"6996\";\n\nexport default function OtpCodeDialog() {\n  const [value, setValue] = useState(\"\");\n  const [hasGuessed, setHasGuessed] = useState<undefined | boolean>(undefined);\n  const inputRef = useRef<HTMLInputElement>(null);\n  const closeButtonRef = useRef<HTMLButtonElement>(null);\n\n  useEffect(() => {\n    if (hasGuessed) {\n      closeButtonRef.current?.focus();\n    }\n  }, [hasGuessed]);\n\n  async function onSubmit(e?: FormEvent<HTMLFormElement>) {\n    e?.preventDefault?.();\n\n    inputRef.current?.select();\n    await new Promise((r) => setTimeout(r, 1_00));\n\n    setHasGuessed(value === CORRECT_CODE);\n\n    setValue(\"\");\n    setTimeout(() => {\n      inputRef.current?.blur();\n    }, 20);\n  }\n\n  return (\n    <ResponsiveDialog>\n      <ResponsiveDialogTrigger asChild>\n        <Button variant=\"outline\" className=\"h-12 rounded-full px-6 capitalize\">\n          Verify OTP\n        </Button>\n      </ResponsiveDialogTrigger>\n      <ResponsiveDialogContent className=\"mx-auto sm:max-w-[400px]\">\n        <div className=\"space-y-4 p-4 pb-6 sm:p-6\">\n          <div className=\"flex flex-col items-center gap-2\">\n            <div className=\"flex size-11 shrink-0 items-center justify-center rounded-full border\" aria-hidden=\"true\">\n              <svg\n                className=\"stroke-zinc-800 dark:stroke-zinc-100\"\n                xmlns=\"http://www.w3.org/2000/svg\"\n                width=\"20\"\n                height=\"20\"\n                viewBox=\"0 0 32 32\"\n                aria-hidden=\"true\"\n              >\n                <circle cx=\"16\" cy=\"16\" r=\"12\" fill=\"none\" strokeWidth=\"8\" />\n              </svg>\n            </div>\n            <ResponsiveDialogHeader className=\"sm:text-center\">\n              <ResponsiveDialogTitle>{hasGuessed ? \"Code verified!\" : \"Enter confirmation code\"}</ResponsiveDialogTitle>\n              <ResponsiveDialogDescription className=\"text-balance\">\n                {hasGuessed\n                  ? \"Your code has been successfully verified.\"\n                  : `Check your email and enter the code - Try ${CORRECT_CODE}`}\n              </ResponsiveDialogDescription>\n            </ResponsiveDialogHeader>\n          </div>\n\n          {hasGuessed ? (\n            <div className=\"text-center\">\n              <ResponsiveDialogClose asChild>\n                <Button type=\"button\" ref={closeButtonRef}>\n                  Close\n                </Button>\n              </ResponsiveDialogClose>\n            </div>\n          ) : (\n            <div className=\"space-y-4\">\n              <div className=\"flex justify-center\">\n                <OTPInput\n                  inputMode=\"numeric\"\n                  id=\"confirmation-code\"\n                  ref={inputRef}\n                  value={value}\n                  onChange={setValue}\n                  containerClassName=\"flex items-center gap-3 has-disabled:opacity-50\"\n                  maxLength={4}\n                  onFocus={() => setHasGuessed(undefined)}\n                  render={({ slots }) => (\n                    <div className=\"flex gap-2\">\n                      {slots.map((slot, idx) => (\n                        <Slot key={idx} {...slot} />\n                      ))}\n                    </div>\n                  )}\n                  onComplete={onSubmit}\n                />\n              </div>\n              {hasGuessed === false && (\n                <p className=\"text-center text-xs text-muted-foreground\" role=\"alert\" aria-live=\"polite\">\n                  Invalid code. Please try again.\n                </p>\n              )}\n              <p className=\"text-center text-sm\">\n                <a className=\"underline hover:no-underline\" href=\"#\">\n                  Resend code\n                </a>\n              </p>\n            </div>\n          )}\n        </div>\n      </ResponsiveDialogContent>\n    </ResponsiveDialog>\n  );\n}\n\nfunction Slot(props: SlotProps) {\n  return (\n    <div\n      className={cn(\n        \"shadow-xs flex size-9 items-center justify-center rounded-md border border-input bg-background font-medium text-foreground transition-[color,box-shadow]\",\n        { \"z-10 border-ring ring-[3px] ring-ring/50\": props.isActive }\n      )}\n    >\n      {props.char !== null && <div>{props.char}</div>}\n    </div>\n  );\n}\n",
      "type": "registry:ui"
    }
  ]
}