{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "sign-in-card",
  "title": "Sign-in Card",
  "description": "A compound sign-in form with providers, credentials, recovery, and async feedback.",
  "dependencies": [
    "class-variance-authority",
    "lucide-react"
  ],
  "registryDependencies": [
    "button",
    "input",
    "label",
    "separator",
    "toggle",
    "https://uaiblocks.dev/r/uai-theme.json",
    "https://uaiblocks.dev/r/uai-utils.json"
  ],
  "files": [
    {
      "path": "src/registry/uai/components/sign-in-card.tsx",
      "content": "\"use client\";\n\nimport { cva } from \"class-variance-authority\";\nimport { Eye, EyeOff, LoaderCircle } from \"lucide-react\";\nimport { type ComponentProps, createContext, useContext, useId, useState } from \"react\";\n\nimport { Button } from \"@/components/ui/button\";\nimport { Input } from \"@/components/ui/input\";\nimport { Label } from \"@/components/ui/label\";\nimport { Separator } from \"@/components/ui/separator\";\nimport { Toggle } from \"@/components/ui/toggle\";\nimport { cn } from \"@/lib/uai-utils\";\n\nexport const SIGN_IN_CARD_VARIANTS = [\"card\", \"split\", \"compact\"] as const;\nexport const SIGN_IN_CARD_STATUSES = [\"idle\", \"submitting\", \"error\"] as const;\n\nexport type SignInCardVariant = (typeof SIGN_IN_CARD_VARIANTS)[number];\nexport type SignInCardStatus = (typeof SIGN_IN_CARD_STATUSES)[number];\n\nexport type SignInCardProps = ComponentProps<\"form\"> & {\n  variant?: SignInCardVariant;\n  status?: SignInCardStatus;\n};\n\ntype SignInCardChrome = {\n  headerClass: string;\n  titleClass: string;\n  descriptionClass: string;\n  bodyClass: string;\n  groupGapClass: string;\n  controlClass: string;\n  controlRadiusClass: string;\n  footerClass: string;\n};\n\nconst signInCardVariants = cva(\"w-full border bg-card text-card-foreground\", {\n  variants: {\n    variant: {\n      card: \"rounded-[14px] p-5\",\n      split: \"rounded-[14px] p-6\",\n      compact: \"rounded-xl p-3.5\",\n    },\n  },\n});\n\nfunction signInCardChrome(variant: SignInCardVariant): SignInCardChrome {\n  const compact = variant === \"compact\";\n\n  return {\n    headerClass: compact ? \"mb-4\" : \"mb-5\",\n    titleClass: compact ? \"text-[15px] leading-5\" : \"text-[17px] leading-6\",\n    descriptionClass: compact\n      ? \"mt-1 text-[12.5px] leading-[18px]\"\n      : \"mt-1.5 text-[13px] leading-[18px]\",\n    bodyClass:\n      variant === \"split\"\n        ? \"grid gap-5 sm:grid-cols-[minmax(0,1fr)_auto_minmax(0,1fr)] sm:items-stretch sm:gap-6\"\n        : \"grid gap-4\",\n    groupGapClass: compact ? \"gap-2.5\" : \"gap-3\",\n    controlClass: compact\n      ? \"h-[34px] py-0 text-[12.5px] md:text-[12.5px]\"\n      : \"h-[38px] py-0 text-[13px] md:text-[13px]\",\n    controlRadiusClass: compact ? \"rounded-lg\" : \"rounded-[10px]\",\n    footerClass: compact ? \"mt-4 pt-3.5\" : \"mt-5 pt-4\",\n  };\n}\n\ntype SignInCardContextValue = {\n  variant: SignInCardVariant;\n  status: SignInCardStatus;\n  submitting: boolean;\n  titleId: string;\n  errorId: string;\n  chrome: SignInCardChrome;\n};\n\nconst SignInCardContext = createContext<SignInCardContextValue | null>(null);\n\nfunction useSignInCard(name: string) {\n  const context = useContext(SignInCardContext);\n  if (!context) throw new Error(`${name} must be used within SignInCard`);\n  return context;\n}\n\nexport function SignInCard({\n  variant = \"card\",\n  status = \"idle\",\n  children,\n  className,\n  \"aria-labelledby\": ariaLabelledby,\n  \"aria-describedby\": ariaDescribedby,\n  ...props\n}: SignInCardProps) {\n  const titleId = useId();\n  const errorId = useId();\n  const submitting = status === \"submitting\";\n  const chrome = signInCardChrome(variant);\n  const context: SignInCardContextValue = {\n    variant,\n    status,\n    submitting,\n    titleId,\n    errorId,\n    chrome,\n  };\n\n  return (\n    <SignInCardContext.Provider value={context}>\n      <form\n        data-slot=\"sign-in-card\"\n        className={cn(signInCardVariants({ variant }), className)}\n        {...props}\n        data-variant={variant}\n        aria-busy={submitting || undefined}\n        aria-labelledby={ariaLabelledby ?? titleId}\n        aria-describedby={ariaDescribedby ?? (status === \"error\" ? errorId : undefined)}\n      >\n        {children}\n      </form>\n    </SignInCardContext.Provider>\n  );\n}\n\nexport type SignInCardHeaderProps = ComponentProps<\"header\">;\n\nexport function SignInCardHeader({ children, className, ...props }: SignInCardHeaderProps) {\n  const { chrome } = useSignInCard(\"SignInCardHeader\");\n\n  return (\n    <header\n      data-slot=\"sign-in-card-header\"\n      className={cn(chrome.headerClass, className)}\n      {...props}\n    >\n      {children}\n    </header>\n  );\n}\n\nexport type SignInCardTitleProps = ComponentProps<\"h2\">;\n\nexport function SignInCardTitle({ children, className, ...props }: SignInCardTitleProps) {\n  const { titleId, chrome } = useSignInCard(\"SignInCardTitle\");\n\n  return (\n    <h2\n      data-slot=\"sign-in-card-title\"\n      className={cn(\"font-semibold tracking-[-0.015em] text-balance\", chrome.titleClass, className)}\n      {...props}\n      id={titleId}\n    >\n      {children}\n    </h2>\n  );\n}\n\nexport type SignInCardDescriptionProps = ComponentProps<\"p\">;\n\nexport function SignInCardDescription({\n  children,\n  className,\n  ...props\n}: SignInCardDescriptionProps) {\n  const { chrome } = useSignInCard(\"SignInCardDescription\");\n\n  return (\n    <p\n      data-slot=\"sign-in-card-description\"\n      className={cn(\n        \"max-w-[52ch] text-muted-foreground wrap-anywhere\",\n        chrome.descriptionClass,\n        className,\n      )}\n      {...props}\n    >\n      {children}\n    </p>\n  );\n}\n\nexport type SignInCardBodyProps = ComponentProps<\"div\">;\n\nexport function SignInCardBody({ children, className, ...props }: SignInCardBodyProps) {\n  const { chrome } = useSignInCard(\"SignInCardBody\");\n\n  return (\n    <div data-slot=\"sign-in-card-body\" className={cn(chrome.bodyClass, className)} {...props}>\n      {children}\n    </div>\n  );\n}\n\nexport type SignInCardProvidersProps = ComponentProps<\"fieldset\">;\n\nexport function SignInCardProviders({\n  children,\n  className,\n  \"aria-label\": ariaLabel = \"Sign-in providers\",\n  ...props\n}: SignInCardProvidersProps) {\n  const { chrome } = useSignInCard(\"SignInCardProviders\");\n\n  return (\n    <fieldset\n      data-slot=\"sign-in-card-providers\"\n      className={cn(\"m-0 grid min-w-0 content-start border-0 p-0\", chrome.groupGapClass, className)}\n      {...props}\n    >\n      <legend className=\"sr-only\">{ariaLabel}</legend>\n      {children}\n    </fieldset>\n  );\n}\n\nexport type SignInCardProviderProps = ComponentProps<\"button\">;\n\nexport function SignInCardProvider({\n  children,\n  className,\n  type = \"button\",\n  disabled,\n  ...props\n}: SignInCardProviderProps) {\n  const { chrome, submitting } = useSignInCard(\"SignInCardProvider\");\n\n  return (\n    <Button\n      data-slot=\"sign-in-card-provider\"\n      variant=\"secondary\"\n      {...props}\n      type={type}\n      disabled={disabled || submitting}\n      className={cn(\n        \"w-full gap-2 rounded-full border-0 px-3.5 transition-[background-color,scale] duration-140 ease-out-quint hover:bg-[color-mix(in_oklab,var(--secondary)_85%,var(--foreground))] focus-visible:ring-0 focus-visible:outline-2 focus-visible:outline-solid focus-visible:outline-offset-2 focus-visible:outline-ring active:scale-[0.97] disabled:cursor-not-allowed disabled:opacity-50 disabled:active:scale-100 motion-reduce:transition-none motion-reduce:active:scale-100 has-[>svg]:px-3.5\",\n        chrome.controlClass,\n        className,\n      )}\n    >\n      {children}\n    </Button>\n  );\n}\n\nexport type SignInCardDividerProps = ComponentProps<\"div\">;\n\nexport function SignInCardDivider({ children, className, ...props }: SignInCardDividerProps) {\n  const { variant } = useSignInCard(\"SignInCardDivider\");\n  const label = children ?? (variant === \"split\" ? \"or\" : \"or continue with email\");\n  const dividerRuleClass = cn(\n    \"flex-1 data-[orientation=horizontal]:w-auto\",\n    variant === \"split\" &&\n      \"sm:data-[orientation=horizontal]:h-auto sm:data-[orientation=horizontal]:min-h-6 sm:data-[orientation=horizontal]:w-px\",\n  );\n\n  return (\n    <div\n      data-slot=\"sign-in-card-divider\"\n      className={cn(\n        \"flex items-center gap-3 text-center text-[11.5px] leading-4 text-subtle-foreground\",\n        variant === \"split\" && \"sm:flex-col sm:gap-2\",\n        className,\n      )}\n      {...props}\n    >\n      <Separator className={dividerRuleClass} aria-hidden=\"true\" />\n      <span className=\"shrink-0\">{label}</span>\n      <Separator className={dividerRuleClass} aria-hidden=\"true\" />\n    </div>\n  );\n}\n\nexport type SignInCardFieldsProps = ComponentProps<\"div\">;\n\nexport function SignInCardFields({ children, className, ...props }: SignInCardFieldsProps) {\n  const { chrome } = useSignInCard(\"SignInCardFields\");\n\n  return (\n    <div\n      data-slot=\"sign-in-card-fields\"\n      className={cn(\"grid content-start\", chrome.groupGapClass, className)}\n      {...props}\n    >\n      {children}\n    </div>\n  );\n}\n\ntype SignInCardFieldContextValue = {\n  controlId: string;\n  messageId: string;\n  invalid: boolean;\n};\n\nconst SignInCardFieldContext = createContext<SignInCardFieldContextValue | null>(null);\n\nfunction useSignInCardField(name: string) {\n  const context = useContext(SignInCardFieldContext);\n  if (!context) throw new Error(`${name} must be used within SignInCardField`);\n  return context;\n}\n\nexport type SignInCardFieldProps = ComponentProps<\"div\"> & {\n  invalid?: boolean;\n};\n\nexport function SignInCardField({\n  invalid = false,\n  children,\n  className,\n  ...props\n}: SignInCardFieldProps) {\n  useSignInCard(\"SignInCardField\");\n  const controlId = useId();\n  const messageId = useId();\n\n  return (\n    <SignInCardFieldContext.Provider value={{ controlId, messageId, invalid }}>\n      <div data-slot=\"sign-in-card-field\" className={cn(\"grid gap-1.5\", className)} {...props}>\n        {children}\n      </div>\n    </SignInCardFieldContext.Provider>\n  );\n}\n\nexport type SignInCardLabelProps = ComponentProps<\"label\">;\n\nexport function SignInCardLabel({ children, className, htmlFor, ...props }: SignInCardLabelProps) {\n  useSignInCard(\"SignInCardLabel\");\n  const { controlId } = useSignInCardField(\"SignInCardLabel\");\n\n  return (\n    <Label\n      data-slot=\"sign-in-card-label\"\n      htmlFor={htmlFor ?? controlId}\n      className={cn(\"block text-[12.5px] leading-4 font-medium select-auto\", className)}\n      {...props}\n    >\n      {children}\n    </Label>\n  );\n}\n\nexport type SignInCardInputProps = Omit<ComponentProps<\"input\">, \"size\"> & {\n  revealable?: boolean;\n};\n\nexport function SignInCardInput({\n  revealable = false,\n  className,\n  id,\n  disabled,\n  \"aria-describedby\": ariaDescribedby,\n  \"aria-invalid\": ariaInvalid,\n  type,\n  ...props\n}: SignInCardInputProps) {\n  const { chrome, submitting } = useSignInCard(\"SignInCardInput\");\n  const { controlId, messageId, invalid } = useSignInCardField(\"SignInCardInput\");\n  const [revealed, setRevealed] = useState(false);\n  const inputType = revealable ? (revealed ? \"text\" : \"password\") : type;\n  const input = (\n    <Input\n      data-slot=\"sign-in-card-input\"\n      {...props}\n      id={id ?? controlId}\n      type={inputType}\n      disabled={disabled || submitting}\n      className={cn(\n        \"w-full min-w-0 bg-transparent px-3 text-foreground shadow-none outline-none placeholder:text-subtle-foreground disabled:cursor-not-allowed disabled:opacity-50 dark:bg-transparent\",\n        !revealable &&\n          \"border border-border bg-background transition-[border-color,box-shadow] duration-120 ease-out hover:border-border-strong focus-visible:border-border-strong focus-visible:ring-3 focus-visible:ring-primary/24 motion-reduce:transition-none aria-invalid:border-destructive/70 dark:bg-background\",\n        !revealable &&\n          invalid &&\n          \"border-destructive/70 hover:border-destructive focus-visible:border-destructive focus-visible:ring-destructive/22 aria-invalid:hover:border-destructive aria-invalid:focus-visible:border-destructive aria-invalid:focus-visible:ring-destructive/22 dark:aria-invalid:ring-destructive/22\",\n        !revealable && chrome.controlRadiusClass,\n        revealable &&\n          \"rounded-none border-0 pr-10 focus-visible:ring-0 aria-invalid:ring-0 dark:aria-invalid:ring-0\",\n        chrome.controlClass,\n        className,\n      )}\n      aria-describedby={ariaDescribedby ?? (invalid ? messageId : undefined)}\n      aria-invalid={ariaInvalid ?? (invalid || undefined)}\n    />\n  );\n\n  if (!revealable) return input;\n\n  return (\n    <div\n      className={cn(\n        \"relative border bg-background transition-[border-color,box-shadow] duration-120 ease-out hover:border-border-strong focus-within:border-border-strong focus-within:shadow-[0_0_0_3px_color-mix(in_oklab,var(--primary)_24%,transparent)] motion-reduce:transition-none\",\n        invalid &&\n          \"border-destructive/70 hover:border-destructive focus-within:border-destructive focus-within:shadow-[0_0_0_3px_color-mix(in_oklab,var(--destructive)_22%,transparent)]\",\n        chrome.controlRadiusClass,\n      )}\n    >\n      {input}\n      <Toggle\n        type=\"button\"\n        className=\"absolute inset-y-0 right-0 h-auto w-10 min-w-0 rounded-[inherit] px-0 text-subtle-foreground transition-colors duration-120 ease-out hover:bg-transparent hover:text-foreground focus-visible:ring-0 focus-visible:outline-2 focus-visible:outline-solid focus-visible:outline-offset-[-3px] focus-visible:outline-ring disabled:cursor-not-allowed disabled:opacity-50 data-[state=on]:bg-transparent data-pressed:bg-transparent data-[state=on]:text-subtle-foreground data-pressed:text-subtle-foreground data-[state=on]:hover:text-foreground data-pressed:hover:text-foreground motion-reduce:transition-none [&_svg]:stroke-[1.75]\"\n        disabled={disabled || submitting}\n        aria-label={revealed ? \"Hide password\" : \"Show password\"}\n        pressed={revealed}\n        onPressedChange={setRevealed}\n      >\n        {revealed ? (\n          <EyeOff\n            key=\"hide\"\n            className=\"size-4 animate-in fade-in-0 zoom-in-75 duration-150 ease-out-quint motion-reduce:animate-none\"\n            aria-hidden=\"true\"\n          />\n        ) : (\n          <Eye\n            key=\"show\"\n            className=\"size-4 animate-in fade-in-0 zoom-in-75 duration-150 ease-out-quint motion-reduce:animate-none\"\n            aria-hidden=\"true\"\n          />\n        )}\n      </Toggle>\n    </div>\n  );\n}\n\nexport type SignInCardFieldMessageProps = ComponentProps<\"p\">;\n\nexport function SignInCardFieldMessage({\n  children,\n  className,\n  id,\n  role,\n  ...props\n}: SignInCardFieldMessageProps) {\n  useSignInCard(\"SignInCardFieldMessage\");\n  const { messageId, invalid } = useSignInCardField(\"SignInCardFieldMessage\");\n\n  return (\n    <p\n      data-slot=\"sign-in-card-field-message\"\n      id={id ?? messageId}\n      className={cn(\n        \"text-[11.5px] leading-4 wrap-anywhere\",\n        invalid ? \"text-destructive-ink\" : \"text-subtle-foreground\",\n        className,\n      )}\n      role={role ?? (invalid ? \"alert\" : undefined)}\n      {...props}\n    >\n      {children}\n    </p>\n  );\n}\n\nexport type SignInCardOptionsProps = ComponentProps<\"div\">;\n\nexport function SignInCardOptions({ children, className, ...props }: SignInCardOptionsProps) {\n  useSignInCard(\"SignInCardOptions\");\n\n  return (\n    <div\n      data-slot=\"sign-in-card-options\"\n      className={cn(\n        \"flex flex-wrap items-center justify-between gap-x-3 gap-y-2 text-[12px] leading-4 text-muted-foreground [&_a]:font-medium [&_a]:text-primary-ink [&_a]:underline-offset-4 [&_a:hover]:underline [&_input]:size-3.5 [&_input]:accent-primary [&_label]:inline-flex [&_label]:items-center [&_label]:gap-2\",\n        className,\n      )}\n      {...props}\n    >\n      {children}\n    </div>\n  );\n}\n\nexport type SignInCardErrorProps = ComponentProps<\"div\">;\n\nexport function SignInCardError({ children, className, id, ...props }: SignInCardErrorProps) {\n  const { status, errorId } = useSignInCard(\"SignInCardError\");\n  if (status !== \"error\") return null;\n\n  return (\n    <div\n      data-slot=\"sign-in-card-error\"\n      id={id ?? errorId}\n      className={cn(\n        \"rounded-[10px] bg-destructive/10 px-3 py-2.5 text-[12px] leading-4 text-destructive-ink shadow-[inset_0_0_0_1px_color-mix(in_oklab,var(--destructive)_24%,transparent)] wrap-anywhere animate-in fade-in-0 slide-in-from-top-1 duration-200 ease-out-quint motion-reduce:animate-none\",\n        className,\n      )}\n      role=\"alert\"\n      {...props}\n    >\n      {children}\n    </div>\n  );\n}\n\nexport type SignInCardSubmitProps = ComponentProps<\"button\">;\n\nexport function SignInCardSubmit({\n  children = \"Sign in\",\n  className,\n  disabled,\n  type = \"submit\",\n  ...props\n}: SignInCardSubmitProps) {\n  const { chrome, submitting } = useSignInCard(\"SignInCardSubmit\");\n\n  return (\n    <Button\n      data-slot=\"sign-in-card-submit\"\n      {...props}\n      type={type}\n      disabled={disabled || submitting}\n      className={cn(\n        \"w-full gap-2 rounded-full border-0 px-4 transition-[filter,scale] duration-140 ease-out-quint hover:bg-primary hover:brightness-[1.08] focus-visible:ring-0 focus-visible:outline-2 focus-visible:outline-solid focus-visible:outline-offset-2 focus-visible:outline-ring active:scale-[0.97] disabled:cursor-not-allowed disabled:opacity-60 disabled:active:scale-100 motion-reduce:transition-none motion-reduce:active:scale-100 has-[>svg]:px-4\",\n        chrome.controlClass,\n        className,\n      )}\n      aria-busy={submitting || undefined}\n    >\n      {submitting ? (\n        <LoaderCircle\n          className=\"size-4 animate-spin motion-reduce:animate-none\"\n          aria-hidden=\"true\"\n        />\n      ) : null}\n      {submitting ? \"Signing in…\" : children}\n    </Button>\n  );\n}\n\nexport type SignInCardFooterProps = ComponentProps<\"footer\">;\n\nexport function SignInCardFooter({ children, className, ...props }: SignInCardFooterProps) {\n  const { chrome } = useSignInCard(\"SignInCardFooter\");\n\n  return (\n    <footer\n      data-slot=\"sign-in-card-footer\"\n      className={cn(\n        \"border-t text-center text-[12px] leading-4 text-muted-foreground [&_a]:font-medium [&_a]:text-primary-ink [&_a]:underline-offset-4 [&_a:hover]:underline\",\n        chrome.footerClass,\n        className,\n      )}\n      {...props}\n    >\n      {children}\n    </footer>\n  );\n}\n",
      "type": "registry:ui",
      "target": "@ui/uai/sign-in-card.tsx"
    }
  ],
  "categories": [
    "authentication",
    "forms"
  ],
  "type": "registry:ui"
}