wizzard-stepper-react 1.3.1 โ 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +239 -34
- package/dist/index.cjs +482 -125
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +191 -23
- package/dist/index.d.ts +191 -23
- package/dist/index.js +484 -125
- package/dist/index.js.map +1 -1
- package/package.json +11 -7
package/README.md
CHANGED
|
@@ -5,7 +5,8 @@ A flexible, headless, and strictly typed multi-step wizard library for React. Bu
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
7
|
- ๐ง **Headless Architecture**: Full control over UI. You bring the components, we provide the logic.
|
|
8
|
-
- ๐ **Adapter Pattern**:
|
|
8
|
+
- ๐ **Adapter Pattern**: Zero-dependency adapters for **Zod**, **Yup** validation. No hard dependencies on these libraries in the core.
|
|
9
|
+
- ๐๏ธ **Complex Data**: Built-in support for nested objects and arrays using dot notation (`users[0].name`).
|
|
9
10
|
- ๐ก๏ธ **Strictly Typed**: Built with TypeScript generics for type safety across steps.
|
|
10
11
|
- ๐ **Conditional Steps**: Dynamic pipelines where steps can be skipped based on data.
|
|
11
12
|
- ๐พ **Persistence**: Auto-save progress to LocalStorage or custom stores.
|
|
@@ -21,51 +22,61 @@ yarn add wizzard-stepper-react
|
|
|
21
22
|
pnpm add wizzard-stepper-react
|
|
22
23
|
```
|
|
23
24
|
|
|
24
|
-
##
|
|
25
|
+
## Usage
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
import { WizardProvider, useWizard, IWizardConfig } from 'wizzard-stepper-react';
|
|
27
|
+
### 1. Basic Usage (Compatible & Simple)
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
{ id: 'contact', label: 'Contact Details' },
|
|
34
|
-
],
|
|
35
|
-
};
|
|
29
|
+
The quickest way to get started. Types are flexible (`any`).
|
|
30
|
+
|
|
31
|
+
```tsx
|
|
32
|
+
import { WizardProvider, useWizard } from 'wizzard-stepper-react';
|
|
36
33
|
|
|
37
|
-
// 2. Create Steps
|
|
38
34
|
const Step1 = () => {
|
|
39
|
-
const {
|
|
35
|
+
const { wizardData, handleStepChange } = useWizard();
|
|
40
36
|
return (
|
|
41
37
|
<input
|
|
42
|
-
value={wizardData.name
|
|
43
|
-
onChange={e => handleStepChange('name', e.target.value)}
|
|
38
|
+
value={wizardData.name}
|
|
39
|
+
onChange={(e) => handleStepChange('name', e.target.value)}
|
|
44
40
|
/>
|
|
45
41
|
);
|
|
46
42
|
};
|
|
47
43
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
44
|
+
const App = () => (
|
|
45
|
+
<WizardProvider>
|
|
46
|
+
<Step1 />
|
|
47
|
+
</WizardProvider>
|
|
48
|
+
);
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### 2. Strict Usage (Factory Pattern ๐ญ)
|
|
52
|
+
|
|
53
|
+
For production apps, use the factory pattern to get perfect type inference.
|
|
54
|
+
|
|
55
|
+
**`wizards/my-wizard.ts`**
|
|
56
|
+
```typescript
|
|
57
|
+
import { createWizardFactory } from 'wizzard-stepper-react';
|
|
58
|
+
|
|
59
|
+
interface MySchema {
|
|
60
|
+
name: string;
|
|
61
|
+
age: number;
|
|
55
62
|
}
|
|
56
63
|
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
)
|
|
64
|
+
export const { WizardProvider, useWizard } = createWizardFactory<MySchema>();
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**`components/MyForm.tsx`**
|
|
68
|
+
```tsx
|
|
69
|
+
import { useWizard } from '../wizards/my-wizard';
|
|
70
|
+
|
|
71
|
+
const Step1 = () => {
|
|
72
|
+
const { wizardData } = useWizard();
|
|
73
|
+
// โ
wizardData is strictly typed as MySchema
|
|
74
|
+
// โ
Autocomplete works for wizardData.name
|
|
66
75
|
}
|
|
67
76
|
```
|
|
68
77
|
|
|
78
|
+
See [MIGRATION.md](./MIGRATION.md) for details on switching to strict mode.
|
|
79
|
+
|
|
69
80
|
## Integration with React Hook Form + Zod
|
|
70
81
|
|
|
71
82
|
```tsx
|
|
@@ -97,12 +108,94 @@ const config = {
|
|
|
97
108
|
{
|
|
98
109
|
id: 'step1',
|
|
99
110
|
label: 'Email',
|
|
100
|
-
|
|
111
|
+
// Zero-dependency: works with any Zod version
|
|
112
|
+
validationAdapter: new ZodAdapter(schema)
|
|
101
113
|
}
|
|
102
114
|
]
|
|
103
115
|
}
|
|
104
116
|
```
|
|
105
117
|
|
|
118
|
+
## Complex Data (Arrays & Objects)
|
|
119
|
+
|
|
120
|
+
The library provides `setData` and `getData` helpers that support deep paths using dot notation and array brackets.
|
|
121
|
+
|
|
122
|
+
```tsx
|
|
123
|
+
const { setData, wizardData } = useWizard<MyData>();
|
|
124
|
+
|
|
125
|
+
// Set nested object property
|
|
126
|
+
setData('user.profile.name', 'John');
|
|
127
|
+
|
|
128
|
+
// Set array item property
|
|
129
|
+
setData('items[0].value', 'New Value');
|
|
130
|
+
|
|
131
|
+
// Get with default value
|
|
132
|
+
const name = getData('user.profile.name', 'Anonymous');
|
|
133
|
+
|
|
134
|
+
// ๐ Bulk Update (Autofill)
|
|
135
|
+
const autoFillParams = () => {
|
|
136
|
+
// Merges into existing data
|
|
137
|
+
updateData({
|
|
138
|
+
name: 'John Doe',
|
|
139
|
+
email: 'john@example.com'
|
|
140
|
+
});
|
|
141
|
+
};
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Performance & Optimization ๐
|
|
145
|
+
|
|
146
|
+
For large forms (e.g., 50+ array items), using `useWizard` context can cause performance issues because it triggers a re-render on every keystroke. To solve this, we provide **granular hooks** that allow components to subscribe only to the specific data they need.
|
|
147
|
+
|
|
148
|
+
### 1. Use `useWizardValue` for Granular Updates
|
|
149
|
+
|
|
150
|
+
Instead of reading the whole `wizardData`, subscribe to a single field. The component will only re-render when *that specific field* changes.
|
|
151
|
+
|
|
152
|
+
```tsx
|
|
153
|
+
// โ
FAST: Only re-renders when "users[0].name" changes
|
|
154
|
+
const NameInput = () => {
|
|
155
|
+
// Subscribe to specific path
|
|
156
|
+
const name = useWizardValue('users[0].name');
|
|
157
|
+
const { setData } = useWizardActions(); // Component actions don't trigger re-renders
|
|
158
|
+
|
|
159
|
+
return <input value={name} onChange={e => setData('users[0].name', e.target.value)} />;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// โ SLOW: Re-renders on ANY change in the form
|
|
163
|
+
const NameInputSlow = () => {
|
|
164
|
+
const { wizardData, setData } = useWizard();
|
|
165
|
+
return <input value={wizardData.users[0].name} ... />;
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### 2. Use `useWizardSelector` for Lists
|
|
170
|
+
|
|
171
|
+
When rendering lists, avoid passing the whole `children` array to the parent component. Instead, select only IDs and let child components fetch their own data.
|
|
172
|
+
|
|
173
|
+
```tsx
|
|
174
|
+
const ChildrenList = () => {
|
|
175
|
+
// โ
Only re-renders when the list LENGTH changes or IDs change
|
|
176
|
+
const childIds = useWizardSelector(state => state.children.map(c => c.id));
|
|
177
|
+
|
|
178
|
+
return (
|
|
179
|
+
<div>
|
|
180
|
+
{childIds.map((id, index) => (
|
|
181
|
+
// Pass ID/Index, NOT the data object
|
|
182
|
+
<ChildRow key={id} index={index} />
|
|
183
|
+
))}
|
|
184
|
+
</div>
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### 3. Debounced Validation
|
|
190
|
+
|
|
191
|
+
For heavy validation schemas, you can debounce validation to keep the UI responsive.
|
|
192
|
+
|
|
193
|
+
```tsx
|
|
194
|
+
setData('field.path', value, {
|
|
195
|
+
debounceValidation: 300 // Wait 300ms before running Zod/Yup validation
|
|
196
|
+
});
|
|
197
|
+
```
|
|
198
|
+
|
|
106
199
|
## Conditional Steps
|
|
107
200
|
|
|
108
201
|
Steps can be dynamically included based on the wizard's state.
|
|
@@ -137,29 +230,141 @@ const config: IWizardConfig = {
|
|
|
137
230
|
}
|
|
138
231
|
```
|
|
139
232
|
|
|
233
|
+
## Advanced Features ๐
|
|
234
|
+
|
|
235
|
+
### 1. Step Renderer (Declarative UI)
|
|
236
|
+
|
|
237
|
+
Instead of manual switch statements with `currentStep.id`, trust the renderer!
|
|
238
|
+
|
|
239
|
+
```typescript
|
|
240
|
+
// Define component in config
|
|
241
|
+
const steps = [
|
|
242
|
+
{ id: 'step1', label: 'Start', component: Step1Component },
|
|
243
|
+
{ id: 'step2', label: 'End', component: Step2Component },
|
|
244
|
+
];
|
|
245
|
+
|
|
246
|
+
// Render
|
|
247
|
+
const App = () => (
|
|
248
|
+
<WizardProvider config={{ steps }}>
|
|
249
|
+
<WizardStepRenderer
|
|
250
|
+
wrapper={({ children }) => (
|
|
251
|
+
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }}>
|
|
252
|
+
{children}
|
|
253
|
+
</motion.div>
|
|
254
|
+
)}
|
|
255
|
+
/>
|
|
256
|
+
</WizardProvider>
|
|
257
|
+
);
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### 2. Routing Integration
|
|
261
|
+
|
|
262
|
+
Sync wizard state with URL using `onStepChange`.
|
|
263
|
+
|
|
264
|
+
```tsx
|
|
265
|
+
const navigate = useNavigate();
|
|
266
|
+
|
|
267
|
+
const config: IWizardConfig = {
|
|
268
|
+
// 1. Sync State -> URL
|
|
269
|
+
onStepChange: (prev, next, data) => {
|
|
270
|
+
navigate(`/wizard/${next}`);
|
|
271
|
+
// Optional: Send event to Analytics
|
|
272
|
+
trackEvent('wizard_step', { step: next });
|
|
273
|
+
},
|
|
274
|
+
steps: [...]
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
// 2. Sync URL -> State (Initial Load)
|
|
278
|
+
const { stepId } = useParams();
|
|
279
|
+
|
|
280
|
+
return <WizardProvider config={config} initialStepId={stepId}>...</WizardProvider>;
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### 3. Granular Persistence
|
|
284
|
+
|
|
285
|
+
By default, the wizard uses `MemoryAdapter` (RAM only). You can enable `LocalStorage` globally, but override it for sensitive steps.
|
|
286
|
+
|
|
287
|
+
```tsx
|
|
288
|
+
const config: IWizardConfig = {
|
|
289
|
+
// Global: Persist everything to LocalStorage
|
|
290
|
+
persistence: { adapter: new LocalStorageAdapter('wizard_') },
|
|
291
|
+
steps: [
|
|
292
|
+
{
|
|
293
|
+
id: 'public',
|
|
294
|
+
label: 'Public Info',
|
|
295
|
+
// Inherits global adapter (LocalStorage)
|
|
296
|
+
},
|
|
297
|
+
{
|
|
298
|
+
id: 'sensitive',
|
|
299
|
+
label: 'Credit Card',
|
|
300
|
+
// Override: Store strictly in memory (cleared on refresh)
|
|
301
|
+
persistenceAdapter: new MemoryAdapter()
|
|
302
|
+
}
|
|
303
|
+
]
|
|
304
|
+
};
|
|
305
|
+
```
|
|
306
|
+
|
|
140
307
|
## API Reference
|
|
141
308
|
|
|
142
309
|
### `IWizardConfig<T>`
|
|
310
|
+
|
|
143
311
|
- `steps`: Array of step configurations.
|
|
144
312
|
- `persistence`: Configuration for state persistence.
|
|
145
313
|
- `autoValidate`: (obj) Global validation setting.
|
|
146
314
|
|
|
147
315
|
### `useWizard<T>()`
|
|
316
|
+
|
|
148
317
|
- `activeSteps`: Steps that match conditions.
|
|
149
318
|
- `currentStep`: The currently active step object.
|
|
150
|
-
- `wizardData`: The global state object.
|
|
151
|
-
- `
|
|
319
|
+
- `wizardData`: The global state object (subscribe cautiously!).
|
|
320
|
+
- `setData(path, value, options?)`: Update state. Options: `{ debounceValidation: number }`.
|
|
321
|
+
- `getData(path, defaultValue?)`: Retrieve nested data.
|
|
322
|
+
- `handleStepChange(key, value)`: simple helper to update top-level state.
|
|
152
323
|
- `goToNextStep()`: Validates and moves next.
|
|
153
324
|
- `goToStep(id)`: Jumps to specific step.
|
|
154
325
|
- `allErrors`: Map of validation errors.
|
|
155
326
|
|
|
327
|
+
### New Performance Hooks
|
|
328
|
+
|
|
329
|
+
#### `useWizardValue<T>(path: string)`
|
|
330
|
+
|
|
331
|
+
Subscribes to a specific data path. Re-renders **only** when that value changes.
|
|
332
|
+
|
|
333
|
+
#### `useWizardError(path: string)`
|
|
334
|
+
|
|
335
|
+
Subscribes to validation errors for a specific path. Highly recommended for individual inputs.
|
|
336
|
+
|
|
337
|
+
#### `useWizardSelector<T>(selector: (state: T) => any)`
|
|
338
|
+
|
|
339
|
+
Create a custom subscription to the wizard state. Ideal for derived state or lists.
|
|
340
|
+
|
|
341
|
+
#### `useWizardActions()`
|
|
342
|
+
|
|
343
|
+
Returns object with actions (`setData`, `goToNextStep`, etc.) **without** subscribing to state changes. Use this in components that trigger updates but don't need to render data.
|
|
344
|
+
|
|
156
345
|
## Demos
|
|
157
346
|
|
|
158
347
|
Check out the [Live Demo](https://ZizzX.github.io/wizzard-stepper-react/), [NPM](https://www.npmjs.com/package/wizzard-stepper-react) or the [source code](https://github.com/ZizzX/wizzard-stepper-react-demo) for a complete implementation featuring:
|
|
348
|
+
|
|
159
349
|
- **Tailwind CSS v4** UI overhaul.
|
|
160
350
|
- **React Hook Form + Zod** integration.
|
|
161
351
|
- **Formik + Yup** integration.
|
|
162
352
|
- **Conditional Routing** logic.
|
|
353
|
+
- **Advanced Features Demo**: (`/advanced`) showcasing:
|
|
354
|
+
- **Autofill**: `updateData` global merge.
|
|
355
|
+
- **Declarative Rendering**: `<WizardStepRenderer />`.
|
|
356
|
+
- **Granular Persistence**: Hybrid Memory/LocalStorage.
|
|
357
|
+
|
|
358
|
+
## Advanced Demo Guide ๐งช
|
|
359
|
+
|
|
360
|
+
Visit `/advanced` in the demo to try:
|
|
361
|
+
|
|
362
|
+
1. **Autofill**: Click "Magic Autofill" to test `updateData()`. It instantly populates the form (merged with existing data).
|
|
363
|
+
2. **Hybrid Persistence**:
|
|
364
|
+
* **Step 1 (Identity)**: Refreshes persist (LocalStorage).
|
|
365
|
+
* **Step 2 (Security)**: Refreshes CLEAR data (MemoryAdapter).
|
|
366
|
+
3. **Declarative UI**: The steps are rendered using `<WizardStepRenderer />` with Framer Motion animations, defined in the config!
|
|
163
367
|
|
|
164
368
|
## License
|
|
369
|
+
|
|
165
370
|
MIT
|