npm package: @neuralsea/react-wizard
Description: Customizable wizard control for React 19+ with TypeScript 5+
Author: Your Name
Latest version: 1.0.1

# React Wizard Control

[![npm version](https://badge.fury.io/js/%40neuralsea%2Freact-wizard.svg)](https://badge.fury.io/js/%40neuralsea%2Freact-wizard)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

A production-grade, fully customisable wizard/stepper component for React 19+ and TypeScript 5+. Designed for complex workflows with built-in support for VS Code extensions, theming, validation, and accessibility.

## Features

- Type-safe: comprehensive TypeScript 5+ definitions
- Fully customisable: theme system with VS Code integration
- Accessible: keyboard navigation and ARIA-friendly components
- Framework-agnostic: suitable for web apps and VS Code webviews
- Dual format: ESM and CommonJS builds
- State persistence: optional localStorage integration
- Performant: optimised hook-based architecture

## Installation

```bash
npm install @neuralsea/react-wizard
# or
yarn add @neuralsea/react-wizard
# or
pnpm add @neuralsea/react-wizard
```

## Quick start

```tsx
import { Wizard } from '@neuralsea/react-wizard';
import type { StepComponentProps, WizardStep } from '@neuralsea/react-wizard';
import '@neuralsea/react-wizard/styles';

type WizardData = {
  name?: string;
  newsletter?: boolean;
};

const PersonalInfoStep: React.FC<StepComponentProps<WizardData>> = ({
  data,
  updateData,
}) => (
  <div>
    <h2>Personal information</h2>
    <input
      type="text"
      value={data.name || ''}
      onChange={(e) => void updateData({ name: e.target.value })}
      placeholder="Your name"
    />
  </div>
);

const PreferencesStep: React.FC<StepComponentProps<WizardData>> = ({
  data,
  updateData,
}) => (
  <div>
    <h2>Preferences</h2>
    <label>
      <input
        type="checkbox"
        checked={data.newsletter || false}
        onChange={(e) => void updateData({ newsletter: e.target.checked })}
      />
      Subscribe to newsletter
    </label>
  </div>
);

const steps: WizardStep[] = [
  {
    id: 'personal',
    title: 'Personal info',
    description: 'Tell us about yourself',
    component: PersonalInfoStep,
    validate: async () => true,
  },
  {
    id: 'preferences',
    title: 'Preferences',
    component: PreferencesStep,
  },
];

export function App() {
  return (
    <Wizard
      steps={steps}
      onComplete={(data) => {
        console.log('Wizard completed with data:', data);
      }}
    />
  );
}
```

## Core concepts

### Step definition

Each step is defined by `WizardStep`:

```ts
interface WizardStep {
  id: string;
  title: string;
  description?: string;
  component: ComponentType<StepComponentProps>;
  validate?: () =>
    | boolean
    | { valid: boolean; error?: string }
    | Promise<boolean | { valid: boolean; error?: string }>;
  canSkip?: boolean;
  icon?: ComponentType<{ size?: number }>;
  optional?: boolean;
}
```

### Step components

Step components receive these props:

```ts
interface StepComponentProps<TData = any> {
  data: TData;
  updateData: (updates: Partial<TData>) => void | Promise<void>;
  goToStep: (stepId: string) => void;
  goNext?: () => Promise<void>;
  goPrevious?: () => void;
}
```

## Theming

### Default theme

```tsx
<Wizard
  steps={steps}
  theme={{
    primary: '#3b82f6',
    primaryHover: '#2563eb',
    success: '#10b981',
    error: '#ef4444',
    radius: '0.5rem',
  }}
/>
```

### VS Code theme

For VS Code extensions:

```tsx
import { vscodeTheme } from '@neuralsea/react-wizard';

<Wizard steps={steps} theme={vscodeTheme} />;
```

## Advanced usage

### Custom layout

Take full control of layout:

```tsx
import {
  Wizard,
  StepIndicator,
  StepContent,
  Navigation,
} from '@neuralsea/react-wizard';

export function CustomWizard() {
  return (
    <Wizard steps={steps}>
      <div className="custom-layout">
        <aside>
          <StepIndicator />
        </aside>
        <main>
          <StepContent />
          <Navigation />
        </main>
      </div>
    </Wizard>
  );
}
```

### Using the hook

Access wizard context in nested components:

```tsx
import { useWizard } from '@neuralsea/react-wizard';

type WizardData = { name: string };

export function CustomComponent() {
  const { steps, currentStepIndex, data, goNext, isLastStep } =
    useWizard<WizardData>();

  return (
    <div>
      <p>
        Step {currentStepIndex + 1} of {steps.length}
      </p>
      <p>Name: {data.name}</p>
      <button onClick={() => void goNext()} disabled={isLastStep}>
        Next
      </button>
    </div>
  );
}
```

### Higher-order components

Wrap step components with wizard capabilities:

```tsx
import { withWizardStep, withValidation } from '@neuralsea/react-wizard';
import type { StepComponentProps, ValidationResult } from '@neuralsea/react-wizard';

interface MyData {
  email: string;
}

const MyStep: React.FC<StepComponentProps<MyData>> = ({ data, updateData }) => (
  <input value={data.email} onChange={(e) => void updateData({ email: e.target.value })} />
);

const validate = (data: MyData): ValidationResult =>
  data.email.includes('@') ? { valid: true } : { valid: false, error: 'Invalid email' };

export default withValidation(withWizardStep<MyData>(MyStep), validate);
```

### Validation

Validation supports booleans or structured error messages:

```tsx
const steps: WizardStep[] = [
  {
    id: 'email',
    title: 'Email',
    component: EmailStep,
    validate: () => {
      if (!data.email) return { valid: false, error: 'Email is required' };
      if (!data.email.includes('@')) return { valid: false, error: 'Invalid email format' };
      return { valid: true };
    },
  },
];
```

### State persistence

```tsx
<Wizard
  steps={steps}
  persistData
  storageKey="my-wizard-data"
  onComplete={(data) => {
    localStorage.removeItem('my-wizard-data');
  }}
/>;
```

### Keyboard navigation

Enabled by default:

- Alt + Right Arrow: next step
- Alt + Left Arrow: previous step

Disable keyboard navigation:

```tsx
<Wizard steps={steps} keyboardNavigation={false} />
```

## Accessibility

The wizard supports:

- ARIA labels and roles
- Keyboard navigation
- Screen reader-friendly structure
- Reduced motion preferences

## Licence

MIT. See `LICENSE`.