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/dist/index.cjs
CHANGED
|
@@ -25,12 +25,20 @@ __export(index_exports, {
|
|
|
25
25
|
LocalStorageAdapter: () => LocalStorageAdapter,
|
|
26
26
|
MemoryAdapter: () => MemoryAdapter,
|
|
27
27
|
WizardProvider: () => WizardProvider,
|
|
28
|
+
WizardStepRenderer: () => WizardStepRenderer,
|
|
29
|
+
WizardStore: () => WizardStore,
|
|
28
30
|
YupAdapter: () => YupAdapter,
|
|
29
31
|
ZodAdapter: () => ZodAdapter,
|
|
32
|
+
createWizardFactory: () => createWizardFactory,
|
|
30
33
|
getByPath: () => getByPath,
|
|
31
34
|
setByPath: () => setByPath,
|
|
32
35
|
useWizard: () => useWizard,
|
|
33
|
-
|
|
36
|
+
useWizardActions: () => useWizardActions,
|
|
37
|
+
useWizardContext: () => useWizardContext,
|
|
38
|
+
useWizardError: () => useWizardError,
|
|
39
|
+
useWizardSelector: () => useWizardSelector,
|
|
40
|
+
useWizardState: () => useWizardState,
|
|
41
|
+
useWizardValue: () => useWizardValue
|
|
34
42
|
});
|
|
35
43
|
module.exports = __toCommonJS(index_exports);
|
|
36
44
|
|
|
@@ -66,6 +74,9 @@ function getByPath(obj, path, defaultValue) {
|
|
|
66
74
|
}
|
|
67
75
|
function setByPath(obj, path, value) {
|
|
68
76
|
if (!path) return value;
|
|
77
|
+
if (!path.includes(".") && !path.includes("[") && !path.includes("]")) {
|
|
78
|
+
return { ...obj, [path]: value };
|
|
79
|
+
}
|
|
69
80
|
const keys = path.replace(/\[(\d+)\]/g, ".$1").split(".").filter(Boolean);
|
|
70
81
|
const update = (current, index) => {
|
|
71
82
|
if (index === keys.length) return value;
|
|
@@ -86,39 +97,93 @@ function setByPath(obj, path, value) {
|
|
|
86
97
|
|
|
87
98
|
// src/context/WizardContext.tsx
|
|
88
99
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
89
|
-
var
|
|
100
|
+
var WizardStateContext = (0, import_react.createContext)(
|
|
101
|
+
void 0
|
|
102
|
+
);
|
|
103
|
+
var WizardActionsContext = (0, import_react.createContext)(
|
|
104
|
+
void 0
|
|
105
|
+
);
|
|
106
|
+
var WizardStore = class {
|
|
107
|
+
constructor(initialData) {
|
|
108
|
+
__publicField(this, "state");
|
|
109
|
+
__publicField(this, "listeners", /* @__PURE__ */ new Set());
|
|
110
|
+
__publicField(this, "getSnapshot", () => this.state);
|
|
111
|
+
__publicField(this, "subscribe", (listener) => {
|
|
112
|
+
this.listeners.add(listener);
|
|
113
|
+
return () => this.listeners.delete(listener);
|
|
114
|
+
});
|
|
115
|
+
this.state = { data: initialData, errors: {} };
|
|
116
|
+
}
|
|
117
|
+
update(newData) {
|
|
118
|
+
this.state = { ...this.state, data: newData };
|
|
119
|
+
this.notify();
|
|
120
|
+
}
|
|
121
|
+
updateErrors(newErrors) {
|
|
122
|
+
this.state = { ...this.state, errors: newErrors };
|
|
123
|
+
this.notify();
|
|
124
|
+
}
|
|
125
|
+
notify() {
|
|
126
|
+
this.listeners.forEach((l) => l());
|
|
127
|
+
}
|
|
128
|
+
};
|
|
90
129
|
function WizardProvider({
|
|
91
130
|
config,
|
|
92
131
|
initialData,
|
|
132
|
+
initialStepId,
|
|
93
133
|
children
|
|
94
134
|
}) {
|
|
95
135
|
const [currentStepId, setCurrentStepId] = (0, import_react.useState)("");
|
|
96
|
-
const [wizardData, setWizardData] = (0, import_react.useState)(initialData || {});
|
|
97
136
|
const [visitedSteps, setVisitedSteps] = (0, import_react.useState)(/* @__PURE__ */ new Set());
|
|
98
137
|
const [completedSteps, setCompletedSteps] = (0, import_react.useState)(/* @__PURE__ */ new Set());
|
|
99
138
|
const [errorSteps, setErrorSteps] = (0, import_react.useState)(/* @__PURE__ */ new Set());
|
|
100
|
-
const [
|
|
139
|
+
const [, setAllErrorsState] = (0, import_react.useState)({});
|
|
101
140
|
const [isLoading, setIsLoading] = (0, import_react.useState)(true);
|
|
141
|
+
const [isPending, startTransition] = (0, import_react.useTransition)();
|
|
142
|
+
const storeRef = (0, import_react.useRef)(new WizardStore(initialData || {}));
|
|
143
|
+
const [wizardData, setWizardData] = (0, import_react.useState)(initialData || {});
|
|
102
144
|
const persistenceAdapter = (0, import_react.useMemo)(() => {
|
|
103
145
|
return config.persistence?.adapter || new MemoryAdapter();
|
|
104
146
|
}, [config.persistence?.adapter]);
|
|
105
147
|
const persistenceMode = config.persistence?.mode || "onStepChange";
|
|
106
|
-
const activeSteps = (0, import_react.
|
|
107
|
-
|
|
148
|
+
const [activeSteps, setActiveSteps] = (0, import_react.useState)(
|
|
149
|
+
() => config.steps.filter((s) => !s.condition || s.condition(wizardData))
|
|
150
|
+
);
|
|
151
|
+
(0, import_react.useEffect)(() => {
|
|
152
|
+
const nextActiveSteps = config.steps.filter((step) => {
|
|
108
153
|
if (step.condition) {
|
|
109
154
|
return step.condition(wizardData);
|
|
110
155
|
}
|
|
111
156
|
return true;
|
|
112
157
|
});
|
|
113
|
-
|
|
158
|
+
const currentIds = activeSteps.map((s) => s.id).join(",");
|
|
159
|
+
const nextIds = nextActiveSteps.map((s) => s.id).join(",");
|
|
160
|
+
if (currentIds !== nextIds) {
|
|
161
|
+
setActiveSteps(nextActiveSteps);
|
|
162
|
+
}
|
|
163
|
+
}, [config.steps, wizardData, activeSteps]);
|
|
114
164
|
(0, import_react.useEffect)(() => {
|
|
115
165
|
if (!currentStepId && activeSteps.length > 0) {
|
|
116
|
-
|
|
166
|
+
if (initialStepId) {
|
|
167
|
+
const target = activeSteps.find((s) => s.id === initialStepId);
|
|
168
|
+
if (target) {
|
|
169
|
+
setCurrentStepId(target.id);
|
|
170
|
+
} else {
|
|
171
|
+
setCurrentStepId(activeSteps[0].id);
|
|
172
|
+
}
|
|
173
|
+
} else {
|
|
174
|
+
setCurrentStepId(activeSteps[0].id);
|
|
175
|
+
}
|
|
117
176
|
setIsLoading(false);
|
|
118
177
|
}
|
|
119
|
-
}, [activeSteps, currentStepId]);
|
|
120
|
-
const currentStep = (0, import_react.useMemo)(
|
|
121
|
-
|
|
178
|
+
}, [activeSteps, currentStepId, initialStepId]);
|
|
179
|
+
const currentStep = (0, import_react.useMemo)(
|
|
180
|
+
() => activeSteps.find((s) => s.id === currentStepId) || null,
|
|
181
|
+
[activeSteps, currentStepId]
|
|
182
|
+
);
|
|
183
|
+
const currentStepIndex = (0, import_react.useMemo)(
|
|
184
|
+
() => activeSteps.findIndex((s) => s.id === currentStepId),
|
|
185
|
+
[activeSteps, currentStepId]
|
|
186
|
+
);
|
|
122
187
|
const isFirstStep = currentStepIndex === 0;
|
|
123
188
|
const isLastStep = currentStepIndex === activeSteps.length - 1;
|
|
124
189
|
const META_KEY = "__wizzard_meta__";
|
|
@@ -138,103 +203,186 @@ function WizardProvider({
|
|
|
138
203
|
}
|
|
139
204
|
});
|
|
140
205
|
if (Object.keys(loadedData).length > 0) {
|
|
141
|
-
setWizardData((prev) =>
|
|
206
|
+
setWizardData((prev) => {
|
|
207
|
+
const newData = { ...prev, ...loadedData };
|
|
208
|
+
storeRef.current.update(newData);
|
|
209
|
+
return newData;
|
|
210
|
+
});
|
|
142
211
|
}
|
|
143
212
|
setIsLoading(false);
|
|
144
213
|
}, [config.steps, persistenceAdapter]);
|
|
145
214
|
(0, import_react.useEffect)(() => {
|
|
146
215
|
hydrate();
|
|
147
216
|
}, [hydrate]);
|
|
148
|
-
const saveData = (0, import_react.useCallback)(
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
217
|
+
const saveData = (0, import_react.useCallback)(
|
|
218
|
+
(mode, stepId, data) => {
|
|
219
|
+
const stepConfig = config.steps.find((s) => s.id === stepId);
|
|
220
|
+
const stepAdapter = stepConfig?.persistenceAdapter;
|
|
221
|
+
const adapterToUse = stepAdapter || persistenceAdapter;
|
|
222
|
+
if (mode === persistenceMode || mode === "manual") {
|
|
223
|
+
adapterToUse.saveStep(stepId, data);
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
[persistenceAdapter, persistenceMode, config.steps]
|
|
227
|
+
);
|
|
228
|
+
const validationTimeoutRef = (0, import_react.useRef)(
|
|
229
|
+
null
|
|
230
|
+
);
|
|
231
|
+
const validateStep = (0, import_react.useCallback)(
|
|
232
|
+
async (stepId, data) => {
|
|
233
|
+
const step = config.steps.find((s) => s.id === stepId);
|
|
234
|
+
if (!step || !step.validationAdapter) return true;
|
|
235
|
+
const result = await step.validationAdapter.validate(data);
|
|
236
|
+
if (!result.isValid) {
|
|
237
|
+
const newAllErrors = {
|
|
238
|
+
...storeRef.current.getSnapshot().errors,
|
|
239
|
+
[stepId]: result.errors || {}
|
|
240
|
+
};
|
|
241
|
+
storeRef.current.updateErrors(newAllErrors);
|
|
242
|
+
setAllErrorsState(newAllErrors);
|
|
243
|
+
setErrorSteps((prev) => {
|
|
244
|
+
const next = new Set(prev);
|
|
245
|
+
next.add(stepId);
|
|
246
|
+
return next;
|
|
247
|
+
});
|
|
248
|
+
return false;
|
|
249
|
+
} else {
|
|
250
|
+
const newAllErrors = { ...storeRef.current.getSnapshot().errors };
|
|
251
|
+
delete newAllErrors[stepId];
|
|
252
|
+
storeRef.current.updateErrors(newAllErrors);
|
|
253
|
+
setAllErrorsState(newAllErrors);
|
|
254
|
+
setErrorSteps((prev) => {
|
|
255
|
+
const next = new Set(prev);
|
|
256
|
+
next.delete(stepId);
|
|
257
|
+
return next;
|
|
258
|
+
});
|
|
259
|
+
return true;
|
|
260
|
+
}
|
|
261
|
+
},
|
|
262
|
+
[config.steps]
|
|
263
|
+
);
|
|
264
|
+
const setStepData = (0, import_react.useCallback)(
|
|
265
|
+
(stepId, data) => {
|
|
266
|
+
const prevData = storeRef.current.getSnapshot().data;
|
|
267
|
+
const newData = { ...prevData, ...data };
|
|
268
|
+
storeRef.current.update(newData);
|
|
269
|
+
startTransition(() => {
|
|
270
|
+
setWizardData(newData);
|
|
271
|
+
});
|
|
156
272
|
if (persistenceMode === "onChange") {
|
|
157
273
|
saveData("onChange", stepId, newData);
|
|
158
274
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
const setData = (0, import_react.useCallback)(
|
|
163
|
-
|
|
164
|
-
const
|
|
275
|
+
},
|
|
276
|
+
[persistenceMode, saveData]
|
|
277
|
+
);
|
|
278
|
+
const setData = (0, import_react.useCallback)(
|
|
279
|
+
(path, value, options) => {
|
|
280
|
+
const prevData = storeRef.current.getSnapshot().data;
|
|
281
|
+
const newData = setByPath(prevData, path, value);
|
|
282
|
+
storeRef.current.update(newData);
|
|
283
|
+
startTransition(() => {
|
|
284
|
+
setWizardData(newData);
|
|
285
|
+
});
|
|
286
|
+
if (options?.debounceValidation) {
|
|
287
|
+
if (validationTimeoutRef.current)
|
|
288
|
+
clearTimeout(validationTimeoutRef.current);
|
|
289
|
+
validationTimeoutRef.current = setTimeout(() => {
|
|
290
|
+
try {
|
|
291
|
+
validateStep(currentStepId, newData).catch((err) => {
|
|
292
|
+
console.error("[Wizard] Debounced validation failed:", err);
|
|
293
|
+
});
|
|
294
|
+
} catch (e) {
|
|
295
|
+
console.error("[Wizard] Error starting validation:", e);
|
|
296
|
+
}
|
|
297
|
+
}, options.debounceValidation);
|
|
298
|
+
} else {
|
|
299
|
+
validateStep(currentStepId, newData);
|
|
300
|
+
}
|
|
165
301
|
if (persistenceMode === "onChange") {
|
|
166
302
|
saveData("onChange", currentStepId, newData);
|
|
167
303
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
const validateStep = (0, import_react.useCallback)(async (stepId) => {
|
|
179
|
-
const step = config.steps.find((s) => s.id === stepId);
|
|
180
|
-
if (!step) return true;
|
|
181
|
-
if (!step.validationAdapter) return true;
|
|
182
|
-
const result = await step.validationAdapter.validate(wizardData);
|
|
183
|
-
if (!result.isValid) {
|
|
184
|
-
setAllErrors((prev) => ({
|
|
185
|
-
...prev,
|
|
186
|
-
[stepId]: result.errors || {}
|
|
187
|
-
}));
|
|
188
|
-
setErrorSteps((prev) => new Set(prev).add(stepId));
|
|
189
|
-
return false;
|
|
190
|
-
} else {
|
|
191
|
-
setAllErrors((prev) => {
|
|
192
|
-
const next = { ...prev };
|
|
193
|
-
delete next[stepId];
|
|
194
|
-
return next;
|
|
304
|
+
},
|
|
305
|
+
[persistenceMode, saveData, currentStepId, validateStep]
|
|
306
|
+
);
|
|
307
|
+
const updateData = (0, import_react.useCallback)(
|
|
308
|
+
(data, options) => {
|
|
309
|
+
const prevData = storeRef.current.getSnapshot().data;
|
|
310
|
+
const newData = options?.replace ? data : { ...prevData, ...data };
|
|
311
|
+
storeRef.current.update(newData);
|
|
312
|
+
startTransition(() => {
|
|
313
|
+
setWizardData(newData);
|
|
195
314
|
});
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
next.delete(stepId);
|
|
199
|
-
return next;
|
|
315
|
+
config.steps.forEach((step) => {
|
|
316
|
+
saveData("manual", step.id, newData);
|
|
200
317
|
});
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
318
|
+
},
|
|
319
|
+
[saveData, config.steps]
|
|
320
|
+
);
|
|
321
|
+
const getData = (0, import_react.useCallback)((path, defaultValue) => {
|
|
322
|
+
return getByPath(storeRef.current.getSnapshot().data, path, defaultValue);
|
|
323
|
+
}, []);
|
|
324
|
+
const handleStepChange = (0, import_react.useCallback)(
|
|
325
|
+
(field, value) => {
|
|
326
|
+
if (!currentStepId) return;
|
|
327
|
+
setData(field, value);
|
|
328
|
+
},
|
|
329
|
+
[setData, currentStepId]
|
|
330
|
+
);
|
|
204
331
|
const validateAll = (0, import_react.useCallback)(async () => {
|
|
205
332
|
let isValid = true;
|
|
333
|
+
const currentData = storeRef.current.getSnapshot().data;
|
|
206
334
|
for (const step of activeSteps) {
|
|
207
|
-
const stepValid = await validateStep(step.id);
|
|
335
|
+
const stepValid = await validateStep(step.id, currentData);
|
|
208
336
|
if (!stepValid) isValid = false;
|
|
209
337
|
}
|
|
210
|
-
|
|
338
|
+
const finalErrors = storeRef.current.getSnapshot().errors;
|
|
339
|
+
return { isValid, errors: finalErrors };
|
|
211
340
|
}, [activeSteps, validateStep]);
|
|
212
|
-
const goToStep = (0, import_react.useCallback)(
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
const
|
|
217
|
-
if (
|
|
218
|
-
const
|
|
219
|
-
if (
|
|
341
|
+
const goToStep = (0, import_react.useCallback)(
|
|
342
|
+
async (stepId) => {
|
|
343
|
+
const targetIndex = activeSteps.findIndex((s) => s.id === stepId);
|
|
344
|
+
if (targetIndex === -1) return false;
|
|
345
|
+
const currentData = storeRef.current.getSnapshot().data;
|
|
346
|
+
if (targetIndex > currentStepIndex) {
|
|
347
|
+
const shouldValidate = currentStep?.autoValidate ?? config.autoValidate ?? true;
|
|
348
|
+
if (shouldValidate) {
|
|
349
|
+
const isValid = await validateStep(currentStepId, currentData);
|
|
350
|
+
if (!isValid) return false;
|
|
351
|
+
}
|
|
220
352
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
353
|
+
if (persistenceMode === "onStepChange" && currentStep) {
|
|
354
|
+
saveData("onStepChange", currentStepId, currentData);
|
|
355
|
+
}
|
|
356
|
+
const nextVisited = new Set(visitedSteps).add(currentStepId);
|
|
357
|
+
setVisitedSteps(nextVisited);
|
|
358
|
+
setCurrentStepId(stepId);
|
|
359
|
+
if (persistenceMode !== "manual") {
|
|
360
|
+
persistenceAdapter.saveStep(META_KEY, {
|
|
361
|
+
currentStepId: stepId,
|
|
362
|
+
visited: Array.from(nextVisited),
|
|
363
|
+
completed: Array.from(completedSteps)
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
if (config.onStepChange) {
|
|
367
|
+
config.onStepChange(currentStepId, stepId, currentData);
|
|
368
|
+
}
|
|
369
|
+
window.scrollTo(0, 0);
|
|
370
|
+
return true;
|
|
371
|
+
},
|
|
372
|
+
[
|
|
373
|
+
activeSteps,
|
|
374
|
+
currentStepId,
|
|
375
|
+
currentStep,
|
|
376
|
+
currentStepIndex,
|
|
377
|
+
config.autoValidate,
|
|
378
|
+
persistenceMode,
|
|
379
|
+
saveData,
|
|
380
|
+
validateStep,
|
|
381
|
+
visitedSteps,
|
|
382
|
+
completedSteps,
|
|
383
|
+
persistenceAdapter
|
|
384
|
+
]
|
|
385
|
+
);
|
|
238
386
|
const goToNextStep = (0, import_react.useCallback)(async () => {
|
|
239
387
|
if (isLastStep) return;
|
|
240
388
|
const nextStep = activeSteps[currentStepIndex + 1];
|
|
@@ -248,12 +396,21 @@ function WizardProvider({
|
|
|
248
396
|
currentStepId: nextStep.id,
|
|
249
397
|
visited: Array.from(new Set(visitedSteps).add(currentStepId)),
|
|
250
398
|
completed: Array.from(nextCompleted)
|
|
251
|
-
// Updated completed steps
|
|
252
399
|
});
|
|
253
400
|
}
|
|
254
401
|
}
|
|
255
402
|
}
|
|
256
|
-
}, [
|
|
403
|
+
}, [
|
|
404
|
+
activeSteps,
|
|
405
|
+
currentStepIndex,
|
|
406
|
+
isLastStep,
|
|
407
|
+
currentStepId,
|
|
408
|
+
goToStep,
|
|
409
|
+
visitedSteps,
|
|
410
|
+
completedSteps,
|
|
411
|
+
persistenceMode,
|
|
412
|
+
persistenceAdapter
|
|
413
|
+
]);
|
|
257
414
|
const goToPrevStep = (0, import_react.useCallback)(() => {
|
|
258
415
|
if (isFirstStep) return;
|
|
259
416
|
const prevStep = activeSteps[currentStepIndex - 1];
|
|
@@ -261,45 +418,235 @@ function WizardProvider({
|
|
|
261
418
|
goToStep(prevStep.id);
|
|
262
419
|
}
|
|
263
420
|
}, [activeSteps, currentStepIndex, isFirstStep, goToStep]);
|
|
264
|
-
const
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
421
|
+
const clearStorage = (0, import_react.useCallback)(
|
|
422
|
+
() => persistenceAdapter.clear(),
|
|
423
|
+
[persistenceAdapter]
|
|
424
|
+
);
|
|
425
|
+
const save = (0, import_react.useCallback)(
|
|
426
|
+
() => saveData("manual", currentStepId, storeRef.current.getSnapshot().data),
|
|
427
|
+
[saveData, currentStepId]
|
|
428
|
+
);
|
|
429
|
+
const stateValue = (0, import_react.useMemo)(
|
|
430
|
+
() => ({
|
|
431
|
+
currentStep,
|
|
432
|
+
currentStepIndex,
|
|
433
|
+
isFirstStep,
|
|
434
|
+
isLastStep,
|
|
435
|
+
isLoading,
|
|
436
|
+
isPending,
|
|
437
|
+
activeSteps,
|
|
438
|
+
visitedSteps,
|
|
439
|
+
completedSteps,
|
|
440
|
+
errorSteps,
|
|
441
|
+
store: storeRef.current
|
|
442
|
+
}),
|
|
443
|
+
[
|
|
444
|
+
currentStep,
|
|
445
|
+
currentStepIndex,
|
|
446
|
+
isFirstStep,
|
|
447
|
+
isLastStep,
|
|
448
|
+
isLoading,
|
|
449
|
+
isPending,
|
|
450
|
+
activeSteps,
|
|
451
|
+
visitedSteps,
|
|
452
|
+
completedSteps,
|
|
453
|
+
errorSteps
|
|
454
|
+
]
|
|
455
|
+
);
|
|
456
|
+
const actionsValue = (0, import_react.useMemo)(
|
|
457
|
+
() => ({
|
|
458
|
+
goToNextStep,
|
|
459
|
+
goToPrevStep,
|
|
460
|
+
goToStep,
|
|
461
|
+
setStepData,
|
|
462
|
+
handleStepChange,
|
|
463
|
+
validateStep: (sid) => validateStep(sid, storeRef.current.getSnapshot().data),
|
|
464
|
+
validateAll,
|
|
465
|
+
save,
|
|
466
|
+
clearStorage,
|
|
467
|
+
setData,
|
|
468
|
+
updateData,
|
|
469
|
+
getData
|
|
470
|
+
}),
|
|
471
|
+
[
|
|
472
|
+
goToNextStep,
|
|
473
|
+
goToPrevStep,
|
|
474
|
+
goToStep,
|
|
475
|
+
setStepData,
|
|
476
|
+
handleStepChange,
|
|
477
|
+
validateStep,
|
|
478
|
+
validateAll,
|
|
479
|
+
save,
|
|
480
|
+
clearStorage,
|
|
481
|
+
setData,
|
|
482
|
+
updateData,
|
|
483
|
+
getData
|
|
484
|
+
]
|
|
485
|
+
);
|
|
486
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(WizardStateContext.Provider, { value: stateValue, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(WizardActionsContext.Provider, { value: actionsValue, children }) });
|
|
289
487
|
}
|
|
290
|
-
function
|
|
291
|
-
const context = (0, import_react.useContext)(
|
|
488
|
+
function useWizardState() {
|
|
489
|
+
const context = (0, import_react.useContext)(WizardStateContext);
|
|
490
|
+
if (!context) {
|
|
491
|
+
throw new Error("useWizardState must be used within a WizardProvider");
|
|
492
|
+
}
|
|
493
|
+
return context;
|
|
494
|
+
}
|
|
495
|
+
function useWizardValue(path) {
|
|
496
|
+
const { store } = useWizardState();
|
|
497
|
+
const lastStateRef = (0, import_react.useRef)(null);
|
|
498
|
+
const lastValueRef = (0, import_react.useRef)(null);
|
|
499
|
+
const getSnapshot = (0, import_react.useCallback)(() => {
|
|
500
|
+
const fullState = store.getSnapshot();
|
|
501
|
+
const data = fullState.data;
|
|
502
|
+
if (data === lastStateRef.current) {
|
|
503
|
+
return lastValueRef.current;
|
|
504
|
+
}
|
|
505
|
+
const value = getByPath(data, path);
|
|
506
|
+
lastStateRef.current = data;
|
|
507
|
+
lastValueRef.current = value;
|
|
508
|
+
return value;
|
|
509
|
+
}, [store, path]);
|
|
510
|
+
return (0, import_react.useSyncExternalStore)(store.subscribe, getSnapshot);
|
|
511
|
+
}
|
|
512
|
+
function useWizardError(path) {
|
|
513
|
+
const { store } = useWizardState();
|
|
514
|
+
const lastStateRef = (0, import_react.useRef)(null);
|
|
515
|
+
const lastValueRef = (0, import_react.useRef)(null);
|
|
516
|
+
const getSnapshot = (0, import_react.useCallback)(() => {
|
|
517
|
+
const fullState = store.getSnapshot();
|
|
518
|
+
const errors = fullState.errors;
|
|
519
|
+
if (errors === lastStateRef.current) {
|
|
520
|
+
return lastValueRef.current;
|
|
521
|
+
}
|
|
522
|
+
let foundError;
|
|
523
|
+
Object.values(errors).forEach((stepErrors) => {
|
|
524
|
+
const typedStepErrors = stepErrors;
|
|
525
|
+
if (typedStepErrors[path]) foundError = typedStepErrors[path];
|
|
526
|
+
});
|
|
527
|
+
lastStateRef.current = errors;
|
|
528
|
+
lastValueRef.current = foundError;
|
|
529
|
+
return foundError;
|
|
530
|
+
}, [store, path]);
|
|
531
|
+
return (0, import_react.useSyncExternalStore)(store.subscribe, getSnapshot);
|
|
532
|
+
}
|
|
533
|
+
function useWizardSelector(selector) {
|
|
534
|
+
const { store } = useWizardState();
|
|
535
|
+
const lastStateRef = (0, import_react.useRef)(null);
|
|
536
|
+
const lastResultRef = (0, import_react.useRef)(null);
|
|
537
|
+
const getSnapshot = (0, import_react.useCallback)(() => {
|
|
538
|
+
const fullState = store.getSnapshot();
|
|
539
|
+
if (fullState === lastStateRef.current) {
|
|
540
|
+
return lastResultRef.current;
|
|
541
|
+
}
|
|
542
|
+
const result = selector(fullState.data);
|
|
543
|
+
lastStateRef.current = fullState;
|
|
544
|
+
lastResultRef.current = result;
|
|
545
|
+
return result;
|
|
546
|
+
}, [store, selector]);
|
|
547
|
+
return (0, import_react.useSyncExternalStore)(store.subscribe, getSnapshot);
|
|
548
|
+
}
|
|
549
|
+
function useWizardActions() {
|
|
550
|
+
const context = (0, import_react.useContext)(WizardActionsContext);
|
|
292
551
|
if (!context) {
|
|
293
|
-
throw new Error("
|
|
552
|
+
throw new Error("useWizardActions must be used within a WizardProvider");
|
|
294
553
|
}
|
|
295
554
|
return context;
|
|
296
555
|
}
|
|
556
|
+
function useWizardContext() {
|
|
557
|
+
const state = useWizardState();
|
|
558
|
+
const actions = useWizardActions();
|
|
559
|
+
const wizardData = useWizardSelector((s) => s);
|
|
560
|
+
const fullState = state.store.getSnapshot();
|
|
561
|
+
return (0, import_react.useMemo)(
|
|
562
|
+
() => ({
|
|
563
|
+
...state,
|
|
564
|
+
...actions,
|
|
565
|
+
wizardData,
|
|
566
|
+
allErrors: fullState.errors
|
|
567
|
+
}),
|
|
568
|
+
[state, actions, wizardData, fullState.errors]
|
|
569
|
+
);
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
// src/components/WizardStepRenderer.tsx
|
|
573
|
+
var import_react2 = require("react");
|
|
574
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
575
|
+
var WizardStepRenderer = ({
|
|
576
|
+
wrapper: Wrapper
|
|
577
|
+
}) => {
|
|
578
|
+
const { currentStep } = useWizardContext();
|
|
579
|
+
const StepComponent = (0, import_react2.useMemo)(() => {
|
|
580
|
+
if (!currentStep?.component) return null;
|
|
581
|
+
return currentStep.component;
|
|
582
|
+
}, [currentStep]);
|
|
583
|
+
if (!currentStep || !StepComponent) {
|
|
584
|
+
return null;
|
|
585
|
+
}
|
|
586
|
+
const content = /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(StepComponent, {});
|
|
587
|
+
if (Wrapper) {
|
|
588
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Wrapper, { children: content }, currentStep.id);
|
|
589
|
+
}
|
|
590
|
+
return content;
|
|
591
|
+
};
|
|
297
592
|
|
|
298
593
|
// src/hooks/useWizard.ts
|
|
299
594
|
var useWizard = () => {
|
|
300
595
|
return useWizardContext();
|
|
301
596
|
};
|
|
302
597
|
|
|
598
|
+
// src/factory.tsx
|
|
599
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
600
|
+
function createWizardFactory() {
|
|
601
|
+
const WizardProvider2 = ({
|
|
602
|
+
config,
|
|
603
|
+
initialData,
|
|
604
|
+
children
|
|
605
|
+
}) => {
|
|
606
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
607
|
+
WizardProvider,
|
|
608
|
+
{
|
|
609
|
+
config,
|
|
610
|
+
initialData,
|
|
611
|
+
children
|
|
612
|
+
}
|
|
613
|
+
);
|
|
614
|
+
};
|
|
615
|
+
const useWizard2 = () => {
|
|
616
|
+
return useWizard();
|
|
617
|
+
};
|
|
618
|
+
const useWizardContext2 = () => {
|
|
619
|
+
return useWizardContext();
|
|
620
|
+
};
|
|
621
|
+
const useWizardValue2 = (path) => {
|
|
622
|
+
return useWizardValue(path);
|
|
623
|
+
};
|
|
624
|
+
const useWizardSelector2 = (selector) => {
|
|
625
|
+
return useWizardSelector(selector);
|
|
626
|
+
};
|
|
627
|
+
const useWizardError2 = (path) => {
|
|
628
|
+
return useWizardError(path);
|
|
629
|
+
};
|
|
630
|
+
const useWizardActions2 = () => {
|
|
631
|
+
return useWizardActions();
|
|
632
|
+
};
|
|
633
|
+
const useWizardState2 = () => {
|
|
634
|
+
return useWizardState();
|
|
635
|
+
};
|
|
636
|
+
const createStep = (config) => config;
|
|
637
|
+
return {
|
|
638
|
+
WizardProvider: WizardProvider2,
|
|
639
|
+
useWizard: useWizard2,
|
|
640
|
+
useWizardContext: useWizardContext2,
|
|
641
|
+
useWizardValue: useWizardValue2,
|
|
642
|
+
useWizardSelector: useWizardSelector2,
|
|
643
|
+
useWizardError: useWizardError2,
|
|
644
|
+
useWizardActions: useWizardActions2,
|
|
645
|
+
useWizardState: useWizardState2,
|
|
646
|
+
createStep
|
|
647
|
+
};
|
|
648
|
+
}
|
|
649
|
+
|
|
303
650
|
// src/adapters/persistence/LocalStorageAdapter.ts
|
|
304
651
|
var LocalStorageAdapter = class {
|
|
305
652
|
constructor(prefix = "wizard_") {
|
|
@@ -349,16 +696,17 @@ var ZodAdapter = class {
|
|
|
349
696
|
return { isValid: true };
|
|
350
697
|
}
|
|
351
698
|
const errors = {};
|
|
352
|
-
result.error
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
699
|
+
if (result.error) {
|
|
700
|
+
result.error.issues.forEach((err) => {
|
|
701
|
+
const path = err.path.join(".");
|
|
702
|
+
errors[path] = err.message;
|
|
703
|
+
});
|
|
704
|
+
}
|
|
356
705
|
return { isValid: false, errors };
|
|
357
706
|
}
|
|
358
707
|
};
|
|
359
708
|
|
|
360
709
|
// src/adapters/validation/YupAdapter.ts
|
|
361
|
-
var import_yup = require("yup");
|
|
362
710
|
var YupAdapter = class {
|
|
363
711
|
constructor(schema) {
|
|
364
712
|
__publicField(this, "schema");
|
|
@@ -369,9 +717,10 @@ var YupAdapter = class {
|
|
|
369
717
|
await this.schema.validate(data, { abortEarly: false });
|
|
370
718
|
return { isValid: true };
|
|
371
719
|
} catch (err) {
|
|
372
|
-
if (err
|
|
720
|
+
if (err && typeof err === "object" && "inner" in err) {
|
|
721
|
+
const yupError = err;
|
|
373
722
|
const errors = {};
|
|
374
|
-
|
|
723
|
+
yupError.inner.forEach((error) => {
|
|
375
724
|
if (error.path) {
|
|
376
725
|
errors[error.path] = error.message;
|
|
377
726
|
}
|
|
@@ -387,11 +736,19 @@ var YupAdapter = class {
|
|
|
387
736
|
LocalStorageAdapter,
|
|
388
737
|
MemoryAdapter,
|
|
389
738
|
WizardProvider,
|
|
739
|
+
WizardStepRenderer,
|
|
740
|
+
WizardStore,
|
|
390
741
|
YupAdapter,
|
|
391
742
|
ZodAdapter,
|
|
743
|
+
createWizardFactory,
|
|
392
744
|
getByPath,
|
|
393
745
|
setByPath,
|
|
394
746
|
useWizard,
|
|
395
|
-
|
|
747
|
+
useWizardActions,
|
|
748
|
+
useWizardContext,
|
|
749
|
+
useWizardError,
|
|
750
|
+
useWizardSelector,
|
|
751
|
+
useWizardState,
|
|
752
|
+
useWizardValue
|
|
396
753
|
});
|
|
397
754
|
//# sourceMappingURL=index.cjs.map
|