@wizzard-packages/react 0.1.0 → 0.3.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/LICENSE +1 -1
- package/README.md +354 -0
- package/dist/index.cjs +573 -89
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +127 -17
- package/dist/index.d.ts +127 -17
- package/dist/index.js +566 -88
- package/dist/index.js.map +1 -1
- package/package.json +14 -4
package/dist/index.cjs
CHANGED
|
@@ -22,24 +22,110 @@ var index_exports = {};
|
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
WizardProvider: () => WizardProvider,
|
|
24
24
|
WizardStepRenderer: () => WizardStepRenderer,
|
|
25
|
-
WizardStore: () =>
|
|
25
|
+
WizardStore: () => import_core4.WizardStore,
|
|
26
26
|
createWizardFactory: () => createWizardFactory,
|
|
27
|
+
createWizardHooks: () => createWizardHooks,
|
|
28
|
+
createWizardStore: () => createWizardStore,
|
|
27
29
|
loggerMiddleware: () => import_middleware.loggerMiddleware,
|
|
28
30
|
useWizard: () => useWizard,
|
|
29
31
|
useWizardActions: () => useWizardActions,
|
|
32
|
+
useWizardAllErrors: () => useWizardAllErrors,
|
|
30
33
|
useWizardContext: () => useWizardContext,
|
|
34
|
+
useWizardCurrentStep: () => useWizardCurrentStep,
|
|
31
35
|
useWizardError: () => useWizardError,
|
|
36
|
+
useWizardField: () => useWizardField,
|
|
37
|
+
useWizardFlatErrors: () => useWizardFlatErrors,
|
|
38
|
+
useWizardMeta: () => useWizardMeta,
|
|
32
39
|
useWizardSelector: () => useWizardSelector,
|
|
33
40
|
useWizardState: () => useWizardState,
|
|
41
|
+
useWizardSteps: () => useWizardSteps,
|
|
42
|
+
useWizardStoreError: () => useWizardStoreError,
|
|
43
|
+
useWizardStoreField: () => useWizardStoreField,
|
|
44
|
+
useWizardStoreSelector: () => useWizardStoreSelector,
|
|
45
|
+
useWizardStoreState: () => useWizardStoreState,
|
|
46
|
+
useWizardStoreValue: () => useWizardStoreValue,
|
|
34
47
|
useWizardValue: () => useWizardValue
|
|
35
48
|
});
|
|
36
49
|
module.exports = __toCommonJS(index_exports);
|
|
37
50
|
|
|
38
51
|
// src/context/WizardContext.tsx
|
|
39
52
|
var import_react = require("react");
|
|
40
|
-
var
|
|
53
|
+
var import_core2 = require("@wizzard-packages/core");
|
|
41
54
|
var import_persistence = require("@wizzard-packages/persistence");
|
|
55
|
+
|
|
56
|
+
// src/internal/dependencies.ts
|
|
57
|
+
var import_core = require("@wizzard-packages/core");
|
|
58
|
+
var applyStepDependencies = (config, store, baseData, changedPaths) => {
|
|
59
|
+
let currentData = { ...baseData };
|
|
60
|
+
const allClearedPaths = /* @__PURE__ */ new Set();
|
|
61
|
+
const snapshot = store.getSnapshot();
|
|
62
|
+
const nextCompletedSteps = new Set(snapshot.completedSteps);
|
|
63
|
+
const nextVisitedSteps = new Set(snapshot.visitedSteps);
|
|
64
|
+
let statusChanged = false;
|
|
65
|
+
const processDependencies = (paths) => {
|
|
66
|
+
const newlyClearedPaths = [];
|
|
67
|
+
config.steps.forEach((step) => {
|
|
68
|
+
const isDependent = step.dependsOn?.some(
|
|
69
|
+
(p) => paths.some((path) => path === p || p.startsWith(path + ".") || path.startsWith(p + "."))
|
|
70
|
+
);
|
|
71
|
+
if (!isDependent) return;
|
|
72
|
+
if (nextCompletedSteps.delete(step.id)) {
|
|
73
|
+
statusChanged = true;
|
|
74
|
+
}
|
|
75
|
+
if (nextVisitedSteps.delete(step.id)) {
|
|
76
|
+
statusChanged = true;
|
|
77
|
+
}
|
|
78
|
+
if (!step.clearData) return;
|
|
79
|
+
if (typeof step.clearData === "function") {
|
|
80
|
+
const patch = step.clearData(currentData, paths);
|
|
81
|
+
Object.keys(patch).forEach((key) => {
|
|
82
|
+
if (currentData[key] !== patch[key]) {
|
|
83
|
+
currentData[key] = patch[key];
|
|
84
|
+
newlyClearedPaths.push(key);
|
|
85
|
+
allClearedPaths.add(key);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
} else {
|
|
89
|
+
const pathsToClear = Array.isArray(step.clearData) ? step.clearData : [step.clearData];
|
|
90
|
+
pathsToClear.forEach((p) => {
|
|
91
|
+
const val = (0, import_core.getByPath)(currentData, p);
|
|
92
|
+
if (val !== void 0) {
|
|
93
|
+
currentData = (0, import_core.setByPath)(currentData, p, void 0);
|
|
94
|
+
newlyClearedPaths.push(p);
|
|
95
|
+
allClearedPaths.add(p);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
if (newlyClearedPaths.length > 0) {
|
|
101
|
+
processDependencies(newlyClearedPaths);
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
processDependencies(changedPaths);
|
|
105
|
+
return {
|
|
106
|
+
newData: currentData,
|
|
107
|
+
hasClearing: allClearedPaths.size > 0,
|
|
108
|
+
clearedPaths: Array.from(allClearedPaths),
|
|
109
|
+
statusChanged,
|
|
110
|
+
nextCompletedSteps,
|
|
111
|
+
nextVisitedSteps
|
|
112
|
+
};
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
// src/context/WizardContext.tsx
|
|
42
116
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
117
|
+
var UNSET = /* @__PURE__ */ Symbol("wizard_unset");
|
|
118
|
+
var shallowEqual = (a, b) => {
|
|
119
|
+
if (a === b) return true;
|
|
120
|
+
if (!a || !b) return false;
|
|
121
|
+
const aKeys = Object.keys(a);
|
|
122
|
+
const bKeys = Object.keys(b);
|
|
123
|
+
if (aKeys.length !== bKeys.length) return false;
|
|
124
|
+
for (const key of aKeys) {
|
|
125
|
+
if (!Object.is(a[key], b[key])) return false;
|
|
126
|
+
}
|
|
127
|
+
return true;
|
|
128
|
+
};
|
|
43
129
|
var WizardStateContext = (0, import_react.createContext)(void 0);
|
|
44
130
|
var WizardActionsContext = (0, import_react.createContext)(void 0);
|
|
45
131
|
var WizardStoreContext = (0, import_react.createContext)(void 0);
|
|
@@ -52,16 +138,17 @@ function WizardProvider({
|
|
|
52
138
|
const [localConfig, setLocalConfig] = (0, import_react.useState)(config);
|
|
53
139
|
const storeRef = (0, import_react.useRef)(null);
|
|
54
140
|
if (!storeRef.current) {
|
|
55
|
-
storeRef.current = new
|
|
141
|
+
storeRef.current = new import_core2.WizardStore(initialData || {}, config.middlewares);
|
|
56
142
|
}
|
|
57
143
|
const isInitialized = (0, import_react.useRef)(false);
|
|
58
144
|
const persistenceAdapter = (0, import_react.useMemo)(() => {
|
|
59
145
|
return localConfig.persistence?.adapter || new import_persistence.MemoryAdapter();
|
|
60
146
|
}, [localConfig.persistence?.adapter]);
|
|
61
147
|
const persistenceMode = localConfig.persistence?.mode || "onStepChange";
|
|
62
|
-
const
|
|
148
|
+
const META_KEY2 = "__wizzard_meta__";
|
|
63
149
|
const snapshot = (0, import_react.useSyncExternalStore)(
|
|
64
150
|
storeRef.current.subscribe,
|
|
151
|
+
storeRef.current.getSnapshot,
|
|
65
152
|
storeRef.current.getSnapshot
|
|
66
153
|
);
|
|
67
154
|
const {
|
|
@@ -175,83 +262,23 @@ function WizardProvider({
|
|
|
175
262
|
const idx = activeStepsIndexMap2.get(currentStepId2) ?? -1;
|
|
176
263
|
if (idx > 0) await goToStep(activeSteps2[idx - 1].id);
|
|
177
264
|
}, [goToStep]);
|
|
178
|
-
const
|
|
179
|
-
(
|
|
180
|
-
|
|
181
|
-
const
|
|
182
|
-
|
|
183
|
-
const
|
|
184
|
-
const
|
|
185
|
-
let statusChanged = false;
|
|
186
|
-
const processDependencies = (changedPaths) => {
|
|
187
|
-
const newlyClearedPaths = [];
|
|
188
|
-
localConfig.steps.forEach((step) => {
|
|
189
|
-
const isDependent = step.dependsOn?.some(
|
|
190
|
-
(p) => changedPaths.some(
|
|
191
|
-
(path) => path === p || p.startsWith(path + ".") || path.startsWith(p + ".")
|
|
192
|
-
)
|
|
193
|
-
);
|
|
194
|
-
if (isDependent) {
|
|
195
|
-
if (nextComp.delete(step.id)) {
|
|
196
|
-
statusChanged = true;
|
|
197
|
-
}
|
|
198
|
-
if (nextVis.delete(step.id)) {
|
|
199
|
-
statusChanged = true;
|
|
200
|
-
}
|
|
201
|
-
if (step.clearData) {
|
|
202
|
-
if (typeof step.clearData === "function") {
|
|
203
|
-
const patch = step.clearData(currentData, changedPaths);
|
|
204
|
-
Object.keys(patch).forEach((key) => {
|
|
205
|
-
if (currentData[key] !== patch[key]) {
|
|
206
|
-
currentData[key] = patch[key];
|
|
207
|
-
newlyClearedPaths.push(key);
|
|
208
|
-
allClearedPaths.add(key);
|
|
209
|
-
}
|
|
210
|
-
});
|
|
211
|
-
} else {
|
|
212
|
-
const pathsToClear = Array.isArray(step.clearData) ? step.clearData : [step.clearData];
|
|
213
|
-
pathsToClear.forEach((p) => {
|
|
214
|
-
const val = (0, import_core.getByPath)(currentData, p);
|
|
215
|
-
if (val !== void 0) {
|
|
216
|
-
currentData = (0, import_core.setByPath)(currentData, p, void 0);
|
|
217
|
-
newlyClearedPaths.push(p);
|
|
218
|
-
allClearedPaths.add(p);
|
|
219
|
-
}
|
|
220
|
-
});
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
});
|
|
225
|
-
if (newlyClearedPaths.length > 0) {
|
|
226
|
-
processDependencies(newlyClearedPaths);
|
|
227
|
-
}
|
|
228
|
-
};
|
|
229
|
-
processDependencies(paths);
|
|
265
|
+
const setData = (0, import_react.useCallback)(
|
|
266
|
+
(path, value, options) => {
|
|
267
|
+
const { stepsMap: stepsMap2, currentStepId: currentStepId2 } = stateRef.current;
|
|
268
|
+
const prevData = storeRef.current.getSnapshot().data;
|
|
269
|
+
if ((0, import_core2.getByPath)(prevData, path) === value) return;
|
|
270
|
+
const baseData = (0, import_core2.setByPath)(prevData, path, value);
|
|
271
|
+
const { newData, hasClearing, statusChanged, nextCompletedSteps, nextVisitedSteps } = applyStepDependencies(localConfig, storeRef.current, baseData, [path]);
|
|
230
272
|
if (statusChanged) {
|
|
231
273
|
storeRef.current.dispatch({
|
|
232
274
|
type: "SET_COMPLETED_STEPS",
|
|
233
|
-
payload: { steps:
|
|
275
|
+
payload: { steps: nextCompletedSteps }
|
|
234
276
|
});
|
|
235
277
|
storeRef.current.dispatch({
|
|
236
278
|
type: "SET_VISITED_STEPS",
|
|
237
|
-
payload: { steps:
|
|
279
|
+
payload: { steps: nextVisitedSteps }
|
|
238
280
|
});
|
|
239
281
|
}
|
|
240
|
-
return {
|
|
241
|
-
newData: currentData,
|
|
242
|
-
hasClearing: allClearedPaths.size > 0,
|
|
243
|
-
clearedPaths: Array.from(allClearedPaths)
|
|
244
|
-
};
|
|
245
|
-
},
|
|
246
|
-
[localConfig.steps]
|
|
247
|
-
);
|
|
248
|
-
const setData = (0, import_react.useCallback)(
|
|
249
|
-
(path, value, options) => {
|
|
250
|
-
const { stepsMap: stepsMap2, currentStepId: currentStepId2 } = stateRef.current;
|
|
251
|
-
const prevData = storeRef.current.getSnapshot().data;
|
|
252
|
-
if ((0, import_core.getByPath)(prevData, path) === value) return;
|
|
253
|
-
const baseData = (0, import_core.setByPath)(prevData, path, value);
|
|
254
|
-
const { newData, hasClearing } = handleStepDependencies([path], baseData);
|
|
255
282
|
if (!hasClearing) {
|
|
256
283
|
storeRef.current.dispatch({
|
|
257
284
|
type: "SET_DATA",
|
|
@@ -285,13 +312,23 @@ function WizardProvider({
|
|
|
285
312
|
}
|
|
286
313
|
}
|
|
287
314
|
},
|
|
288
|
-
[localConfig, validateStep
|
|
315
|
+
[localConfig, validateStep]
|
|
289
316
|
);
|
|
290
317
|
const updateData = (0, import_react.useCallback)(
|
|
291
318
|
(data2, options) => {
|
|
292
319
|
const prev = storeRef.current.getSnapshot().data;
|
|
293
320
|
const baseData = options?.replace ? data2 : { ...prev, ...data2 };
|
|
294
|
-
const { newData } =
|
|
321
|
+
const { newData, statusChanged, nextCompletedSteps, nextVisitedSteps } = applyStepDependencies(localConfig, storeRef.current, baseData, Object.keys(data2));
|
|
322
|
+
if (statusChanged) {
|
|
323
|
+
storeRef.current.dispatch({
|
|
324
|
+
type: "SET_COMPLETED_STEPS",
|
|
325
|
+
payload: { steps: nextCompletedSteps }
|
|
326
|
+
});
|
|
327
|
+
storeRef.current.dispatch({
|
|
328
|
+
type: "SET_VISITED_STEPS",
|
|
329
|
+
payload: { steps: nextVisitedSteps }
|
|
330
|
+
});
|
|
331
|
+
}
|
|
295
332
|
storeRef.current.update(newData, Object.keys(data2));
|
|
296
333
|
if (options?.persist) {
|
|
297
334
|
if (storeRef.current.save) {
|
|
@@ -299,7 +336,7 @@ function WizardProvider({
|
|
|
299
336
|
}
|
|
300
337
|
}
|
|
301
338
|
},
|
|
302
|
-
[
|
|
339
|
+
[localConfig]
|
|
303
340
|
);
|
|
304
341
|
const reset = (0, import_react.useCallback)(() => {
|
|
305
342
|
storeRef.current.setInitialData(initialData || {});
|
|
@@ -394,7 +431,7 @@ function WizardProvider({
|
|
|
394
431
|
reset,
|
|
395
432
|
setData,
|
|
396
433
|
updateData,
|
|
397
|
-
getData: (p, d) => (0,
|
|
434
|
+
getData: (p, d) => (0, import_core2.getByPath)(storeRef.current.getSnapshot().data, p, d),
|
|
398
435
|
updateConfig: (nc) => {
|
|
399
436
|
setLocalConfig((prev) => ({ ...prev, ...nc }));
|
|
400
437
|
}
|
|
@@ -445,7 +482,7 @@ function WizardProvider({
|
|
|
445
482
|
(0, import_react.useEffect)(() => {
|
|
446
483
|
if (hasHydratedRef.current) return;
|
|
447
484
|
hasHydratedRef.current = true;
|
|
448
|
-
const meta = persistenceAdapter.getStep(
|
|
485
|
+
const meta = persistenceAdapter.getStep(META_KEY2);
|
|
449
486
|
if (meta) {
|
|
450
487
|
if (meta.currentStepId) {
|
|
451
488
|
storeRef.current.dispatch({
|
|
@@ -508,12 +545,14 @@ function useWizardValue(path, options) {
|
|
|
508
545
|
const store = (0, import_react.useContext)(WizardStoreContext);
|
|
509
546
|
if (!store) throw new Error("useWizardValue must be used within a WizardProvider");
|
|
510
547
|
const lastStateRef = (0, import_react.useRef)(null);
|
|
511
|
-
const lastValueRef = (0, import_react.useRef)(
|
|
548
|
+
const lastValueRef = (0, import_react.useRef)(UNSET);
|
|
512
549
|
const getSnapshot = (0, import_react.useCallback)(() => {
|
|
513
550
|
const data = store.getSnapshot().data;
|
|
514
|
-
if (data === lastStateRef.current
|
|
515
|
-
|
|
516
|
-
|
|
551
|
+
if (data === lastStateRef.current && lastValueRef.current !== UNSET) {
|
|
552
|
+
return lastValueRef.current;
|
|
553
|
+
}
|
|
554
|
+
const value = (0, import_core2.getByPath)(data, path);
|
|
555
|
+
if (lastValueRef.current !== UNSET && (options?.isEqual || Object.is)(lastValueRef.current, value)) {
|
|
517
556
|
lastStateRef.current = data;
|
|
518
557
|
return lastValueRef.current;
|
|
519
558
|
}
|
|
@@ -521,7 +560,18 @@ function useWizardValue(path, options) {
|
|
|
521
560
|
lastValueRef.current = value;
|
|
522
561
|
return value;
|
|
523
562
|
}, [store, path, options?.isEqual]);
|
|
524
|
-
return (0, import_react.useSyncExternalStore)(store.subscribe, getSnapshot);
|
|
563
|
+
return (0, import_react.useSyncExternalStore)(store.subscribe, getSnapshot, getSnapshot);
|
|
564
|
+
}
|
|
565
|
+
function useWizardField(path, options) {
|
|
566
|
+
const value = useWizardValue(path, options);
|
|
567
|
+
const { setData } = useWizardActions();
|
|
568
|
+
const setValue = (0, import_react.useCallback)(
|
|
569
|
+
(next) => {
|
|
570
|
+
setData(path, next);
|
|
571
|
+
},
|
|
572
|
+
[setData, path]
|
|
573
|
+
);
|
|
574
|
+
return [value, setValue];
|
|
525
575
|
}
|
|
526
576
|
function useWizardError(path) {
|
|
527
577
|
const store = (0, import_react.useContext)(WizardStoreContext);
|
|
@@ -534,22 +584,22 @@ function useWizardError(path) {
|
|
|
534
584
|
}
|
|
535
585
|
return void 0;
|
|
536
586
|
}, [store, path]);
|
|
537
|
-
return (0, import_react.useSyncExternalStore)(store.subscribe, getSnapshot);
|
|
587
|
+
return (0, import_react.useSyncExternalStore)(store.subscribe, getSnapshot, getSnapshot);
|
|
538
588
|
}
|
|
539
589
|
function useWizardSelector(selector, options) {
|
|
540
590
|
const store = (0, import_react.useContext)(WizardStoreContext);
|
|
541
591
|
if (!store) throw new Error("useWizardSelector must be used within a WizardProvider");
|
|
542
|
-
const lastResultRef = (0, import_react.useRef)(
|
|
592
|
+
const lastResultRef = (0, import_react.useRef)(UNSET);
|
|
543
593
|
const getSnapshot = (0, import_react.useCallback)(() => {
|
|
544
594
|
const full = store.getSnapshot();
|
|
545
595
|
const res = selector(full);
|
|
546
|
-
if (lastResultRef.current !==
|
|
596
|
+
if (lastResultRef.current !== UNSET && (options?.isEqual || Object.is)(lastResultRef.current, res)) {
|
|
547
597
|
return lastResultRef.current;
|
|
548
598
|
}
|
|
549
599
|
lastResultRef.current = res;
|
|
550
600
|
return res;
|
|
551
601
|
}, [store, selector, options?.isEqual]);
|
|
552
|
-
return (0, import_react.useSyncExternalStore)(store.subscribe, getSnapshot);
|
|
602
|
+
return (0, import_react.useSyncExternalStore)(store.subscribe, getSnapshot, getSnapshot);
|
|
553
603
|
}
|
|
554
604
|
function useWizardActions() {
|
|
555
605
|
const context = (0, import_react.useContext)(WizardActionsContext);
|
|
@@ -582,6 +632,44 @@ function useWizardContext() {
|
|
|
582
632
|
[stateProps, actions, data, allErrors, errors, store]
|
|
583
633
|
);
|
|
584
634
|
}
|
|
635
|
+
function useWizardCurrentStep() {
|
|
636
|
+
return useWizardSelector((s) => s.currentStep);
|
|
637
|
+
}
|
|
638
|
+
function useWizardSteps() {
|
|
639
|
+
return useWizardSelector((s) => s.activeSteps);
|
|
640
|
+
}
|
|
641
|
+
function useWizardMeta() {
|
|
642
|
+
return useWizardSelector(
|
|
643
|
+
(s) => ({
|
|
644
|
+
currentStepId: s.currentStepId,
|
|
645
|
+
currentStepIndex: s.currentStepIndex,
|
|
646
|
+
isFirstStep: s.isFirstStep,
|
|
647
|
+
isLastStep: s.isLastStep,
|
|
648
|
+
isLoading: s.isLoading,
|
|
649
|
+
isBusy: s.isBusy,
|
|
650
|
+
isDirty: s.isDirty,
|
|
651
|
+
progress: s.progress,
|
|
652
|
+
activeStepsCount: s.activeStepsCount,
|
|
653
|
+
goToStepResult: s.goToStepResult
|
|
654
|
+
}),
|
|
655
|
+
{ isEqual: shallowEqual }
|
|
656
|
+
);
|
|
657
|
+
}
|
|
658
|
+
function useWizardAllErrors() {
|
|
659
|
+
return useWizardSelector((s) => s.errors, {
|
|
660
|
+
isEqual: shallowEqual
|
|
661
|
+
});
|
|
662
|
+
}
|
|
663
|
+
function useWizardFlatErrors() {
|
|
664
|
+
const allErrors = useWizardAllErrors();
|
|
665
|
+
return (0, import_react.useMemo)(() => {
|
|
666
|
+
const flat = {};
|
|
667
|
+
Object.values(allErrors).forEach((stepErrors) => {
|
|
668
|
+
Object.assign(flat, stepErrors);
|
|
669
|
+
});
|
|
670
|
+
return flat;
|
|
671
|
+
}, [allErrors]);
|
|
672
|
+
}
|
|
585
673
|
|
|
586
674
|
// src/hooks/useWizard.ts
|
|
587
675
|
var useWizard = () => {
|
|
@@ -594,9 +682,18 @@ function createWizardFactory() {
|
|
|
594
682
|
const WizardProvider2 = ({
|
|
595
683
|
config,
|
|
596
684
|
initialData,
|
|
685
|
+
initialStepId,
|
|
597
686
|
children
|
|
598
687
|
}) => {
|
|
599
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
688
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
689
|
+
WizardProvider,
|
|
690
|
+
{
|
|
691
|
+
config,
|
|
692
|
+
initialData,
|
|
693
|
+
initialStepId,
|
|
694
|
+
children
|
|
695
|
+
}
|
|
696
|
+
);
|
|
600
697
|
};
|
|
601
698
|
const useWizard2 = () => {
|
|
602
699
|
return useWizard();
|
|
@@ -607,6 +704,11 @@ function createWizardFactory() {
|
|
|
607
704
|
const useWizardValue2 = (path, options) => {
|
|
608
705
|
return useWizardValue(path, options);
|
|
609
706
|
};
|
|
707
|
+
const useWizardField2 = (path, options) => {
|
|
708
|
+
const value = useWizardValue2(path, options);
|
|
709
|
+
const { setData } = useWizardActions2();
|
|
710
|
+
return [value, (next) => setData(path, next)];
|
|
711
|
+
};
|
|
610
712
|
const useWizardSelector2 = (selector, options) => {
|
|
611
713
|
return useWizardSelector(selector, options);
|
|
612
714
|
};
|
|
@@ -628,6 +730,7 @@ function createWizardFactory() {
|
|
|
628
730
|
useWizard: useWizard2,
|
|
629
731
|
useWizardContext: useWizardContext2,
|
|
630
732
|
useWizardValue: useWizardValue2,
|
|
733
|
+
useWizardField: useWizardField2,
|
|
631
734
|
useWizardSelector: useWizardSelector2,
|
|
632
735
|
useWizardError: useWizardError2,
|
|
633
736
|
useWizardActions: useWizardActions2,
|
|
@@ -659,8 +762,376 @@ var WizardStepRenderer = ({
|
|
|
659
762
|
return content;
|
|
660
763
|
};
|
|
661
764
|
|
|
765
|
+
// src/store.ts
|
|
766
|
+
var import_react3 = require("react");
|
|
767
|
+
var import_core3 = require("@wizzard-packages/core");
|
|
768
|
+
var import_persistence2 = require("@wizzard-packages/persistence");
|
|
769
|
+
var UNSET2 = /* @__PURE__ */ Symbol("wizard_store_unset");
|
|
770
|
+
var META_KEY = "__wizzard_meta__";
|
|
771
|
+
var applyStoredMeta = (store, adapter) => {
|
|
772
|
+
const meta = adapter.getStep(META_KEY);
|
|
773
|
+
if (!meta) return;
|
|
774
|
+
if (meta.currentStepId) {
|
|
775
|
+
store.dispatch({
|
|
776
|
+
type: "SET_CURRENT_STEP_ID",
|
|
777
|
+
payload: { stepId: meta.currentStepId }
|
|
778
|
+
});
|
|
779
|
+
}
|
|
780
|
+
if (meta.visited) {
|
|
781
|
+
store.dispatch({
|
|
782
|
+
type: "SET_VISITED_STEPS",
|
|
783
|
+
payload: { steps: new Set(meta.visited) }
|
|
784
|
+
});
|
|
785
|
+
}
|
|
786
|
+
if (meta.completed) {
|
|
787
|
+
store.dispatch({
|
|
788
|
+
type: "SET_COMPLETED_STEPS",
|
|
789
|
+
payload: { steps: new Set(meta.completed) }
|
|
790
|
+
});
|
|
791
|
+
}
|
|
792
|
+
if (meta.history) {
|
|
793
|
+
store.dispatch({
|
|
794
|
+
type: "SET_HISTORY",
|
|
795
|
+
payload: { history: meta.history }
|
|
796
|
+
});
|
|
797
|
+
}
|
|
798
|
+
};
|
|
799
|
+
var ensureInitialStep = (store, activeSteps, initialStepId) => {
|
|
800
|
+
const snapshot = store.getSnapshot();
|
|
801
|
+
if (snapshot.currentStepId || activeSteps.length === 0) return;
|
|
802
|
+
const startId = initialStepId && activeSteps.some((s) => s.id === initialStepId) ? initialStepId : activeSteps[0].id;
|
|
803
|
+
store.dispatch({
|
|
804
|
+
type: "SET_CURRENT_STEP_ID",
|
|
805
|
+
payload: { stepId: startId }
|
|
806
|
+
});
|
|
807
|
+
if (snapshot.history.length === 0) {
|
|
808
|
+
store.dispatch({
|
|
809
|
+
type: "SET_HISTORY",
|
|
810
|
+
payload: { history: [startId] }
|
|
811
|
+
});
|
|
812
|
+
}
|
|
813
|
+
const currentVisited = new Set(snapshot.visitedSteps);
|
|
814
|
+
if (!currentVisited.has(startId)) {
|
|
815
|
+
currentVisited.add(startId);
|
|
816
|
+
store.dispatch({
|
|
817
|
+
type: "SET_VISITED_STEPS",
|
|
818
|
+
payload: { steps: currentVisited }
|
|
819
|
+
});
|
|
820
|
+
}
|
|
821
|
+
};
|
|
822
|
+
var resolveAndSetActiveSteps = async (store, data, initialStepId) => {
|
|
823
|
+
const resolved = await store.resolveActiveSteps(data);
|
|
824
|
+
store.dispatch({
|
|
825
|
+
type: "SET_ACTIVE_STEPS",
|
|
826
|
+
payload: { steps: resolved }
|
|
827
|
+
});
|
|
828
|
+
ensureInitialStep(store, resolved, initialStepId);
|
|
829
|
+
const snapshot = store.getSnapshot();
|
|
830
|
+
if (resolved.length > 0 && snapshot.isLoading) {
|
|
831
|
+
store.updateMeta({ isLoading: false });
|
|
832
|
+
}
|
|
833
|
+
};
|
|
834
|
+
var createWizardActions = (store, config, persistenceAdapter, initialData) => {
|
|
835
|
+
let currentConfig = config;
|
|
836
|
+
const validationDebounceRef = { current: null };
|
|
837
|
+
const stepsMap = /* @__PURE__ */ new Map();
|
|
838
|
+
currentConfig.steps.forEach((step) => stepsMap.set(step.id, step));
|
|
839
|
+
const resolveActiveStepsHelper = (data) => store.resolveActiveSteps(data);
|
|
840
|
+
const validateStep = (stepId) => store.validateStep(stepId);
|
|
841
|
+
const setData = (path, value, options) => {
|
|
842
|
+
const prevData = store.getSnapshot().data;
|
|
843
|
+
if ((0, import_core3.getByPath)(prevData, path) === value) return;
|
|
844
|
+
const baseData = (0, import_core3.setByPath)(prevData, path, value);
|
|
845
|
+
const { newData, hasClearing, statusChanged, nextCompletedSteps, nextVisitedSteps } = applyStepDependencies(currentConfig, store, baseData, [path]);
|
|
846
|
+
if (statusChanged) {
|
|
847
|
+
store.dispatch({
|
|
848
|
+
type: "SET_COMPLETED_STEPS",
|
|
849
|
+
payload: { steps: nextCompletedSteps }
|
|
850
|
+
});
|
|
851
|
+
store.dispatch({
|
|
852
|
+
type: "SET_VISITED_STEPS",
|
|
853
|
+
payload: { steps: nextVisitedSteps }
|
|
854
|
+
});
|
|
855
|
+
}
|
|
856
|
+
if (!hasClearing) {
|
|
857
|
+
store.dispatch({
|
|
858
|
+
type: "SET_DATA",
|
|
859
|
+
payload: {
|
|
860
|
+
path,
|
|
861
|
+
value,
|
|
862
|
+
options: { ...options, __from_set_data__: true }
|
|
863
|
+
}
|
|
864
|
+
});
|
|
865
|
+
} else {
|
|
866
|
+
store.dispatch({
|
|
867
|
+
type: "UPDATE_DATA",
|
|
868
|
+
payload: {
|
|
869
|
+
data: newData,
|
|
870
|
+
options: { replace: true, __from_set_data__: true, path }
|
|
871
|
+
}
|
|
872
|
+
});
|
|
873
|
+
}
|
|
874
|
+
const snapshot = store.getSnapshot();
|
|
875
|
+
const currentStepId = snapshot.currentStepId;
|
|
876
|
+
if (currentStepId) {
|
|
877
|
+
store.deleteError(currentStepId, path);
|
|
878
|
+
const step = stepsMap.get(currentStepId);
|
|
879
|
+
const mode = step?.validationMode || currentConfig.validationMode || "onStepChange";
|
|
880
|
+
if (mode === "onChange") {
|
|
881
|
+
const debounceMs = options?.debounceValidation ?? currentConfig.validationDebounceTime ?? 300;
|
|
882
|
+
if (validationDebounceRef.current) {
|
|
883
|
+
clearTimeout(validationDebounceRef.current);
|
|
884
|
+
}
|
|
885
|
+
validationDebounceRef.current = setTimeout(() => {
|
|
886
|
+
void validateStep(currentStepId);
|
|
887
|
+
}, debounceMs);
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
};
|
|
891
|
+
const updateData = (data, options) => {
|
|
892
|
+
const prev = store.getSnapshot().data;
|
|
893
|
+
const baseData = options?.replace ? data : { ...prev, ...data };
|
|
894
|
+
const { newData, statusChanged, nextCompletedSteps, nextVisitedSteps } = applyStepDependencies(
|
|
895
|
+
currentConfig,
|
|
896
|
+
store,
|
|
897
|
+
baseData,
|
|
898
|
+
Object.keys(data)
|
|
899
|
+
);
|
|
900
|
+
if (statusChanged) {
|
|
901
|
+
store.dispatch({
|
|
902
|
+
type: "SET_COMPLETED_STEPS",
|
|
903
|
+
payload: { steps: nextCompletedSteps }
|
|
904
|
+
});
|
|
905
|
+
store.dispatch({
|
|
906
|
+
type: "SET_VISITED_STEPS",
|
|
907
|
+
payload: { steps: nextVisitedSteps }
|
|
908
|
+
});
|
|
909
|
+
}
|
|
910
|
+
store.update(newData, Object.keys(data));
|
|
911
|
+
if (options?.persist) {
|
|
912
|
+
store.save(store.getSnapshot().currentStepId);
|
|
913
|
+
}
|
|
914
|
+
};
|
|
915
|
+
const reset = () => {
|
|
916
|
+
store.setInitialData(initialData || {});
|
|
917
|
+
store.update(initialData || {});
|
|
918
|
+
store.updateErrors({});
|
|
919
|
+
store.dispatch({
|
|
920
|
+
type: "SET_VISITED_STEPS",
|
|
921
|
+
payload: { steps: /* @__PURE__ */ new Set() }
|
|
922
|
+
});
|
|
923
|
+
store.dispatch({
|
|
924
|
+
type: "SET_COMPLETED_STEPS",
|
|
925
|
+
payload: { steps: /* @__PURE__ */ new Set() }
|
|
926
|
+
});
|
|
927
|
+
store.dispatch({
|
|
928
|
+
type: "SET_ERROR_STEPS",
|
|
929
|
+
payload: { steps: /* @__PURE__ */ new Set() }
|
|
930
|
+
});
|
|
931
|
+
const snapshot = store.getSnapshot();
|
|
932
|
+
if (snapshot.activeSteps.length > 0) {
|
|
933
|
+
const startId = snapshot.activeSteps[0].id;
|
|
934
|
+
store.dispatch({
|
|
935
|
+
type: "SET_CURRENT_STEP_ID",
|
|
936
|
+
payload: { stepId: startId }
|
|
937
|
+
});
|
|
938
|
+
store.dispatch({
|
|
939
|
+
type: "SET_HISTORY",
|
|
940
|
+
payload: { history: [startId] }
|
|
941
|
+
});
|
|
942
|
+
} else {
|
|
943
|
+
store.dispatch({
|
|
944
|
+
type: "SET_CURRENT_STEP_ID",
|
|
945
|
+
payload: { stepId: "" }
|
|
946
|
+
});
|
|
947
|
+
store.dispatch({
|
|
948
|
+
type: "SET_HISTORY",
|
|
949
|
+
payload: { history: [] }
|
|
950
|
+
});
|
|
951
|
+
}
|
|
952
|
+
persistenceAdapter.clear();
|
|
953
|
+
currentConfig.analytics?.onEvent("wizard_reset", { data: initialData });
|
|
954
|
+
};
|
|
955
|
+
const goToStep = (stepId, providedActiveSteps, options) => {
|
|
956
|
+
return store.goToStep(stepId, {
|
|
957
|
+
validate: options?.validate ?? true,
|
|
958
|
+
providedActiveSteps
|
|
959
|
+
});
|
|
960
|
+
};
|
|
961
|
+
const goToNextStep = async () => {
|
|
962
|
+
const snapshot = store.getSnapshot();
|
|
963
|
+
const currentStepId = snapshot.currentStepId;
|
|
964
|
+
if (!currentStepId) return;
|
|
965
|
+
const step = stepsMap.get(currentStepId);
|
|
966
|
+
const shouldVal = step?.autoValidate ?? currentConfig.autoValidate ?? !!step?.validationAdapter;
|
|
967
|
+
if (shouldVal) {
|
|
968
|
+
const ok = await validateStep(currentStepId);
|
|
969
|
+
if (!ok) return;
|
|
970
|
+
}
|
|
971
|
+
const resolvedSteps = await resolveActiveStepsHelper(snapshot.data);
|
|
972
|
+
const idx = resolvedSteps.findIndex((s) => s.id === currentStepId);
|
|
973
|
+
if (idx !== -1 && idx < resolvedSteps.length - 1) {
|
|
974
|
+
const nextStepId = resolvedSteps[idx + 1].id;
|
|
975
|
+
const success = await goToStep(nextStepId, resolvedSteps, {
|
|
976
|
+
validate: false
|
|
977
|
+
});
|
|
978
|
+
if (success) {
|
|
979
|
+
const currentSnapshot = store.getSnapshot();
|
|
980
|
+
if (!currentSnapshot.errorSteps.has(currentStepId)) {
|
|
981
|
+
const nextComp = new Set(currentSnapshot.completedSteps);
|
|
982
|
+
nextComp.add(currentStepId);
|
|
983
|
+
store.dispatch({
|
|
984
|
+
type: "SET_COMPLETED_STEPS",
|
|
985
|
+
payload: { steps: nextComp }
|
|
986
|
+
});
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
};
|
|
991
|
+
const goToPrevStep = async () => {
|
|
992
|
+
const snapshot = store.getSnapshot();
|
|
993
|
+
const idx = snapshot.activeSteps.findIndex((s) => s.id === snapshot.currentStepId);
|
|
994
|
+
if (idx > 0) {
|
|
995
|
+
await goToStep(snapshot.activeSteps[idx - 1].id);
|
|
996
|
+
}
|
|
997
|
+
};
|
|
998
|
+
const setStepData = (_stepId, data) => {
|
|
999
|
+
const next = { ...store.getSnapshot().data, ...data };
|
|
1000
|
+
store.update(next, Object.keys(data));
|
|
1001
|
+
};
|
|
1002
|
+
const handleStepChange = (field, value) => {
|
|
1003
|
+
if (store.getSnapshot().currentStepId) {
|
|
1004
|
+
setData(field, value);
|
|
1005
|
+
}
|
|
1006
|
+
};
|
|
1007
|
+
const validateAll = async () => {
|
|
1008
|
+
const result = await store.validateAll();
|
|
1009
|
+
return result;
|
|
1010
|
+
};
|
|
1011
|
+
const save = (ids) => {
|
|
1012
|
+
if (ids === true) {
|
|
1013
|
+
currentConfig.steps.forEach((s) => store.save(s.id));
|
|
1014
|
+
} else if (!ids) {
|
|
1015
|
+
store.save();
|
|
1016
|
+
} else {
|
|
1017
|
+
(Array.isArray(ids) ? ids : [ids]).forEach((id) => store.save(id));
|
|
1018
|
+
}
|
|
1019
|
+
};
|
|
1020
|
+
const clearStorage = () => persistenceAdapter.clear();
|
|
1021
|
+
const getData = (path, defaultValue) => {
|
|
1022
|
+
return (0, import_core3.getByPath)(store.getSnapshot().data, path, defaultValue);
|
|
1023
|
+
};
|
|
1024
|
+
const updateConfig = (nextConfig) => {
|
|
1025
|
+
currentConfig = { ...currentConfig, ...nextConfig };
|
|
1026
|
+
stepsMap.clear();
|
|
1027
|
+
currentConfig.steps.forEach((step) => stepsMap.set(step.id, step));
|
|
1028
|
+
store.updateMeta({ config: currentConfig });
|
|
1029
|
+
};
|
|
1030
|
+
return {
|
|
1031
|
+
goToNextStep,
|
|
1032
|
+
goToPrevStep,
|
|
1033
|
+
goToStep,
|
|
1034
|
+
setStepData,
|
|
1035
|
+
handleStepChange,
|
|
1036
|
+
validateStep,
|
|
1037
|
+
validateAll,
|
|
1038
|
+
save,
|
|
1039
|
+
clearStorage,
|
|
1040
|
+
reset,
|
|
1041
|
+
setData,
|
|
1042
|
+
updateData,
|
|
1043
|
+
getData,
|
|
1044
|
+
updateConfig
|
|
1045
|
+
};
|
|
1046
|
+
};
|
|
1047
|
+
var createWizardStore = (options) => {
|
|
1048
|
+
const initialData = options.initialData || {};
|
|
1049
|
+
const store = new import_core3.WizardStore(initialData, options.config.middlewares);
|
|
1050
|
+
const persistenceAdapter = options.config.persistence?.adapter || new import_persistence2.MemoryAdapter();
|
|
1051
|
+
store.injectPersistence(persistenceAdapter);
|
|
1052
|
+
store.dispatch({
|
|
1053
|
+
type: "INIT",
|
|
1054
|
+
payload: { data: initialData, config: options.config }
|
|
1055
|
+
});
|
|
1056
|
+
store.hydrate();
|
|
1057
|
+
applyStoredMeta(store, persistenceAdapter);
|
|
1058
|
+
void resolveAndSetActiveSteps(store, store.getSnapshot().data, options.initialStepId);
|
|
1059
|
+
return {
|
|
1060
|
+
store,
|
|
1061
|
+
actions: createWizardActions(store, options.config, persistenceAdapter, initialData)
|
|
1062
|
+
};
|
|
1063
|
+
};
|
|
1064
|
+
var useWizardStoreState = (store) => {
|
|
1065
|
+
return (0, import_react3.useSyncExternalStore)(store.subscribe, store.getSnapshot, store.getSnapshot);
|
|
1066
|
+
};
|
|
1067
|
+
var useWizardStoreValue = (store, path, options) => {
|
|
1068
|
+
const lastStateRef = (0, import_react3.useRef)(UNSET2);
|
|
1069
|
+
const lastValueRef = (0, import_react3.useRef)(UNSET2);
|
|
1070
|
+
const getSnapshot = (0, import_react3.useCallback)(() => {
|
|
1071
|
+
const data = store.getSnapshot().data;
|
|
1072
|
+
if (data === lastStateRef.current && lastValueRef.current !== UNSET2) {
|
|
1073
|
+
return lastValueRef.current;
|
|
1074
|
+
}
|
|
1075
|
+
const value = (0, import_core3.getByPath)(data, path);
|
|
1076
|
+
if (lastValueRef.current !== UNSET2 && (options?.isEqual || Object.is)(lastValueRef.current, value)) {
|
|
1077
|
+
lastStateRef.current = data;
|
|
1078
|
+
return lastValueRef.current;
|
|
1079
|
+
}
|
|
1080
|
+
lastStateRef.current = data;
|
|
1081
|
+
lastValueRef.current = value;
|
|
1082
|
+
return value;
|
|
1083
|
+
}, [store, path, options?.isEqual]);
|
|
1084
|
+
return (0, import_react3.useSyncExternalStore)(store.subscribe, getSnapshot, getSnapshot);
|
|
1085
|
+
};
|
|
1086
|
+
var useWizardStoreField = (store, setData, path, options) => {
|
|
1087
|
+
const value = useWizardStoreValue(store, path, options);
|
|
1088
|
+
const setValue = (0, import_react3.useCallback)(
|
|
1089
|
+
(next) => {
|
|
1090
|
+
setData(path, next);
|
|
1091
|
+
},
|
|
1092
|
+
[setData, path]
|
|
1093
|
+
);
|
|
1094
|
+
return [value, setValue];
|
|
1095
|
+
};
|
|
1096
|
+
var useWizardStoreError = (store, path) => {
|
|
1097
|
+
const getSnapshot = (0, import_react3.useCallback)(() => {
|
|
1098
|
+
const errors = store.getSnapshot().errors;
|
|
1099
|
+
for (const [_, stepErrors] of Object.entries(errors)) {
|
|
1100
|
+
const typed = stepErrors;
|
|
1101
|
+
if (typed[path]) return typed[path];
|
|
1102
|
+
}
|
|
1103
|
+
return void 0;
|
|
1104
|
+
}, [store, path]);
|
|
1105
|
+
return (0, import_react3.useSyncExternalStore)(store.subscribe, getSnapshot, getSnapshot);
|
|
1106
|
+
};
|
|
1107
|
+
var useWizardStoreSelector = (store, selector, options) => {
|
|
1108
|
+
const lastResultRef = (0, import_react3.useRef)(UNSET2);
|
|
1109
|
+
const getSnapshot = (0, import_react3.useCallback)(() => {
|
|
1110
|
+
const full = store.getSnapshot();
|
|
1111
|
+
const res = selector(full);
|
|
1112
|
+
if (lastResultRef.current !== UNSET2 && (options?.isEqual || Object.is)(lastResultRef.current, res)) {
|
|
1113
|
+
return lastResultRef.current;
|
|
1114
|
+
}
|
|
1115
|
+
lastResultRef.current = res;
|
|
1116
|
+
return res;
|
|
1117
|
+
}, [store, selector, options?.isEqual]);
|
|
1118
|
+
return (0, import_react3.useSyncExternalStore)(store.subscribe, getSnapshot, getSnapshot);
|
|
1119
|
+
};
|
|
1120
|
+
var createWizardHooks = (store, actions) => ({
|
|
1121
|
+
useWizardState: () => useWizardStoreState(store),
|
|
1122
|
+
useWizardValue: (path, options) => useWizardStoreValue(store, path, options),
|
|
1123
|
+
useWizardField: (path, options) => {
|
|
1124
|
+
if (!actions) {
|
|
1125
|
+
throw new Error("useWizardField requires actions. Pass actions to createWizardHooks.");
|
|
1126
|
+
}
|
|
1127
|
+
return useWizardStoreField(store, actions.setData, path, options);
|
|
1128
|
+
},
|
|
1129
|
+
useWizardError: (path) => useWizardStoreError(store, path),
|
|
1130
|
+
useWizardSelector: (selector, options) => useWizardStoreSelector(store, selector, options)
|
|
1131
|
+
});
|
|
1132
|
+
|
|
662
1133
|
// src/index.ts
|
|
663
|
-
var
|
|
1134
|
+
var import_core4 = require("@wizzard-packages/core");
|
|
664
1135
|
var import_middleware = require("@wizzard-packages/middleware");
|
|
665
1136
|
// Annotate the CommonJS export names for ESM import in node:
|
|
666
1137
|
0 && (module.exports = {
|
|
@@ -668,13 +1139,26 @@ var import_middleware = require("@wizzard-packages/middleware");
|
|
|
668
1139
|
WizardStepRenderer,
|
|
669
1140
|
WizardStore,
|
|
670
1141
|
createWizardFactory,
|
|
1142
|
+
createWizardHooks,
|
|
1143
|
+
createWizardStore,
|
|
671
1144
|
loggerMiddleware,
|
|
672
1145
|
useWizard,
|
|
673
1146
|
useWizardActions,
|
|
1147
|
+
useWizardAllErrors,
|
|
674
1148
|
useWizardContext,
|
|
1149
|
+
useWizardCurrentStep,
|
|
675
1150
|
useWizardError,
|
|
1151
|
+
useWizardField,
|
|
1152
|
+
useWizardFlatErrors,
|
|
1153
|
+
useWizardMeta,
|
|
676
1154
|
useWizardSelector,
|
|
677
1155
|
useWizardState,
|
|
1156
|
+
useWizardSteps,
|
|
1157
|
+
useWizardStoreError,
|
|
1158
|
+
useWizardStoreField,
|
|
1159
|
+
useWizardStoreSelector,
|
|
1160
|
+
useWizardStoreState,
|
|
1161
|
+
useWizardStoreValue,
|
|
678
1162
|
useWizardValue
|
|
679
1163
|
});
|
|
680
1164
|
//# sourceMappingURL=index.cjs.map
|