npm package: @haykal/auth-ui
Description: Haykal Auth UI — Reusable authentication screens, forms, and flows
Latest version: 1.0.0

# @haykal/auth-ui

> Pre-built authentication UI components for React — login, registration, password reset, email verification, and session management screens using a **controlled/uncontrolled** pattern.

## Installation

```bash
pnpm add @haykal/auth-ui
```

**Peer dependencies:** `@haykal/auth-client`, `@haykal/ui`, `react`, `react-hook-form`, `zod`

## Architecture

The package follows a **two-tier pattern** with smart screens:

1. **Forms** — Pure presentational form components with `react-hook-form` + Zod validation
2. **Screens** — Card-wrapped layouts that work in two modes:
   - **Uncontrolled (default)** — Handles API calls internally via `@haykal/auth-client`
   - **Controlled** — Parent manages API calls by providing `onSubmit`, `error`, and `isLoading` props

```
Forms (presentational, controlled by props)
  └── Screens (smart — uncontrolled by default, controllable via props)
```

This follows the same pattern as React's `<input>` element — works standalone by default, but can be controlled when needed.

## Key Exports

### Screens (Smart Components)

Every screen component supports both **uncontrolled** (default, handles API internally) and **controlled** (parent manages API) modes.

| Export                 | Description                   | Uncontrolled Hook                                    |
| ---------------------- | ----------------------------- | ---------------------------------------------------- |
| `LoginScreen`          | Login with email + password   | `useAuth().login()`                                  |
| `RegisterScreen`       | User registration             | `useAuth().register()`                               |
| `ForgotPasswordScreen` | Request password reset email  | `useAuthControllerForgotPassword()`                  |
| `ResetPasswordScreen`  | Reset password with token     | `useAuthControllerResetPassword()`                   |
| `ChangePasswordScreen` | Authenticated password change | `useAuthControllerChangePassword()`                  |
| `VerifyEmailScreen`    | Email verification with token | `useAuthControllerVerifyEmail()`                     |
| `SessionsScreen`       | Active session management     | `useAuthControllerListSessions()` + revoke mutations |

### Forms

| Export               | Description                              |
| -------------------- | ---------------------------------------- |
| `LoginForm`          | Email + password form                    |
| `RegisterForm`       | Registration form with password strength |
| `ForgotPasswordForm` | Email input for reset request            |
| `ResetPasswordForm`  | New password form                        |
| `ChangePasswordForm` | Current + new password form              |
| `VerifyEmailForm`    | Token verification form                  |

### UI Components

| Export                      | Description                               |
| --------------------------- | ----------------------------------------- |
| `AuthCardLayout`            | Centered card wrapper for auth pages      |
| `AuthErrorAlert`            | Error display with auth-specific messages |
| `OAuthButton`               | Social login button                       |
| `PasswordStrengthIndicator` | Visual password strength meter            |
| `SessionCard`               | Session info display with revoke action   |

### Auth Flow

| Export              | Description                                            |
| ------------------- | ------------------------------------------------------ |
| `AuthFlow`          | Route-agnostic state machine for multi-step auth flows |
| `AuthFlowStep`      | Enum of auth steps (login, register, verify, etc.)     |
| `AuthFlowCallbacks` | Callback interface for auth flow transitions           |

### Hooks

| Export                | Description                                   |
| --------------------- | --------------------------------------------- |
| `useAuthErrorMessage` | Convert error codes to user-friendly messages |
| `usePasswordStrength` | Calculate password strength score             |

### Zod Schemas

| Export                 | Description                   |
| ---------------------- | ----------------------------- |
| `loginSchema`          | Login form validation         |
| `registerSchema`       | Registration validation       |
| `forgotPasswordSchema` | Forgot password validation    |
| `resetPasswordSchema`  | Reset password validation     |
| `changePasswordSchema` | Change password validation    |
| `verifyEmailSchema`    | Email verification validation |

## Usage Examples

### Uncontrolled Mode (Default — Quickest Setup)

Screens handle API calls internally. Just provide callbacks for navigation:

```tsx
// app/(auth)/login/page.tsx
import { LoginScreen } from '@haykal/auth-ui';

export default function LoginPage() {
  const router = useRouter();

  return (
    <LoginScreen
      onSuccess={() => router.push('/dashboard')}
      onForgotPassword={() => router.push('/forgot-password')}
      onRegister={() => router.push('/register')}
    />
  );
}
```

### Controlled Mode (Custom API Logic)

Pass `onSubmit` to take full control over API calls:

```tsx
import { LoginScreen } from '@haykal/auth-ui';

export default function CustomLoginPage() {
  const customLogin = useMyCustomLogin();

  return (
    <LoginScreen
      onSubmit={async (values) => {
        await customLogin.mutate(values);
        await analytics.track('login_success');
        router.push('/onboarding');
      }}
      error={customLogin.error}
      isLoading={customLogin.isPending}
    />
  );
}
```

### Using the Auth Flow State Machine

```tsx
import { AuthFlow } from '@haykal/auth-ui';

export default function AuthPage() {
  return (
    <AuthFlow
      step="login"
      onNavigate={(event) => router.push(`/auth/${event.step}`)}
      onLoginSuccess={() => router.push('/dashboard')}
      onRegisterSuccess={() => router.push('/verify-email')}
    />
  );
}
```

### Using Forms Directly

For maximum control, use the form components directly:

```tsx
import { LoginForm, loginSchema } from '@haykal/auth-ui';

export default function CustomLogin() {
  return (
    <LoginForm
      onSubmit={async (data) => {
        // data is validated against loginSchema
        await myCustomLogin(data.email, data.password);
      }}
      isLoading={false}
    />
  );
}
```

## Controlled vs Uncontrolled — Quick Reference

| Prop provided? | Mode         | Behavior                                                            |
| -------------- | ------------ | ------------------------------------------------------------------- |
| No `onSubmit`  | Uncontrolled | Screen calls `@haykal/auth-client` hooks internally                 |
| Has `onSubmit` | Controlled   | Screen delegates to your handler, uses your `error` and `isLoading` |

Both modes support `onSuccess` and `onError` callbacks.

## Related Packages

- `@haykal/auth-backend` — Backend auth module
- `@haykal/auth-client` — React Query hooks (`useAuth`, `useCurrentUser`)
- `@haykal/ui` — Base UI component library (shadcn/ui)

## Further Reading

- [Admin App Development](../../../docs/admin-app-development.md) — Building pages in the admin dashboard
- [Client SDK Generation](../../../docs/client-sdk-generation.md) — Orval pipeline and regeneration