wizzard-stepper-react 1.3.0 → 1.4.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 +143 -35
- package/dist/index.cjs +418 -123
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +138 -18
- package/dist/index.d.ts +138 -18
- package/dist/index.js +421 -123
- 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,85 @@ 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
|
+
|
|
135
|
+
## Performance & Optimization 🚀
|
|
136
|
+
|
|
137
|
+
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.
|
|
138
|
+
|
|
139
|
+
### 1. Use `useWizardValue` for Granular Updates
|
|
140
|
+
|
|
141
|
+
Instead of reading the whole `wizardData`, subscribe to a single field. The component will only re-render when *that specific field* changes.
|
|
142
|
+
|
|
143
|
+
```tsx
|
|
144
|
+
// ✅ FAST: Only re-renders when "users[0].name" changes
|
|
145
|
+
const NameInput = () => {
|
|
146
|
+
// Subscribe to specific path
|
|
147
|
+
const name = useWizardValue('users[0].name');
|
|
148
|
+
const { setData } = useWizardActions(); // Component actions don't trigger re-renders
|
|
149
|
+
|
|
150
|
+
return <input value={name} onChange={e => setData('users[0].name', e.target.value)} />;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// ❌ SLOW: Re-renders on ANY change in the form
|
|
154
|
+
const NameInputSlow = () => {
|
|
155
|
+
const { wizardData, setData } = useWizard();
|
|
156
|
+
return <input value={wizardData.users[0].name} ... />;
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### 2. Use `useWizardSelector` for Lists
|
|
161
|
+
|
|
162
|
+
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.
|
|
163
|
+
|
|
164
|
+
```tsx
|
|
165
|
+
const ChildrenList = () => {
|
|
166
|
+
// ✅ Only re-renders when the list LENGTH changes or IDs change
|
|
167
|
+
const childIds = useWizardSelector(state => state.children.map(c => c.id));
|
|
168
|
+
|
|
169
|
+
return (
|
|
170
|
+
<div>
|
|
171
|
+
{childIds.map((id, index) => (
|
|
172
|
+
// Pass ID/Index, NOT the data object
|
|
173
|
+
<ChildRow key={id} index={index} />
|
|
174
|
+
))}
|
|
175
|
+
</div>
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### 3. Debounced Validation
|
|
181
|
+
|
|
182
|
+
For heavy validation schemas, you can debounce validation to keep the UI responsive.
|
|
183
|
+
|
|
184
|
+
```tsx
|
|
185
|
+
setData('field.path', value, {
|
|
186
|
+
debounceValidation: 300 // Wait 300ms before running Zod/Yup validation
|
|
187
|
+
});
|
|
188
|
+
```
|
|
189
|
+
|
|
106
190
|
## Conditional Steps
|
|
107
191
|
|
|
108
192
|
Steps can be dynamically included based on the wizard's state.
|
|
@@ -140,26 +224,50 @@ const config: IWizardConfig = {
|
|
|
140
224
|
## API Reference
|
|
141
225
|
|
|
142
226
|
### `IWizardConfig<T>`
|
|
227
|
+
|
|
143
228
|
- `steps`: Array of step configurations.
|
|
144
229
|
- `persistence`: Configuration for state persistence.
|
|
145
230
|
- `autoValidate`: (obj) Global validation setting.
|
|
146
231
|
|
|
147
232
|
### `useWizard<T>()`
|
|
233
|
+
|
|
148
234
|
- `activeSteps`: Steps that match conditions.
|
|
149
235
|
- `currentStep`: The currently active step object.
|
|
150
|
-
- `wizardData`: The global state object.
|
|
151
|
-
- `
|
|
236
|
+
- `wizardData`: The global state object (subscribe cautiously!).
|
|
237
|
+
- `setData(path, value, options?)`: Update state. Options: `{ debounceValidation: number }`.
|
|
238
|
+
- `getData(path, defaultValue?)`: Retrieve nested data.
|
|
239
|
+
- `handleStepChange(key, value)`: simple helper to update top-level state.
|
|
152
240
|
- `goToNextStep()`: Validates and moves next.
|
|
153
241
|
- `goToStep(id)`: Jumps to specific step.
|
|
154
242
|
- `allErrors`: Map of validation errors.
|
|
155
243
|
|
|
244
|
+
### New Performance Hooks
|
|
245
|
+
|
|
246
|
+
#### `useWizardValue<T>(path: string)`
|
|
247
|
+
|
|
248
|
+
Subscribes to a specific data path. Re-renders **only** when that value changes.
|
|
249
|
+
|
|
250
|
+
#### `useWizardError(path: string)`
|
|
251
|
+
|
|
252
|
+
Subscribes to validation errors for a specific path. Highly recommended for individual inputs.
|
|
253
|
+
|
|
254
|
+
#### `useWizardSelector<T>(selector: (state: T) => any)`
|
|
255
|
+
|
|
256
|
+
Create a custom subscription to the wizard state. Ideal for derived state or lists.
|
|
257
|
+
|
|
258
|
+
#### `useWizardActions()`
|
|
259
|
+
|
|
260
|
+
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.
|
|
261
|
+
|
|
156
262
|
## Demos
|
|
157
263
|
|
|
158
|
-
Check out the [Live Demo](https://ZizzX.github.io/wizzard-stepper-react
|
|
264
|
+
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:
|
|
265
|
+
|
|
159
266
|
- **Tailwind CSS v4** UI overhaul.
|
|
160
267
|
- **React Hook Form + Zod** integration.
|
|
161
268
|
- **Formik + Yup** integration.
|
|
162
269
|
- **Conditional Routing** logic.
|
|
163
270
|
|
|
164
271
|
## License
|
|
272
|
+
|
|
165
273
|
MIT
|