{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "login-1",
  "title": "Login 1: card with SSO and magic link",
  "author": "Ballmac <https://ui.ballmac.com>",
  "description": "Centered sign-in card: SSO and email-link buttons, an email and password form with remember me, a loading submit and an inline error.",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "utils",
    "https://ui.ballmac.com/r/button.json",
    "https://ui.ballmac.com/r/checkbox.json",
    "https://ui.ballmac.com/r/input.json",
    "https://ui.ballmac.com/r/label.json"
  ],
  "files": [
    {
      "path": "registry/ballmac/components/blocks/login-1/login-1.tsx",
      "content": "// Ballmac UI: Login 1. https://ui.ballmac.com/blocks/login-1\n\"use client\"\n\nimport * as React from \"react\"\nimport { KeyRound, Mail } from \"lucide-react\"\n\nimport { Button } from \"@/components/ballmac/button\"\nimport { Checkbox } from \"@/components/ballmac/checkbox\"\nimport { Input } from \"@/components/ballmac/input\"\nimport { Label } from \"@/components/ballmac/label\"\nimport { cn } from \"@/lib/utils\"\n\ntype Login1Props = Omit<React.ComponentProps<\"section\">, \"onSubmit\"> & {\n  /** Brand name or logo above the form. */\n  brand?: React.ReactNode\n  /** Heading. */\n  title?: string\n  /** Called with the form values. Show errors by passing `error`. */\n  onSubmit?: (values: { email: string; password: string; remember: boolean }) => void | Promise<void>\n  /** Called when \"Continue with SSO\" is pressed. Pass null to hide the button. */\n  onSso?: (() => void) | null\n  /** Called when \"Email me a sign-in link\" is pressed. Pass null to hide the button. */\n  onMagicLink?: (() => void) | null\n  /** Error message shown above the form. */\n  error?: string\n  /** Where the \"Forgot password?\" link goes. */\n  forgotHref?: string\n  /** Where the \"Create an account\" link goes. */\n  signupHref?: string\n}\n\nfunction Login1({\n  brand = \"Acme\",\n  title = \"Sign in to your account\",\n  onSubmit,\n  onSso = () => {},\n  onMagicLink = () => {},\n  error,\n  forgotHref = \"#\",\n  signupHref = \"#\",\n  className,\n  ...props\n}: Login1Props) {\n  const id = React.useId()\n  const [pending, setPending] = React.useState(false)\n  return (\n    <section data-slot=\"login-1\" className={cn(\"flex min-h-[640px] items-center justify-center px-4 py-16\", className)} {...props}>\n      <div className=\"w-full max-w-sm\">\n        <div className=\"text-center\">\n          <div className=\"text-lg font-semibold tracking-tight\">{brand}</div>\n          <h1 className=\"mt-6 text-2xl font-semibold tracking-tight\">{title}</h1>\n        </div>\n        <div className=\"mt-8 rounded-2xl border bg-card p-6 shadow-[0_20px_60px_-40px_rgb(0_0_0/0.35)]\">\n          <div className=\"grid gap-2\">\n            {onSso && (\n              <Button variant=\"outline\" onClick={onSso}>\n                <KeyRound /> Continue with SSO\n              </Button>\n            )}\n            {onMagicLink && (\n              <Button variant=\"outline\" onClick={onMagicLink}>\n                <Mail /> Email me a sign-in link\n              </Button>\n            )}\n          </div>\n          <div className=\"my-6 flex items-center gap-3 text-xs text-muted-foreground\" aria-hidden=\"true\">\n            <span className=\"h-px flex-1 bg-border\" />\n            or\n            <span className=\"h-px flex-1 bg-border\" />\n          </div>\n          <form\n            className=\"grid gap-4\"\n            onSubmit={async (e) => {\n              e.preventDefault()\n              const data = new FormData(e.currentTarget)\n              setPending(true)\n              try {\n                await onSubmit?.({ email: String(data.get(\"email\")), password: String(data.get(\"password\")), remember: data.get(\"remember\") === \"on\" })\n              } finally {\n                setPending(false)\n              }\n            }}\n          >\n            {error && (\n              <p role=\"alert\" className=\"rounded-md border border-destructive/30 bg-destructive/10 px-3 py-2 text-sm text-destructive\">\n                {error}\n              </p>\n            )}\n            <div className=\"grid gap-2\">\n              <Label htmlFor={`${id}-email`}>Email</Label>\n              <Input id={`${id}-email`} name=\"email\" type=\"email\" autoComplete=\"email\" required aria-invalid={error ? true : undefined} />\n            </div>\n            <div className=\"grid gap-2\">\n              <div className=\"flex items-center justify-between\">\n                <Label htmlFor={`${id}-password`}>Password</Label>\n                <a href={forgotHref} className=\"text-sm text-muted-foreground underline-offset-4 hover:text-foreground hover:underline\">\n                  Forgot password?\n                </a>\n              </div>\n              <Input id={`${id}-password`} name=\"password\" type=\"password\" autoComplete=\"current-password\" required aria-invalid={error ? true : undefined} />\n            </div>\n            <div className=\"flex items-center gap-2\">\n              <Checkbox id={`${id}-remember`} name=\"remember\" />\n              <Label htmlFor={`${id}-remember`} className=\"font-normal\">\n                Keep me signed in\n              </Label>\n            </div>\n            <Button type=\"submit\" loading={pending} className=\"mt-2 w-full\">\n              Sign in\n            </Button>\n          </form>\n        </div>\n        <p className=\"mt-6 text-center text-sm text-muted-foreground\">\n          New here?{\" \"}\n          <a href={signupHref} className=\"text-foreground underline underline-offset-4\">\n            Create an account\n          </a>\n        </p>\n      </div>\n    </section>\n  )\n}\n\nexport { Login1, type Login1Props }\n",
      "type": "registry:component",
      "target": "@components/ballmac/blocks/login-1/login-1.tsx"
    }
  ],
  "meta": {
    "schema": 1,
    "tier": "free",
    "tags": [
      "login",
      "sign in",
      "auth",
      "form",
      "sso"
    ],
    "version": "1.0.0",
    "updated": "2026-09-28",
    "ai": {
      "summary": "A sign-in screen. Wire onSubmit to your auth (it can be async; the button shows a spinner), pass error to show failures, and onSso/onMagicLink for passwordless options.",
      "whenToUse": [
        "App sign-in pages",
        "Admin or dashboard login"
      ],
      "whenNotToUse": [
        "Sign-up with many fields (build a form from input, label and checkbox)"
      ],
      "composesWith": [
        "footer-1"
      ],
      "a11y": [],
      "customization": [
        "onSubmit({ email, password, remember })",
        "error, onSso, onMagicLink, forgotHref, signupHref props",
        "Pass onSso={null} or onMagicLink={null} to hide that button"
      ]
    },
    "examples": [
      "login-1-demo"
    ],
    "url": "https://ui.ballmac.com/components/login-1"
  },
  "categories": [
    "blocks",
    "auth"
  ],
  "type": "registry:block"
}