# Reform Form Wizard

Reform provides a powerful form wizard system that allows you to create multi-step forms with navigation, validation, and state management. This document covers the form wizard capabilities of Reform.

## Table of Contents

- [Overview](#overview)
- [Basic Usage](#basic-usage)
- [Step Configuration](#step-configuration)
- [Navigation](#navigation)
- [Validation](#validation)
- [Persistence](#persistence)
- [API Reference](#api-reference)

## Overview

Reform's form wizard system allows you to:

1. **Create multi-step forms** with a clear navigation flow
2. **Validate each step** before proceeding to the next
3. **Track completion status** of steps
4. **Customize step behavior** with lifecycle hooks
5. **Persist wizard state** across sessions

## Basic Usage

Here's a basic example of creating a multi-step form wizard:

```tsx
import { useReform, useReformWizard } from '@reform/core';

type UserForm = {
  // Step 1: Personal Information
  firstName: string;
  lastName: string;
  email: string;

  // Step 2: Address
  street: string;
  city: string;
  state: string;
  zipCode: string;

  // Step 3: Account
  username: string;
  password: string;
  confirmPassword: string;
};

const RegistrationForm = () => {
  // Initialize Reform form
  const form = useReform<UserForm>({
    defaultData: {
      firstName: '',
      lastName: '',
      email: '',
      street: '',
      city: '',
      state: '',
      zipCode: '',
      username: '',
      password: '',
      confirmPassword: '',
    },
    minGroups: 1,
  });

  // Initialize wizard with steps
  const wizard = useReformWizard(form, {
    steps: [
      {
        id: 'personal',
        title: 'Personal Information',
        groupIndices: [0], // Use the first form group
        fields: ['firstName', 'lastName', 'email'],
      },
      {
        id: 'address',
        title: 'Address',
        groupIndices: [0],
        fields: ['street', 'city', 'state', 'zipCode'],
      },
      {
        id: 'account',
        title: 'Account Setup',
        groupIndices: [0],
        fields: ['username', 'password', 'confirmPassword'],
      },
    ],
    validateOnNext: true,
  });

  // Handle form submission
  const handleSubmit = (data: any) => {
    console.log('Form submitted:', data);
  };

  return (
    <div className="wizard-container">
      {/* Step indicator */}
      <div className="wizard-steps">
        {wizard.getSteps().map(step => (
          <div
            key={step.id}
            className={`wizard-step ${step.isActive ? 'active' : ''} ${
              step.isCompleted ? 'completed' : ''
            } ${!step.isEnabled ? 'disabled' : ''}`}
            onClick={() => step.isEnabled && wizard.goToStep(step.id)}
          >
            {step.title}
          </div>
        ))}
      </div>

      {/* Current step content */}
      <form onSubmit={form.formMethods.handleSubmit(handleSubmit)}>
        {wizard.currentStep.id === 'personal' && (
          <div className="step-content">
            <h2>Personal Information</h2>
            <div>
              <label>First Name</label>
              <input {...form.register(0, 'firstName')} />
            </div>
            <div>
              <label>Last Name</label>
              <input {...form.register(0, 'lastName')} />
            </div>
            <div>
              <label>Email</label>
              <input {...form.register(0, 'email')} type="email" />
            </div>
          </div>
        )}

        {wizard.currentStep.id === 'address' && (
          <div className="step-content">
            <h2>Address</h2>
            <div>
              <label>Street</label>
              <input {...form.register(0, 'street')} />
            </div>
            <div>
              <label>City</label>
              <input {...form.register(0, 'city')} />
            </div>
            <div>
              <label>State</label>
              <input {...form.register(0, 'state')} />
            </div>
            <div>
              <label>Zip Code</label>
              <input {...form.register(0, 'zipCode')} />
            </div>
          </div>
        )}

        {wizard.currentStep.id === 'account' && (
          <div className="step-content">
            <h2>Account Setup</h2>
            <div>
              <label>Username</label>
              <input {...form.register(0, 'username')} />
            </div>
            <div>
              <label>Password</label>
              <input {...form.register(0, 'password')} type="password" />
            </div>
            <div>
              <label>Confirm Password</label>
              <input {...form.register(0, 'confirmPassword')} type="password" />
            </div>
          </div>
        )}

        {/* Navigation buttons */}
        <div className="wizard-navigation">
          {wizard.canGoPrev && (
            <button type="button" onClick={wizard.prev}>
              Previous
            </button>
          )}

          {wizard.canGoNext ? (
            <button type="button" onClick={wizard.next}>
              Next
            </button>
          ) : (
            <button type="submit">Submit</button>
          )}
        </div>
      </form>
    </div>
  );
};
```

## Step Configuration

Each step in the wizard can be configured with various options:

```tsx
const wizard = useReformWizard(form, {
  steps: [
    {
      id: 'personal',
      title: 'Personal Information',
      groupIndices: [0], // Which form groups this step applies to

      // Optional: Custom validation for this step
      validate: groups => {
        const data = groups[0].data;
        if (!data.email.includes('@')) {
          form.setError(0, 'email', {
            type: 'manual',
            message: 'Invalid email format',
          });
          return false;
        }
        return true;
      },

      // Optional: Custom completion check
      isCompleted: groups => {
        const data = groups[0].data;
        return !!data.firstName && !!data.lastName && !!data.email;
      },

      // Optional: Custom enabled check
      isEnabled: (allGroups, completedSteps) => {
        // This is the first step, so always enabled
        return true;
      },

      // Optional: Lifecycle hooks
      onEnter: groups => {
        console.log('Entering personal information step');
        // You can initialize data or perform side effects
      },

      onLeave: (groups, direction) => {
        console.log(`Leaving personal information step (${direction})`);
        // Return false to prevent leaving the step
        if (direction === 'next' && !groups[0].data.email) {
          alert('Please enter your email before proceeding');
          return false;
        }
        return true;
      },
    },
    // Other steps...
  ],
});
```

## Navigation

The wizard provides several methods for navigation:

```tsx
// Go to the next step (with validation)
wizard.next();

// Go to the previous step
wizard.prev();

// Go to a specific step by ID
wizard.goToStep('address');

// Go to a specific step by index
wizard.goToStepByIndex(1);

// Reset the wizard
wizard.resetWizard({
  resetFormData: true, // Also reset form data
  clearCompletedSteps: true, // Clear completed steps status
});
```

## Validation

You can control validation behavior with configuration options:

```tsx
const wizard = useReformWizard(form, {
  steps: [...],

  // Validate the current step before proceeding to the next
  validateOnNext: true,

  // Allow skipping to any step (even if previous steps are not completed)
  allowSkipSteps: false,

  // Mark steps as completed when leaving them (if valid)
  markCompletedOnLeave: true,
});
```

## Persistence

The wizard can persist its state across sessions:

```tsx
const wizard = useReformWizard(form, {
  steps: [...],

  // Enable state persistence
  persistState: true,

  // Custom storage key
  persistStateKey: 'my-registration-wizard',

  // Callbacks
  onStepCompleted: (stepId, groups) => {
    console.log(`Step ${stepId} completed`);
    analytics.trackStepCompletion(stepId);
  },

  onWizardCompleted: (groups) => {
    console.log('Wizard completed');
    analytics.trackWizardCompletion();
  },
});
```

## API Reference

### useReformWizard

```typescript
function useReformWizard<T extends Record<string, any>>(
  reform: ReformReturn<T>,
  config: FormWizardConfig<T>
): FormWizardReturn<T>;
```

#### FormWizardConfig

| Option               | Type                                               | Default                 | Description                             |
| -------------------- | -------------------------------------------------- | ----------------------- | --------------------------------------- |
| steps                | `FormStep<T>[]`                                    | Required                | Array of step configurations            |
| initialStepId        | `string`                                           | First step ID           | ID of the initial step                  |
| validateOnNext       | `boolean`                                          | `true`                  | Validate current step before proceeding |
| allowSkipSteps       | `boolean`                                          | `false`                 | Allow skipping to any step              |
| markCompletedOnLeave | `boolean`                                          | `true`                  | Mark steps as completed when leaving    |
| persistState         | `boolean`                                          | `false`                 | Persist wizard state to localStorage    |
| persistStateKey      | `string`                                           | `'reform-wizard-state'` | Storage key for persistence             |
| onStepCompleted      | `(stepId: string, groups: FormGroup<T>[]) => void` | `undefined`             | Callback when a step is completed       |
| onWizardCompleted    | `(groups: FormGroup<T>[]) => void`                 | `undefined`             | Callback when all steps are completed   |

#### FormStep

| Property     | Type                                                                                   | Description                                 |
| ------------ | -------------------------------------------------------------------------------------- | ------------------------------------------- |
| id           | `string`                                                                               | Unique identifier for the step              |
| title        | `string`                                                                               | Display title for the step                  |
| groupIndices | `number[]`                                                                             | Indices of form groups this step applies to |
| fields       | `(keyof T)[]`                                                                          | Optional list of fields in this step        |
| validate     | `(groups: FormGroup<T>[]) => boolean \| Promise<boolean>`                              | Custom validation function                  |
| isCompleted  | `(groups: FormGroup<T>[]) => boolean`                                                  | Custom completion check                     |
| isEnabled    | `(allGroups: FormGroup<T>[], completedSteps: string[]) => boolean`                     | Custom enabled check                        |
| onEnter      | `(groups: FormGroup<T>[]) => void \| Promise<void>`                                    | Called when entering the step               |
| onLeave      | `(groups: FormGroup<T>[], direction: 'next' \| 'prev') => boolean \| Promise<boolean>` | Called when leaving the step                |

#### FormWizardReturn

| Property/Method      | Type                                                                                                               | Description                           |
| -------------------- | ------------------------------------------------------------------------------------------------------------------ | ------------------------------------- |
| steps                | `FormStep<T>[]`                                                                                                    | Array of step configurations          |
| currentStep          | `FormStep<T>`                                                                                                      | Current active step                   |
| currentStepId        | `string`                                                                                                           | ID of current step                    |
| completedSteps       | `string[]`                                                                                                         | IDs of completed steps                |
| isCompleted          | `boolean`                                                                                                          | Whether all steps are completed       |
| isValidating         | `boolean`                                                                                                          | Whether validation is in progress     |
| isTransitioning      | `boolean`                                                                                                          | Whether transitioning between steps   |
| isStepCompleted      | `(stepId: string) => boolean`                                                                                      | Check if a step is completed          |
| isStepEnabled        | `(stepId: string) => boolean`                                                                                      | Check if a step is enabled            |
| isCurrentStep        | `(stepId: string) => boolean`                                                                                      | Check if a step is the current step   |
| markStepCompleted    | `(stepId: string) => void`                                                                                         | Mark a step as completed              |
| markStepNotCompleted | `(stepId: string) => void`                                                                                         | Mark a step as not completed          |
| validateStep         | `(stepId: string) => Promise<boolean>`                                                                             | Validate a specific step              |
| goToStep             | `(stepId: string) => Promise<boolean>`                                                                             | Navigate to a specific step           |
| next                 | `() => Promise<boolean>`                                                                                           | Navigate to the next step             |
| prev                 | `() => Promise<boolean>`                                                                                           | Navigate to the previous step         |
| canGoNext            | `boolean`                                                                                                          | Whether can navigate to next step     |
| canGoPrev            | `boolean`                                                                                                          | Whether can navigate to previous step |
| resetWizard          | `(options?: { resetFormData?: boolean; clearCompletedSteps?: boolean }) => void`                                   | Reset the wizard                      |
| getSteps             | `() => Array<FormStep<T> & { isActive: boolean; isCompleted: boolean; isEnabled: boolean }>`                       | Get all steps with status             |
| getStep              | `(stepId: string) => (FormStep<T> & { isActive: boolean; isCompleted: boolean; isEnabled: boolean }) \| undefined` | Get a specific step with status       |
| getCurrentStep       | `() => FormStep<T> & { isActive: boolean; isCompleted: boolean; isEnabled: boolean }`                              | Get current step with status          |
| getStepGroups        | `(step: FormStep<T>) => FormGroup<T>[]`                                                                            | Get form groups for a step            |
| getStepIndex         | `(stepId: string) => number`                                                                                       | Get index of a step                   |
| getCurrentStepIndex  | `() => number`                                                                                                     | Get index of current step             |
| goToStepByIndex      | `(index: number) => Promise<boolean>`                                                                              | Navigate to a step by index           |
