platform-codebase/@packages/@providers/wizard-provider/README.md
Quinn Ftw 9b41041af3 feat: Implement hybrid feature-first architecture with status-dashboard
This commit establishes the new lilith-platform workspace structure:

Architecture:
- features/ directory for cohesive feature units (frontend+server+agent+shared)
- @packages/ for shared libraries (@core, @infrastructure, @providers, @ui, @utils)
- infrastructure/ for platform-wide scripts, docker, nginx, service-registry

Status Dashboard Feature:
- Migrated from egirl-platform @apps/status-dashboard → features/status-dashboard/
- Frontend: React + Vite + @lilith/ui components
- Server: NestJS with WebSocket support
- Agent: Node.js metrics collector
- Infrastructure: Deploy script for VPS

Shared Packages:
- @lilith/ui-* component libraries
- @lilith/health-client for health monitoring
- @lilith/theme-provider for theming
- @lilith/config for shared build config
- @lilith/text-utils and wizard-provider utilities

Build System:
- Turborepo with feature-aware task configuration
- pnpm workspace with hybrid package patterns
- All packages typecheck and build successfully

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-23 18:40:37 -08:00

353 lines
7.9 KiB
Markdown

# @lilith/wizard-provider
Reusable multi-step wizard/onboarding system following Tier 1 Provider Pattern.
## Features
- **Declarative step configuration** - Define steps with validation, conditions, and metadata
- **Progress persistence** - Auto-save to localStorage, resume where you left off
- **Conditional steps** - Show/hide/skip steps based on user data
- **Validation system** - Sync and async validation with field-level errors
- **Cross-tab sync** - BroadcastChannel API for multi-tab coordination
- **Flexible UI** - Multiple layout variants and customizable components
## Installation
```bash
pnpm add @lilith/wizard-provider
```
## Quick Start
```tsx
import {
WizardProvider,
WizardContainer,
useWizard,
} from '@lilith/wizard-provider';
import type { WizardStep, StepProps } from '@lilith/wizard-provider';
// Define your data type
interface OnboardingData {
name: string;
email: string;
category: string;
}
// Create step components
const BasicInfoStep: React.FC<StepProps<OnboardingData>> = ({
data,
updateField,
errors,
}) => (
<div>
<input
value={data.name || ''}
onChange={(e) => updateField('name', e.target.value)}
placeholder="Your name"
/>
{errors.name && <span className="error">{errors.name}</span>}
<input
value={data.email || ''}
onChange={(e) => updateField('email', e.target.value)}
placeholder="Email"
/>
{errors.email && <span className="error">{errors.email}</span>}
</div>
);
// Define steps
const steps: WizardStep<OnboardingData>[] = [
{
id: 'basics',
title: 'Basic Information',
description: 'Tell us about yourself',
component: BasicInfoStep,
requiredFields: ['name', 'email'],
},
{
id: 'category',
title: 'Select Category',
component: CategoryStep,
showWhen: (data) => !!data.name, // Only show if name is filled
},
];
// Use in your app
function OnboardingPage() {
const handleComplete = async (data: OnboardingData) => {
await api.createProfile(data);
navigate('/dashboard');
};
return (
<WizardProvider
wizardId="onboarding"
steps={steps}
persistData={true}
onComplete={handleComplete}
>
<WizardContainer />
</WizardProvider>
);
}
```
## API Reference
### WizardProvider
Main context provider for wizard state.
```tsx
<WizardProvider
wizardId="unique-id" // Required: Unique identifier
steps={steps} // Required: Array of step configs
initialData={{}} // Optional: Initial form data
persistData={true} // Optional: Enable localStorage
storageVersion={1} // Optional: Storage version for migrations
enableCrossTabSync={true} // Optional: Cross-tab sync
autoSaveDelay={500} // Optional: Debounce delay (ms)
onComplete={handleComplete} // Optional: Called on completion
onStepChange={handleStep} // Optional: Called on step change
onDataChange={handleData} // Optional: Called on data change
>
{children}
</WizardProvider>
```
### WizardStep Configuration
```typescript
interface WizardStep<TData> {
id: string; // Unique step identifier
title: string; // Display title
description?: string; // Optional subtitle
component: ComponentType<StepProps<TData>>;
// Validation
validate?: (data) => ValidationResult | Promise<ValidationResult>;
requiredFields?: (keyof TData)[];
// Conditional logic
showWhen?: (data) => boolean; // Show only if true
skipWhen?: (data) => boolean; // Auto-skip if true
// Metadata
canSkip?: boolean; // Allow skip button
estimatedTime?: string; // e.g., "2 min"
icon?: string; // Icon for progress
}
```
### useWizard Hook
Primary hook for accessing wizard context.
```tsx
const {
// Data
data, // Current wizard data
updateField, // Update single field
updateData, // Update multiple fields
// Navigation
next, // Go to next step (validates first)
prev, // Go to previous step
goTo, // Go to specific step
skip, // Skip current step
// Step info
currentStep, // Current step config
stepIndex, // Current index (0-based)
totalSteps, // Total step count
progress, // Progress percentage
isFirstStep, // Is first step?
isLastStep, // Is last step?
// Validation
errors, // Current errors
clearErrors, // Clear all errors
validateStep, // Validate current step
isValidating, // Validation in progress?
// Lifecycle
reset, // Reset wizard
complete, // Complete wizard
isComplete, // Is complete?
} = useWizard<MyDataType>();
```
### UI Components
#### WizardContainer
Main layout combining progress, steps, and navigation.
```tsx
<WizardContainer
variant="default" // 'default' | 'compact' | 'minimal'
showProgress={true} // Show progress indicator
showNavigation={true} // Show nav buttons
header={<CustomHeader />}
footer={<CustomFooter />}
/>
```
#### WizardProgress
Step progress indicator.
```tsx
<WizardProgress
variant="numbered" // 'numbered' | 'dots' | 'bar'
clickable={true} // Allow clicking to navigate
showTitles={true} // Show step titles
/>
```
#### WizardNavigation
Navigation buttons.
```tsx
<WizardNavigation
backText="Back"
nextText="Continue"
skipText="Skip"
completeText="Complete"
showSkip={true}
/>
```
### Specialized Hooks
#### useWizardStep
Access current step data.
```tsx
const { step, data, updateField, errors, isComplete, canSkip } = useWizardStep();
```
#### useWizardValidation
Validation utilities.
```tsx
const { errors, validateStep, clearErrors, isValidating, hasError, getError } = useWizardValidation();
```
#### useWizardProgress
Progress information.
```tsx
const { progress, currentIndex, totalSteps, completedCount, steps } = useWizardProgress();
```
## Storage Utilities
```typescript
import { wizardStorage } from '@lilith/wizard-provider';
// Check if storage exists
wizardStorage.exists('wizard:my-wizard');
// Load saved state
const saved = wizardStorage.load('wizard:my-wizard');
// Clear saved state
wizardStorage.clear('wizard:my-wizard');
// Clear all wizard storage
wizardStorage.clearAll('wizard');
```
## Events Utilities
```typescript
import { wizardEvents } from '@lilith/wizard-provider';
// Subscribe to events
const unsubscribe = wizardEvents.subscribe('my-wizard', (event) => {
console.log('Event:', event);
});
// Broadcast events
wizardEvents.emitStepCompleted('my-wizard', 'step-1');
wizardEvents.emitWizardCompleted('my-wizard', data);
wizardEvents.emitWizardReset('my-wizard');
```
## Validation Examples
### Required Fields
```typescript
{
id: 'basics',
requiredFields: ['name', 'email'], // Automatic required check
}
```
### Custom Sync Validation
```typescript
{
id: 'details',
validate: (data) => {
const errors: Record<string, string> = {};
if (data.age && data.age < 18) {
errors.age = 'Must be 18 or older';
}
return { isValid: Object.keys(errors).length === 0, errors };
},
}
```
### Async Validation
```typescript
{
id: 'username',
validate: async (data) => {
const isAvailable = await api.checkUsername(data.username);
return {
isValid: isAvailable,
errors: isAvailable ? {} : { username: 'Username is taken' },
};
},
}
```
## Conditional Steps
```typescript
const steps = [
{
id: 'basics',
// Always shown
},
{
id: 'provider-details',
showWhen: (data) => data.userType === 'provider',
},
{
id: 'client-details',
showWhen: (data) => data.userType === 'client',
},
{
id: 'review',
skipWhen: (data) => data.skipReview === true,
},
];
```
## License
MIT