{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "auth-5",
  "description": "Tabbed auth card that swaps sign-in and sign-up fields, with social login buttons and a divider",
  "dependencies": [
    "@remixicon/react",
    "zod",
    "@base-ui/react"
  ],
  "registryDependencies": [
    "button",
    "card",
    "field",
    "input",
    "separator",
    "sonner",
    "tabs"
  ],
  "files": [
    {
      "path": "registry/blocks/auth/5/auth-block.tsx",
      "content": "\"use client\"\n\nimport { useState } from \"react\"\nimport {\n  RiAppleFill,\n  RiArrowRightLine,\n  RiGithubFill,\n  RiGoogleFill,\n  RiShieldKeyholeLine,\n} from \"@remixicon/react\"\nimport { toast } from \"sonner\"\nimport { z } from \"zod\"\n\nimport { Button } from \"@/components/ui/button\"\nimport {\n  Card,\n  CardContent,\n  CardDescription,\n  CardFooter,\n  CardHeader,\n  CardTitle,\n} from \"@/components/ui/card\"\nimport {\n  Field,\n  FieldDescription,\n  FieldError,\n  FieldLabel,\n} from \"@/components/ui/field\"\nimport { Input } from \"@/components/ui/input\"\nimport { Separator } from \"@/components/ui/separator\"\nimport { Toaster } from \"@/components/ui/sonner\"\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from \"@/components/ui/tabs\"\n\nconst BRAND = \"Acme\"\n\nconst SOCIALS = [\n  { id: \"google\", label: \"Google\", icon: RiGoogleFill },\n  { id: \"github\", label: \"GitHub\", icon: RiGithubFill },\n  { id: \"apple\", label: \"Apple\", icon: RiAppleFill },\n]\n\nconst signInSchema = z.object({\n  email: z\n    .string()\n    .min(1, \"Email is required\")\n    .email(\"Enter a valid email address\"),\n  password: z.string().min(1, \"Password is required\"),\n})\n\nconst signUpSchema = z\n  .object({\n    name: z.string().min(1, \"Full name is required\"),\n    email: z\n      .string()\n      .min(1, \"Email is required\")\n      .email(\"Enter a valid email address\"),\n    password: z\n      .string()\n      .min(8, \"Password must be at least 8 characters\")\n      .regex(/[0-9]/, \"Include at least one number\"),\n    confirm: z.string().min(1, \"Please confirm your password\"),\n  })\n  .refine((data) => data.password === data.confirm, {\n    message: \"Passwords do not match\",\n    path: [\"confirm\"],\n  })\n\nexport default function AuthBlock() {\n  const [tab, setTab] = useState(\"signin\")\n  const [errors, setErrors] = useState<Record<string, string>>({})\n  const isSignUp = tab === \"signup\"\n\n  function handleSubmit(event: React.FormEvent<HTMLFormElement>) {\n    event.preventDefault()\n    const data = Object.fromEntries(new FormData(event.currentTarget))\n    const result = (isSignUp ? signUpSchema : signInSchema).safeParse(data)\n    if (!result.success) {\n      const next: Record<string, string> = {}\n      for (const issue of result.error.issues) {\n        const key = issue.path[0]\n        if (typeof key === \"string\" && !next[key]) {\n          next[key] = issue.message\n        }\n      }\n      setErrors(next)\n      return\n    }\n    setErrors({})\n    toast.promise(new Promise((resolve) => setTimeout(resolve, 1400)), {\n      loading: isSignUp ? \"Creating your account…\" : \"Signing you in…\",\n      success: isSignUp\n        ? `Welcome to ${BRAND}! Your account is ready.`\n        : `Welcome back to ${BRAND}.`,\n      error: isSignUp\n        ? \"Could not create account. Please try again.\"\n        : \"Sign-in failed. Please try again.\",\n    })\n  }\n\n  function clearError(name: string) {\n    setErrors((prev) => {\n      if (!prev[name]) return prev\n      const next = { ...prev }\n      delete next[name]\n      return next\n    })\n  }\n\n  function handleSocial(label: string) {\n    toast.info(`Continuing with ${label}`, {\n      description: \"Redirecting you to authenticate…\",\n    })\n  }\n\n  return (\n    <section className=\"flex w-full items-center justify-center bg-muted/30 px-6 py-16 text-foreground\">\n      <Toaster />\n      <Card className=\"w-full max-w-md gap-6\">\n        <CardHeader className=\"items-center gap-3 text-center\">\n          <span className=\"mx-auto flex size-11 items-center justify-center border border-border bg-muted text-foreground\">\n            <RiShieldKeyholeLine className=\"size-5\" aria-hidden=\"true\" />\n          </span>\n          <div className=\"flex flex-col gap-1\">\n            <CardTitle className=\"text-lg font-bold tracking-tight\">\n              {isSignUp ? `Join ${BRAND}` : `Welcome back to ${BRAND}`}\n            </CardTitle>\n            <CardDescription>\n              {isSignUp\n                ? \"Create your account in under a minute.\"\n                : \"Sign in to pick up where you left off.\"}\n            </CardDescription>\n          </div>\n        </CardHeader>\n\n        <CardContent className=\"flex flex-col gap-6\">\n          <Tabs\n            value={tab}\n            onValueChange={(value) => {\n              setTab(value as string)\n              setErrors({})\n            }}\n          >\n            <TabsList className=\"grid h-9 w-full grid-cols-2\">\n              <TabsTrigger value=\"signin\">Sign in</TabsTrigger>\n              <TabsTrigger value=\"signup\">Sign up</TabsTrigger>\n            </TabsList>\n\n            <TabsContent value=\"signin\" className=\"pt-5\">\n              <form\n                className=\"flex flex-col gap-5\"\n                onSubmit={handleSubmit}\n                noValidate\n              >\n                <Field>\n                  <FieldLabel htmlFor=\"signin-email\">Email</FieldLabel>\n                  <Input\n                    id=\"signin-email\"\n                    name=\"email\"\n                    type=\"email\"\n                    placeholder=\"jordan@company.com\"\n                    autoComplete=\"email\"\n                    aria-invalid={!!errors.email}\n                    onChange={() => clearError(\"email\")}\n                  />\n                  <FieldError>{errors.email}</FieldError>\n                </Field>\n                <Field>\n                  <div className=\"flex items-center justify-between\">\n                    <FieldLabel htmlFor=\"signin-password\">Password</FieldLabel>\n                    <Button\n                      variant=\"link\"\n                      className=\"h-auto p-0 text-xs\"\n                      render={<a href=\"#\" />}\n                      nativeButton={false}\n                    >\n                      Forgot password?\n                    </Button>\n                  </div>\n                  <Input\n                    id=\"signin-password\"\n                    name=\"password\"\n                    type=\"password\"\n                    placeholder=\"••••••••\"\n                    autoComplete=\"current-password\"\n                    aria-invalid={!!errors.password}\n                    onChange={() => clearError(\"password\")}\n                  />\n                  <FieldError>{errors.password}</FieldError>\n                </Field>\n                <Button type=\"submit\" size=\"lg\" className=\"w-full\">\n                  Sign in\n                  <RiArrowRightLine data-icon=\"inline-end\" />\n                </Button>\n              </form>\n            </TabsContent>\n\n            <TabsContent value=\"signup\" className=\"pt-5\">\n              <form\n                className=\"flex flex-col gap-5\"\n                onSubmit={handleSubmit}\n                noValidate\n              >\n                <Field>\n                  <FieldLabel htmlFor=\"signup-name\">Full name</FieldLabel>\n                  <Input\n                    id=\"signup-name\"\n                    name=\"name\"\n                    type=\"text\"\n                    placeholder=\"Jordan Blake\"\n                    autoComplete=\"name\"\n                    aria-invalid={!!errors.name}\n                    onChange={() => clearError(\"name\")}\n                  />\n                  <FieldError>{errors.name}</FieldError>\n                </Field>\n                <Field>\n                  <FieldLabel htmlFor=\"signup-email\">Email</FieldLabel>\n                  <Input\n                    id=\"signup-email\"\n                    name=\"email\"\n                    type=\"email\"\n                    placeholder=\"jordan@company.com\"\n                    autoComplete=\"email\"\n                    aria-invalid={!!errors.email}\n                    onChange={() => clearError(\"email\")}\n                  />\n                  <FieldError>{errors.email}</FieldError>\n                </Field>\n                <Field>\n                  <FieldLabel htmlFor=\"signup-password\">Password</FieldLabel>\n                  <Input\n                    id=\"signup-password\"\n                    name=\"password\"\n                    type=\"password\"\n                    placeholder=\"••••••••\"\n                    autoComplete=\"new-password\"\n                    aria-invalid={!!errors.password}\n                    onChange={() => clearError(\"password\")}\n                  />\n                  {errors.password ? (\n                    <FieldError>{errors.password}</FieldError>\n                  ) : (\n                    <FieldDescription>\n                      Minimum 8 characters, at least one number.\n                    </FieldDescription>\n                  )}\n                </Field>\n                <Field>\n                  <FieldLabel htmlFor=\"signup-confirm\">\n                    Confirm password\n                  </FieldLabel>\n                  <Input\n                    id=\"signup-confirm\"\n                    name=\"confirm\"\n                    type=\"password\"\n                    placeholder=\"••••••••\"\n                    autoComplete=\"new-password\"\n                    aria-invalid={!!errors.confirm}\n                    onChange={() => clearError(\"confirm\")}\n                  />\n                  <FieldError>{errors.confirm}</FieldError>\n                </Field>\n                <Button type=\"submit\" size=\"lg\" className=\"w-full\">\n                  Create account\n                  <RiArrowRightLine data-icon=\"inline-end\" />\n                </Button>\n              </form>\n            </TabsContent>\n          </Tabs>\n\n          <div className=\"flex items-center gap-3\">\n            <Separator className=\"flex-1\" />\n            <span className=\"text-xs text-muted-foreground\">Or</span>\n            <Separator className=\"flex-1\" />\n          </div>\n\n          <div className=\"grid grid-cols-3 gap-3\">\n            {SOCIALS.map((social) => {\n              const Icon = social.icon\n              return (\n                <Button\n                  key={social.id}\n                  variant=\"outline\"\n                  type=\"button\"\n                  className=\"w-full\"\n                  aria-label={`Continue with ${social.label}`}\n                  onClick={() => handleSocial(social.label)}\n                >\n                  <Icon data-icon=\"inline-start\" />\n                  <span className=\"sr-only sm:not-sr-only\">{social.label}</span>\n                </Button>\n              )\n            })}\n          </div>\n        </CardContent>\n\n        <CardFooter className=\"justify-center text-xs text-muted-foreground\">\n          {isSignUp ? \"Already have an account?\" : \"New to Acme?\"}\n          <Button\n            variant=\"link\"\n            className=\"px-1 text-xs\"\n            type=\"button\"\n            onClick={() => setTab(isSignUp ? \"signin\" : \"signup\")}\n          >\n            {isSignUp ? \"Sign in\" : \"Create one\"}\n          </Button>\n        </CardFooter>\n      </Card>\n    </section>\n  )\n}\n",
      "type": "registry:component"
    }
  ],
  "meta": {
    "height": "85vh",
    "tier": "free"
  },
  "categories": [
    "auth"
  ],
  "type": "registry:block"
}