{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "authentication-form",
  "type": "registry:block",
  "title": "Authentication Form",
  "description": "Login and registration form with validation and optional social callbacks.",
  "dependencies": [
    "@mantine/core@^9",
    "@mantine/form@^9",
    "@mantine/hooks@^9",
    "@tabler/icons-react@^3"
  ],
  "docs": "Adapted from Mantine UI AuthenticationForm at ffbf61c559f374a7ea28fcf00355e84dcbe9a908; submission and social actions are exposed as callbacks.",
  "registryDependencies": [
    "@house/mantine-ui-license"
  ],
  "files": [
    {
      "path": "registry/mantine-ui/authentication-form/authentication-form.tsx",
      "type": "registry:ui",
      "content": "/**\n * Adapted from Mantine UI's AuthenticationForm at\n * ffbf61c559f374a7ea28fcf00355e84dcbe9a908. MIT licensed; see\n * LICENSES/MANTINE-UI.txt after installation.\n *\n * Curated deviation from upstream: the terms-and-conditions checkbox defaults to\n * unchecked here (`initialTerms` prop, default `false`). Upstream initializes it\n * `true`, which renders a pre-checked consent checkbox with no user action — a\n * dark pattern this registry does not ship by default.\n */\nimport {\n  Anchor,\n  Button,\n  Checkbox,\n  Divider,\n  Group,\n  Paper,\n  type PaperProps,\n  PasswordInput,\n  Stack,\n  Text,\n  TextInput,\n} from \"@mantine/core\";\nimport { useForm } from \"@mantine/form\";\nimport { upperFirst, useToggle } from \"@mantine/hooks\";\n\nimport { GithubButton } from \"./github-button\";\nimport { GoogleButton } from \"./google-button\";\n\nexport type AuthenticationMode = \"login\" | \"register\";\n\nexport interface AuthenticationValues {\n  email: string;\n  name: string;\n  password: string;\n  terms: boolean;\n}\n\nexport interface AuthenticationFormProps extends PaperProps {\n  initialMode?: AuthenticationMode;\n  heading?: string;\n  /** Initial checked state of the terms-and-conditions checkbox. Defaults to `false` — the box\n   * must never render pre-checked without the consumer opting in explicitly. */\n  initialTerms?: boolean;\n  onSubmit?: (values: AuthenticationValues, mode: AuthenticationMode) => void;\n  onGoogle?: () => void;\n  onGithub?: () => void;\n}\n\nexport function AuthenticationForm({\n  initialMode = \"login\",\n  heading = \"Welcome\",\n  initialTerms = false,\n  onSubmit,\n  onGoogle,\n  onGithub,\n  ...paperProps\n}: AuthenticationFormProps) {\n  const alternateMode: AuthenticationMode = initialMode === \"login\" ? \"register\" : \"login\";\n  const [mode, toggle] = useToggle<AuthenticationMode>([initialMode, alternateMode]);\n  const hasSocialLogin = Boolean(onGoogle || onGithub);\n  const form = useForm<AuthenticationValues>({\n    initialValues: { email: \"\", name: \"\", password: \"\", terms: initialTerms },\n    validate: {\n      email: (value) => (/^\\S+@\\S+$/.test(value) ? null : \"Enter a valid email address\"),\n      password: (value) =>\n        value.length >= 7 ? null : \"Password should include at least 7 characters\",\n    },\n  });\n\n  return (\n    <Paper radius=\"md\" p=\"lg\" withBorder {...paperProps}>\n      <Text size=\"lg\" fw={500} c=\"bright\">\n        {heading}, {mode} with\n      </Text>\n\n      {hasSocialLogin && (\n        <>\n          <Group grow mb=\"md\" mt=\"md\">\n            {onGoogle && (\n              <GoogleButton radius=\"xl\" onClick={onGoogle}>\n                Google\n              </GoogleButton>\n            )}\n            {onGithub && (\n              <GithubButton radius=\"xl\" onClick={onGithub}>\n                GitHub\n              </GithubButton>\n            )}\n          </Group>\n\n          <Divider\n            label=\"Or continue with email\"\n            labelPosition=\"center\"\n            my=\"lg\"\n            styles={{ label: { color: \"var(--mantine-color-bright)\", opacity: 0.85 } }}\n          />\n        </>\n      )}\n\n      <form onSubmit={form.onSubmit((values) => onSubmit?.(values, mode))}>\n        <Stack>\n          {mode === \"register\" && (\n            <TextInput\n              label=\"Name\"\n              placeholder=\"Enter your name\"\n              key={form.key(\"name\")}\n              {...form.getInputProps(\"name\")}\n              radius=\"md\"\n            />\n          )}\n\n          <TextInput\n            required\n            label=\"Email\"\n            placeholder=\"Enter your email\"\n            key={form.key(\"email\")}\n            {...form.getInputProps(\"email\")}\n            radius=\"md\"\n          />\n\n          <PasswordInput\n            required\n            label=\"Password\"\n            placeholder=\"Enter your password\"\n            key={form.key(\"password\")}\n            {...form.getInputProps(\"password\")}\n            radius=\"md\"\n          />\n\n          {mode === \"register\" && (\n            <Checkbox\n              label=\"I accept the terms and conditions\"\n              key={form.key(\"terms\")}\n              {...form.getInputProps(\"terms\", { type: \"checkbox\" })}\n            />\n          )}\n        </Stack>\n\n        <Group justify=\"space-between\" mt=\"xl\">\n          <Anchor\n            component=\"button\"\n            type=\"button\"\n            c=\"bright\"\n            opacity={0.85}\n            onClick={() => toggle()}\n            size=\"xs\"\n          >\n            {mode === \"register\"\n              ? \"Already have an account? Login\"\n              : \"Don't have an account? Register\"}\n          </Anchor>\n          <Button type=\"submit\" radius=\"xl\" color=\"blue.9\">\n            {upperFirst(mode)}\n          </Button>\n        </Group>\n      </form>\n    </Paper>\n  );\n}\n"
    },
    {
      "path": "registry/mantine-ui/authentication-form/google-button.tsx",
      "type": "registry:ui",
      "content": "/**\n * Adapted from Mantine UI's AuthenticationForm at\n * ffbf61c559f374a7ea28fcf00355e84dcbe9a908. MIT licensed; see\n * LICENSES/MANTINE-UI.txt after installation.\n */\n\nimport { Button, type ButtonProps } from \"@mantine/core\";\nimport type { ComponentPropsWithoutRef } from \"react\";\n\nfunction GoogleIcon(props: ComponentPropsWithoutRef<\"svg\">) {\n  return (\n    <svg\n      xmlns=\"http://www.w3.org/2000/svg\"\n      preserveAspectRatio=\"xMidYMid\"\n      viewBox=\"0 0 256 262\"\n      style={{ width: 14, height: 14 }}\n      aria-hidden=\"true\"\n      {...props}\n    >\n      <path\n        fill=\"#4285F4\"\n        d=\"M255.878 133.451c0-10.734-.871-18.567-2.756-26.69H130.55v48.448h71.947c-1.45 12.04-9.283 30.172-26.69 42.356l-.244 1.622 38.755 30.023 2.685.268c24.659-22.774 38.875-56.282 38.875-96.027\"\n      />\n      <path\n        fill=\"#34A853\"\n        d=\"M130.55 261.1c35.248 0 64.839-11.605 86.453-31.622l-41.196-31.913c-11.024 7.688-25.82 13.055-45.257 13.055-34.523 0-63.824-22.773-74.269-54.25l-1.531.13-40.298 31.187-.527 1.465C35.393 231.798 79.49 261.1 130.55 261.1\"\n      />\n      <path\n        fill=\"#FBBC05\"\n        d=\"M56.281 156.37c-2.756-8.123-4.351-16.827-4.351-25.82 0-8.994 1.595-17.697 4.206-25.82l-.073-1.73L15.26 71.312l-1.335.635C5.077 89.644 0 109.517 0 130.55s5.077 40.905 13.925 58.602l42.356-32.782\"\n      />\n      <path\n        fill=\"#EB4335\"\n        d=\"M130.55 50.479c24.514 0 41.05 10.589 50.479 19.438l36.844-35.974C195.245 12.91 165.798 0 130.55 0 79.49 0 35.393 29.301 13.925 71.947l42.211 32.783c10.59-31.477 39.891-54.251 74.414-54.251\"\n      />\n    </svg>\n  );\n}\n\nexport function GoogleButton(props: ButtonProps & ComponentPropsWithoutRef<\"button\">) {\n  return (\n    <Button\n      leftSection={<GoogleIcon />}\n      variant=\"default\"\n      styles={{ section: { marginInlineEnd: 8 } }}\n      {...props}\n    />\n  );\n}\n"
    },
    {
      "path": "registry/mantine-ui/authentication-form/github-button.tsx",
      "type": "registry:ui",
      "content": "/**\n * Adapted from Mantine UI's AuthenticationForm social button at\n * ffbf61c559f374a7ea28fcf00355e84dcbe9a908. MIT licensed; see\n * LICENSES/MANTINE-UI.txt after installation.\n */\n\nimport { Button, type ButtonProps } from \"@mantine/core\";\nimport { IconBrandGithub } from \"@tabler/icons-react\";\nimport type { ComponentPropsWithoutRef } from \"react\";\n\nexport function GithubButton(props: ButtonProps & ComponentPropsWithoutRef<\"button\">) {\n  return (\n    <Button\n      leftSection={<IconBrandGithub size={16} />}\n      variant=\"default\"\n      styles={{ section: { marginInlineEnd: 8 } }}\n      {...props}\n    />\n  );\n}\n"
    }
  ],
  "meta": {
    "mantine": {
      "requires": ">=9",
      "provider": "MantineProvider",
      "props": {
        "AuthenticationForm": [
          {
            "name": "initialMode",
            "type": "\"login\" | \"register\"",
            "default": "\"login\"",
            "description": "Sets which mode the form starts in; the internal toggle then switches between login and register."
          },
          {
            "name": "heading",
            "type": "string",
            "default": "\"Welcome\"",
            "description": "Heading text rendered as \"{heading}, {mode} with\" above the form, e.g. \"Welcome, login with\"."
          },
          {
            "name": "initialTerms",
            "type": "boolean",
            "default": "false",
            "description": "Initial checked state of the terms-and-conditions checkbox shown in register mode. Upstream Mantine UI initializes it true, which renders a pre-checked consent box the user never touched; this registry defaults it false. Set it true only if your flow genuinely warrants a pre-checked consent."
          },
          {
            "name": "onSubmit",
            "type": "(values: AuthenticationValues, mode: AuthenticationMode) => void",
            "description": "Called with the validated form values and current mode when the form is submitted."
          },
          {
            "name": "onGoogle",
            "type": "() => void",
            "description": "Renders the Google social button and handles its click; the social row and divider are hidden entirely when neither social handler is set."
          },
          {
            "name": "onGithub",
            "type": "() => void",
            "description": "Renders the GitHub social button and handles its click; the social row and divider are hidden entirely when neither social handler is set."
          },
          {
            "name": "...others",
            "type": "PaperProps",
            "description": "All other props are forwarded to the underlying Paper. AuthenticationFormProps extends PaperProps, and the spread is applied after the component's own radius=\"md\", p=\"lg\", withBorder defaults, so any of those three can be overridden by the caller."
          }
        ]
      },
      "usage": {
        "path": "registry/mantine-ui/authentication-form/authentication-form.usage.tsx",
        "content": "import { AuthenticationForm } from \"@/components/ui/authentication-form\";\n\nexport function AccountSignIn() {\n  return (\n    <AuthenticationForm\n      heading=\"Welcome back\"\n      onSubmit={(values, mode) => console.log(\"submit\", values, mode)}\n      onGoogle={() => console.log(\"continue with google\")}\n      onGithub={() => console.log(\"continue with github\")}\n    />\n  );\n}\n"
      }
    }
  }
}
