{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "auth-signup",
  "title": "Auth Signup",
  "description": "The account-creation surface — name/email/password with a live strength meter and requirements checklist, terms acceptance, social sign-up and a sign-in prompt.",
  "dependencies": [
    "@untitledui/icons@^0.0.22"
  ],
  "registryDependencies": [
    "@nx-ui/auth-login",
    "@nx-ui/button",
    "@nx-ui/checkbox",
    "@nx-ui/field",
    "@nx-ui/input",
    "@nx-ui/label",
    "@nx-ui/nx-logo",
    "@nx-ui/utils"
  ],
  "files": [
    {
      "path": "components/blocks/auth-signup.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Check, X } from \"@untitledui/icons\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Button } from \"@/components/ui/button\"\nimport { Checkbox } from \"@/components/ui/checkbox\"\nimport {\n  Field,\n  FieldContent,\n  FieldError,\n  FieldGroup,\n  FieldLabel,\n  FieldSeparator,\n} from \"@/components/ui/field\"\nimport { Input } from \"@/components/ui/input\"\nimport { Label } from \"@/components/ui/label\"\nimport { NxLogo } from \"@/components/blocks/nx-logo\"\nimport { SocialButtons, type SocialProvider } from \"@/components/blocks/auth-login\"\n\n/**\n * auth-signup — the account-creation surface: `SignupForm`, a card with\n * name/email/password fields, a live password-strength meter and\n * requirements checklist, a terms checkbox, a social sign-up row and a\n * sign-in prompt. Purely visual — wire `onSubmit` to whatever backend the\n * consumer uses.\n */\n\n// ---------------------------------------------------------------------------\n// Password strength\n// ---------------------------------------------------------------------------\n\ntype Requirement = { label: string; test: (value: string) => boolean }\n\nconst REQUIREMENTS: Requirement[] = [\n  { label: \"At least 8 characters\", test: (v) => v.length >= 8 },\n  { label: \"One uppercase letter\", test: (v) => /[A-Z]/.test(v) },\n  { label: \"One number\", test: (v) => /\\d/.test(v) },\n  { label: \"One special character\", test: (v) => /[^A-Za-z0-9]/.test(v) },\n]\n\nfunction passwordScore(value: string) {\n  if (!value) return 0\n  return REQUIREMENTS.reduce((score, req) => score + (req.test(value) ? 1 : 0), 0)\n}\n\nconst STRENGTH_LABEL = [\"Very weak\", \"Weak\", \"Fair\", \"Good\", \"Strong\"]\nconst STRENGTH_TONE = [\n  \"bg-destructive\",\n  \"bg-destructive\",\n  \"bg-warning-500\",\n  \"bg-success-500\",\n  \"bg-success-600\",\n]\n\nfunction PasswordStrengthMeter({ value }: { value: string }) {\n  const score = passwordScore(value)\n\n  return (\n    <div className=\"flex flex-col gap-3\" aria-live=\"polite\">\n      <div className=\"flex gap-1.5\">\n        {REQUIREMENTS.map((_, index) => (\n          <div\n            key={index}\n            className={cn(\n              \"h-1.5 flex-1 rounded-full bg-muted transition-colors\",\n              value && index < score && STRENGTH_TONE[score]\n            )}\n          />\n        ))}\n      </div>\n\n      {value ? (\n        <p className=\"text-xs font-medium text-muted-foreground\">\n          Password strength: {STRENGTH_LABEL[score]}\n        </p>\n      ) : null}\n\n      <ul className=\"flex flex-col gap-1.5\">\n        {REQUIREMENTS.map((req) => {\n          const met = req.test(value)\n          return (\n            <li\n              key={req.label}\n              className={cn(\n                \"flex items-center gap-1.5 text-xs\",\n                met ? \"text-success-600 dark:text-success-500\" : \"text-muted-foreground\"\n              )}\n            >\n              {met ? (\n                <Check className=\"size-3.5 shrink-0\" />\n              ) : (\n                <X className=\"size-3.5 shrink-0\" />\n              )}\n              {req.label}\n            </li>\n          )\n        })}\n      </ul>\n    </div>\n  )\n}\n\n// ---------------------------------------------------------------------------\n// SignupForm\n// ---------------------------------------------------------------------------\n\ntype SignupFormValues = {\n  name: string\n  email: string\n  password: string\n  acceptedTerms: boolean\n}\n\nfunction SignupForm({\n  className,\n  logo = <NxLogo variant=\"lockup\" className=\"h-8\" />,\n  title = \"Create your account\",\n  description = \"Start your free trial — no card required.\",\n  socialProviders = [\"google\", \"microsoft\", \"apple\"],\n  onSubmit,\n  onSocialSignIn,\n  onSignIn,\n  termsHref = \"#\",\n  privacyHref = \"#\",\n  errors,\n  loading = false,\n}: {\n  className?: string\n  logo?: React.ReactNode\n  title?: React.ReactNode\n  description?: React.ReactNode\n  socialProviders?: SocialProvider[]\n  onSubmit?: (values: SignupFormValues) => void\n  onSocialSignIn?: (provider: SocialProvider) => void\n  onSignIn?: () => void\n  termsHref?: string\n  privacyHref?: string\n  errors?: Partial<Record<\"name\" | \"email\" | \"password\" | \"acceptedTerms\", string>>\n  loading?: boolean\n}) {\n  const [password, setPassword] = React.useState(\"\")\n  const [acceptedTerms, setAcceptedTerms] = React.useState(false)\n  const fieldId = React.useId()\n  const nameId = `${fieldId}-name`\n  const emailId = `${fieldId}-email`\n  const passwordId = `${fieldId}-password`\n  const termsId = `${fieldId}-terms`\n\n  function handleSubmit(event: React.FormEvent<HTMLFormElement>) {\n    event.preventDefault()\n    const data = new FormData(event.currentTarget)\n    onSubmit?.({\n      name: String(data.get(\"name\") ?? \"\"),\n      email: String(data.get(\"email\") ?? \"\"),\n      password,\n      acceptedTerms,\n    })\n  }\n\n  return (\n    <div className={cn(\"flex w-full max-w-sm flex-col gap-6\", className)}>\n      <div className=\"flex flex-col items-center gap-4 text-center\">\n        {logo}\n        <div className=\"flex flex-col gap-1\">\n          <h1 className=\"text-display-xs font-semibold text-foreground\">{title}</h1>\n          {description ? (\n            <p className=\"text-sm text-muted-foreground\">{description}</p>\n          ) : null}\n        </div>\n      </div>\n\n      <form onSubmit={handleSubmit} noValidate>\n        <FieldGroup>\n          <Field data-invalid={!!errors?.name}>\n            <FieldLabel htmlFor={nameId}>Full name</FieldLabel>\n            <Input\n              id={nameId}\n              name=\"name\"\n              type=\"text\"\n              autoComplete=\"name\"\n              placeholder=\"Jane Cooper\"\n              aria-invalid={!!errors?.name}\n              required\n            />\n            <FieldError>{errors?.name}</FieldError>\n          </Field>\n\n          <Field data-invalid={!!errors?.email}>\n            <FieldLabel htmlFor={emailId}>Email</FieldLabel>\n            <Input\n              id={emailId}\n              name=\"email\"\n              type=\"email\"\n              autoComplete=\"email\"\n              placeholder=\"you@company.com\"\n              aria-invalid={!!errors?.email}\n              required\n            />\n            <FieldError>{errors?.email}</FieldError>\n          </Field>\n\n          <Field data-invalid={!!errors?.password}>\n            <FieldLabel htmlFor={passwordId}>Password</FieldLabel>\n            <Input\n              id={passwordId}\n              name=\"password\"\n              type=\"password\"\n              autoComplete=\"new-password\"\n              placeholder=\"••••••••\"\n              value={password}\n              onChange={(event) => setPassword(event.target.value)}\n              aria-invalid={!!errors?.password}\n              required\n            />\n            <FieldError>{errors?.password}</FieldError>\n            <PasswordStrengthMeter value={password} />\n          </Field>\n\n          <Field orientation=\"horizontal\" data-invalid={!!errors?.acceptedTerms}>\n            <Checkbox\n              id={termsId}\n              checked={acceptedTerms}\n              onCheckedChange={(checked) => setAcceptedTerms(checked === true)}\n              required\n            />\n            <FieldContent>\n              <Label htmlFor={termsId}>\n                I agree to the{\" \"}\n                <a href={termsHref} className=\"underline underline-offset-4 hover:text-primary\">\n                  Terms of Service\n                </a>{\" \"}\n                and{\" \"}\n                <a\n                  href={privacyHref}\n                  className=\"underline underline-offset-4 hover:text-primary\"\n                >\n                  Privacy Policy\n                </a>\n              </Label>\n              <FieldError>{errors?.acceptedTerms}</FieldError>\n            </FieldContent>\n          </Field>\n\n          <Button type=\"submit\" className=\"w-full\" disabled={loading}>\n            {loading ? \"Creating account…\" : \"Create account\"}\n          </Button>\n\n          {socialProviders.length ? (\n            <>\n              <FieldSeparator>Or continue with</FieldSeparator>\n              <SocialButtons\n                providers={socialProviders}\n                onSocialSignIn={onSocialSignIn}\n              />\n            </>\n          ) : null}\n        </FieldGroup>\n      </form>\n\n      <p className=\"text-center text-sm text-muted-foreground\">\n        Already have an account?{\" \"}\n        <Button type=\"button\" variant=\"link-color\" size=\"sm\" onClick={onSignIn}>\n          Sign in\n        </Button>\n      </p>\n    </div>\n  )\n}\n\nexport { SignupForm, PasswordStrengthMeter }\n",
      "type": "registry:component"
    }
  ],
  "type": "registry:block"
}