@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.js
CHANGED
|
@@ -11,11 +11,87 @@ import {
|
|
|
11
11
|
} from "react";
|
|
12
12
|
import {
|
|
13
13
|
WizardStore,
|
|
14
|
+
getByPath as getByPath2,
|
|
15
|
+
setByPath as setByPath2
|
|
16
|
+
} from "@wizzard-packages/core";
|
|
17
|
+
import { MemoryAdapter } from "@wizzard-packages/persistence";
|
|
18
|
+
|
|
19
|
+
// src/internal/dependencies.ts
|
|
20
|
+
import {
|
|
14
21
|
getByPath,
|
|
15
22
|
setByPath
|
|
16
23
|
} from "@wizzard-packages/core";
|
|
17
|
-
|
|
24
|
+
var applyStepDependencies = (config, store, baseData, changedPaths) => {
|
|
25
|
+
let currentData = { ...baseData };
|
|
26
|
+
const allClearedPaths = /* @__PURE__ */ new Set();
|
|
27
|
+
const snapshot = store.getSnapshot();
|
|
28
|
+
const nextCompletedSteps = new Set(snapshot.completedSteps);
|
|
29
|
+
const nextVisitedSteps = new Set(snapshot.visitedSteps);
|
|
30
|
+
let statusChanged = false;
|
|
31
|
+
const processDependencies = (paths) => {
|
|
32
|
+
const newlyClearedPaths = [];
|
|
33
|
+
config.steps.forEach((step) => {
|
|
34
|
+
const isDependent = step.dependsOn?.some(
|
|
35
|
+
(p) => paths.some((path) => path === p || p.startsWith(path + ".") || path.startsWith(p + "."))
|
|
36
|
+
);
|
|
37
|
+
if (!isDependent) return;
|
|
38
|
+
if (nextCompletedSteps.delete(step.id)) {
|
|
39
|
+
statusChanged = true;
|
|
40
|
+
}
|
|
41
|
+
if (nextVisitedSteps.delete(step.id)) {
|
|
42
|
+
statusChanged = true;
|
|
43
|
+
}
|
|
44
|
+
if (!step.clearData) return;
|
|
45
|
+
if (typeof step.clearData === "function") {
|
|
46
|
+
const patch = step.clearData(currentData, paths);
|
|
47
|
+
Object.keys(patch).forEach((key) => {
|
|
48
|
+
if (currentData[key] !== patch[key]) {
|
|
49
|
+
currentData[key] = patch[key];
|
|
50
|
+
newlyClearedPaths.push(key);
|
|
51
|
+
allClearedPaths.add(key);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
} else {
|
|
55
|
+
const pathsToClear = Array.isArray(step.clearData) ? step.clearData : [step.clearData];
|
|
56
|
+
pathsToClear.forEach((p) => {
|
|
57
|
+
const val = getByPath(currentData, p);
|
|
58
|
+
if (val !== void 0) {
|
|
59
|
+
currentData = setByPath(currentData, p, void 0);
|
|
60
|
+
newlyClearedPaths.push(p);
|
|
61
|
+
allClearedPaths.add(p);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
if (newlyClearedPaths.length > 0) {
|
|
67
|
+
processDependencies(newlyClearedPaths);
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
processDependencies(changedPaths);
|
|
71
|
+
return {
|
|
72
|
+
newData: currentData,
|
|
73
|
+
hasClearing: allClearedPaths.size > 0,
|
|
74
|
+
clearedPaths: Array.from(allClearedPaths),
|
|
75
|
+
statusChanged,
|
|
76
|
+
nextCompletedSteps,
|
|
77
|
+
nextVisitedSteps
|
|
78
|
+
};
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// src/context/WizardContext.tsx
|
|
18
82
|
import { jsx } from "react/jsx-runtime";
|
|
83
|
+
var UNSET = /* @__PURE__ */ Symbol("wizard_unset");
|
|
84
|
+
var shallowEqual = (a, b) => {
|
|
85
|
+
if (a === b) return true;
|
|
86
|
+
if (!a || !b) return false;
|
|
87
|
+
const aKeys = Object.keys(a);
|
|
88
|
+
const bKeys = Object.keys(b);
|
|
89
|
+
if (aKeys.length !== bKeys.length) return false;
|
|
90
|
+
for (const key of aKeys) {
|
|
91
|
+
if (!Object.is(a[key], b[key])) return false;
|
|
92
|
+
}
|
|
93
|
+
return true;
|
|
94
|
+
};
|
|
19
95
|
var WizardStateContext = createContext(void 0);
|
|
20
96
|
var WizardActionsContext = createContext(void 0);
|
|
21
97
|
var WizardStoreContext = createContext(void 0);
|
|
@@ -35,9 +111,10 @@ function WizardProvider({
|
|
|
35
111
|
return localConfig.persistence?.adapter || new MemoryAdapter();
|
|
36
112
|
}, [localConfig.persistence?.adapter]);
|
|
37
113
|
const persistenceMode = localConfig.persistence?.mode || "onStepChange";
|
|
38
|
-
const
|
|
114
|
+
const META_KEY2 = "__wizzard_meta__";
|
|
39
115
|
const snapshot = useSyncExternalStore(
|
|
40
116
|
storeRef.current.subscribe,
|
|
117
|
+
storeRef.current.getSnapshot,
|
|
41
118
|
storeRef.current.getSnapshot
|
|
42
119
|
);
|
|
43
120
|
const {
|
|
@@ -151,83 +228,23 @@ function WizardProvider({
|
|
|
151
228
|
const idx = activeStepsIndexMap2.get(currentStepId2) ?? -1;
|
|
152
229
|
if (idx > 0) await goToStep(activeSteps2[idx - 1].id);
|
|
153
230
|
}, [goToStep]);
|
|
154
|
-
const
|
|
155
|
-
(
|
|
156
|
-
|
|
157
|
-
const
|
|
158
|
-
|
|
159
|
-
const
|
|
160
|
-
const
|
|
161
|
-
let statusChanged = false;
|
|
162
|
-
const processDependencies = (changedPaths) => {
|
|
163
|
-
const newlyClearedPaths = [];
|
|
164
|
-
localConfig.steps.forEach((step) => {
|
|
165
|
-
const isDependent = step.dependsOn?.some(
|
|
166
|
-
(p) => changedPaths.some(
|
|
167
|
-
(path) => path === p || p.startsWith(path + ".") || path.startsWith(p + ".")
|
|
168
|
-
)
|
|
169
|
-
);
|
|
170
|
-
if (isDependent) {
|
|
171
|
-
if (nextComp.delete(step.id)) {
|
|
172
|
-
statusChanged = true;
|
|
173
|
-
}
|
|
174
|
-
if (nextVis.delete(step.id)) {
|
|
175
|
-
statusChanged = true;
|
|
176
|
-
}
|
|
177
|
-
if (step.clearData) {
|
|
178
|
-
if (typeof step.clearData === "function") {
|
|
179
|
-
const patch = step.clearData(currentData, changedPaths);
|
|
180
|
-
Object.keys(patch).forEach((key) => {
|
|
181
|
-
if (currentData[key] !== patch[key]) {
|
|
182
|
-
currentData[key] = patch[key];
|
|
183
|
-
newlyClearedPaths.push(key);
|
|
184
|
-
allClearedPaths.add(key);
|
|
185
|
-
}
|
|
186
|
-
});
|
|
187
|
-
} else {
|
|
188
|
-
const pathsToClear = Array.isArray(step.clearData) ? step.clearData : [step.clearData];
|
|
189
|
-
pathsToClear.forEach((p) => {
|
|
190
|
-
const val = getByPath(currentData, p);
|
|
191
|
-
if (val !== void 0) {
|
|
192
|
-
currentData = setByPath(currentData, p, void 0);
|
|
193
|
-
newlyClearedPaths.push(p);
|
|
194
|
-
allClearedPaths.add(p);
|
|
195
|
-
}
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
});
|
|
201
|
-
if (newlyClearedPaths.length > 0) {
|
|
202
|
-
processDependencies(newlyClearedPaths);
|
|
203
|
-
}
|
|
204
|
-
};
|
|
205
|
-
processDependencies(paths);
|
|
231
|
+
const setData = useCallback(
|
|
232
|
+
(path, value, options) => {
|
|
233
|
+
const { stepsMap: stepsMap2, currentStepId: currentStepId2 } = stateRef.current;
|
|
234
|
+
const prevData = storeRef.current.getSnapshot().data;
|
|
235
|
+
if (getByPath2(prevData, path) === value) return;
|
|
236
|
+
const baseData = setByPath2(prevData, path, value);
|
|
237
|
+
const { newData, hasClearing, statusChanged, nextCompletedSteps, nextVisitedSteps } = applyStepDependencies(localConfig, storeRef.current, baseData, [path]);
|
|
206
238
|
if (statusChanged) {
|
|
207
239
|
storeRef.current.dispatch({
|
|
208
240
|
type: "SET_COMPLETED_STEPS",
|
|
209
|
-
payload: { steps:
|
|
241
|
+
payload: { steps: nextCompletedSteps }
|
|
210
242
|
});
|
|
211
243
|
storeRef.current.dispatch({
|
|
212
244
|
type: "SET_VISITED_STEPS",
|
|
213
|
-
payload: { steps:
|
|
245
|
+
payload: { steps: nextVisitedSteps }
|
|
214
246
|
});
|
|
215
247
|
}
|
|
216
|
-
return {
|
|
217
|
-
newData: currentData,
|
|
218
|
-
hasClearing: allClearedPaths.size > 0,
|
|
219
|
-
clearedPaths: Array.from(allClearedPaths)
|
|
220
|
-
};
|
|
221
|
-
},
|
|
222
|
-
[localConfig.steps]
|
|
223
|
-
);
|
|
224
|
-
const setData = useCallback(
|
|
225
|
-
(path, value, options) => {
|
|
226
|
-
const { stepsMap: stepsMap2, currentStepId: currentStepId2 } = stateRef.current;
|
|
227
|
-
const prevData = storeRef.current.getSnapshot().data;
|
|
228
|
-
if (getByPath(prevData, path) === value) return;
|
|
229
|
-
const baseData = setByPath(prevData, path, value);
|
|
230
|
-
const { newData, hasClearing } = handleStepDependencies([path], baseData);
|
|
231
248
|
if (!hasClearing) {
|
|
232
249
|
storeRef.current.dispatch({
|
|
233
250
|
type: "SET_DATA",
|
|
@@ -261,13 +278,23 @@ function WizardProvider({
|
|
|
261
278
|
}
|
|
262
279
|
}
|
|
263
280
|
},
|
|
264
|
-
[localConfig, validateStep
|
|
281
|
+
[localConfig, validateStep]
|
|
265
282
|
);
|
|
266
283
|
const updateData = useCallback(
|
|
267
284
|
(data2, options) => {
|
|
268
285
|
const prev = storeRef.current.getSnapshot().data;
|
|
269
286
|
const baseData = options?.replace ? data2 : { ...prev, ...data2 };
|
|
270
|
-
const { newData } =
|
|
287
|
+
const { newData, statusChanged, nextCompletedSteps, nextVisitedSteps } = applyStepDependencies(localConfig, storeRef.current, baseData, Object.keys(data2));
|
|
288
|
+
if (statusChanged) {
|
|
289
|
+
storeRef.current.dispatch({
|
|
290
|
+
type: "SET_COMPLETED_STEPS",
|
|
291
|
+
payload: { steps: nextCompletedSteps }
|
|
292
|
+
});
|
|
293
|
+
storeRef.current.dispatch({
|
|
294
|
+
type: "SET_VISITED_STEPS",
|
|
295
|
+
payload: { steps: nextVisitedSteps }
|
|
296
|
+
});
|
|
297
|
+
}
|
|
271
298
|
storeRef.current.update(newData, Object.keys(data2));
|
|
272
299
|
if (options?.persist) {
|
|
273
300
|
if (storeRef.current.save) {
|
|
@@ -275,7 +302,7 @@ function WizardProvider({
|
|
|
275
302
|
}
|
|
276
303
|
}
|
|
277
304
|
},
|
|
278
|
-
[
|
|
305
|
+
[localConfig]
|
|
279
306
|
);
|
|
280
307
|
const reset = useCallback(() => {
|
|
281
308
|
storeRef.current.setInitialData(initialData || {});
|
|
@@ -370,7 +397,7 @@ function WizardProvider({
|
|
|
370
397
|
reset,
|
|
371
398
|
setData,
|
|
372
399
|
updateData,
|
|
373
|
-
getData: (p, d) =>
|
|
400
|
+
getData: (p, d) => getByPath2(storeRef.current.getSnapshot().data, p, d),
|
|
374
401
|
updateConfig: (nc) => {
|
|
375
402
|
setLocalConfig((prev) => ({ ...prev, ...nc }));
|
|
376
403
|
}
|
|
@@ -421,7 +448,7 @@ function WizardProvider({
|
|
|
421
448
|
useEffect(() => {
|
|
422
449
|
if (hasHydratedRef.current) return;
|
|
423
450
|
hasHydratedRef.current = true;
|
|
424
|
-
const meta = persistenceAdapter.getStep(
|
|
451
|
+
const meta = persistenceAdapter.getStep(META_KEY2);
|
|
425
452
|
if (meta) {
|
|
426
453
|
if (meta.currentStepId) {
|
|
427
454
|
storeRef.current.dispatch({
|
|
@@ -484,12 +511,14 @@ function useWizardValue(path, options) {
|
|
|
484
511
|
const store = useContext(WizardStoreContext);
|
|
485
512
|
if (!store) throw new Error("useWizardValue must be used within a WizardProvider");
|
|
486
513
|
const lastStateRef = useRef(null);
|
|
487
|
-
const lastValueRef = useRef(
|
|
514
|
+
const lastValueRef = useRef(UNSET);
|
|
488
515
|
const getSnapshot = useCallback(() => {
|
|
489
516
|
const data = store.getSnapshot().data;
|
|
490
|
-
if (data === lastStateRef.current
|
|
491
|
-
|
|
492
|
-
|
|
517
|
+
if (data === lastStateRef.current && lastValueRef.current !== UNSET) {
|
|
518
|
+
return lastValueRef.current;
|
|
519
|
+
}
|
|
520
|
+
const value = getByPath2(data, path);
|
|
521
|
+
if (lastValueRef.current !== UNSET && (options?.isEqual || Object.is)(lastValueRef.current, value)) {
|
|
493
522
|
lastStateRef.current = data;
|
|
494
523
|
return lastValueRef.current;
|
|
495
524
|
}
|
|
@@ -497,7 +526,18 @@ function useWizardValue(path, options) {
|
|
|
497
526
|
lastValueRef.current = value;
|
|
498
527
|
return value;
|
|
499
528
|
}, [store, path, options?.isEqual]);
|
|
500
|
-
return useSyncExternalStore(store.subscribe, getSnapshot);
|
|
529
|
+
return useSyncExternalStore(store.subscribe, getSnapshot, getSnapshot);
|
|
530
|
+
}
|
|
531
|
+
function useWizardField(path, options) {
|
|
532
|
+
const value = useWizardValue(path, options);
|
|
533
|
+
const { setData } = useWizardActions();
|
|
534
|
+
const setValue = useCallback(
|
|
535
|
+
(next) => {
|
|
536
|
+
setData(path, next);
|
|
537
|
+
},
|
|
538
|
+
[setData, path]
|
|
539
|
+
);
|
|
540
|
+
return [value, setValue];
|
|
501
541
|
}
|
|
502
542
|
function useWizardError(path) {
|
|
503
543
|
const store = useContext(WizardStoreContext);
|
|
@@ -510,22 +550,22 @@ function useWizardError(path) {
|
|
|
510
550
|
}
|
|
511
551
|
return void 0;
|
|
512
552
|
}, [store, path]);
|
|
513
|
-
return useSyncExternalStore(store.subscribe, getSnapshot);
|
|
553
|
+
return useSyncExternalStore(store.subscribe, getSnapshot, getSnapshot);
|
|
514
554
|
}
|
|
515
555
|
function useWizardSelector(selector, options) {
|
|
516
556
|
const store = useContext(WizardStoreContext);
|
|
517
557
|
if (!store) throw new Error("useWizardSelector must be used within a WizardProvider");
|
|
518
|
-
const lastResultRef = useRef(
|
|
558
|
+
const lastResultRef = useRef(UNSET);
|
|
519
559
|
const getSnapshot = useCallback(() => {
|
|
520
560
|
const full = store.getSnapshot();
|
|
521
561
|
const res = selector(full);
|
|
522
|
-
if (lastResultRef.current !==
|
|
562
|
+
if (lastResultRef.current !== UNSET && (options?.isEqual || Object.is)(lastResultRef.current, res)) {
|
|
523
563
|
return lastResultRef.current;
|
|
524
564
|
}
|
|
525
565
|
lastResultRef.current = res;
|
|
526
566
|
return res;
|
|
527
567
|
}, [store, selector, options?.isEqual]);
|
|
528
|
-
return useSyncExternalStore(store.subscribe, getSnapshot);
|
|
568
|
+
return useSyncExternalStore(store.subscribe, getSnapshot, getSnapshot);
|
|
529
569
|
}
|
|
530
570
|
function useWizardActions() {
|
|
531
571
|
const context = useContext(WizardActionsContext);
|
|
@@ -558,6 +598,44 @@ function useWizardContext() {
|
|
|
558
598
|
[stateProps, actions, data, allErrors, errors, store]
|
|
559
599
|
);
|
|
560
600
|
}
|
|
601
|
+
function useWizardCurrentStep() {
|
|
602
|
+
return useWizardSelector((s) => s.currentStep);
|
|
603
|
+
}
|
|
604
|
+
function useWizardSteps() {
|
|
605
|
+
return useWizardSelector((s) => s.activeSteps);
|
|
606
|
+
}
|
|
607
|
+
function useWizardMeta() {
|
|
608
|
+
return useWizardSelector(
|
|
609
|
+
(s) => ({
|
|
610
|
+
currentStepId: s.currentStepId,
|
|
611
|
+
currentStepIndex: s.currentStepIndex,
|
|
612
|
+
isFirstStep: s.isFirstStep,
|
|
613
|
+
isLastStep: s.isLastStep,
|
|
614
|
+
isLoading: s.isLoading,
|
|
615
|
+
isBusy: s.isBusy,
|
|
616
|
+
isDirty: s.isDirty,
|
|
617
|
+
progress: s.progress,
|
|
618
|
+
activeStepsCount: s.activeStepsCount,
|
|
619
|
+
goToStepResult: s.goToStepResult
|
|
620
|
+
}),
|
|
621
|
+
{ isEqual: shallowEqual }
|
|
622
|
+
);
|
|
623
|
+
}
|
|
624
|
+
function useWizardAllErrors() {
|
|
625
|
+
return useWizardSelector((s) => s.errors, {
|
|
626
|
+
isEqual: shallowEqual
|
|
627
|
+
});
|
|
628
|
+
}
|
|
629
|
+
function useWizardFlatErrors() {
|
|
630
|
+
const allErrors = useWizardAllErrors();
|
|
631
|
+
return useMemo(() => {
|
|
632
|
+
const flat = {};
|
|
633
|
+
Object.values(allErrors).forEach((stepErrors) => {
|
|
634
|
+
Object.assign(flat, stepErrors);
|
|
635
|
+
});
|
|
636
|
+
return flat;
|
|
637
|
+
}, [allErrors]);
|
|
638
|
+
}
|
|
561
639
|
|
|
562
640
|
// src/hooks/useWizard.ts
|
|
563
641
|
var useWizard = () => {
|
|
@@ -570,9 +648,18 @@ function createWizardFactory() {
|
|
|
570
648
|
const WizardProvider2 = ({
|
|
571
649
|
config,
|
|
572
650
|
initialData,
|
|
651
|
+
initialStepId,
|
|
573
652
|
children
|
|
574
653
|
}) => {
|
|
575
|
-
return /* @__PURE__ */ jsx2(
|
|
654
|
+
return /* @__PURE__ */ jsx2(
|
|
655
|
+
WizardProvider,
|
|
656
|
+
{
|
|
657
|
+
config,
|
|
658
|
+
initialData,
|
|
659
|
+
initialStepId,
|
|
660
|
+
children
|
|
661
|
+
}
|
|
662
|
+
);
|
|
576
663
|
};
|
|
577
664
|
const useWizard2 = () => {
|
|
578
665
|
return useWizard();
|
|
@@ -583,6 +670,11 @@ function createWizardFactory() {
|
|
|
583
670
|
const useWizardValue2 = (path, options) => {
|
|
584
671
|
return useWizardValue(path, options);
|
|
585
672
|
};
|
|
673
|
+
const useWizardField2 = (path, options) => {
|
|
674
|
+
const value = useWizardValue2(path, options);
|
|
675
|
+
const { setData } = useWizardActions2();
|
|
676
|
+
return [value, (next) => setData(path, next)];
|
|
677
|
+
};
|
|
586
678
|
const useWizardSelector2 = (selector, options) => {
|
|
587
679
|
return useWizardSelector(selector, options);
|
|
588
680
|
};
|
|
@@ -604,6 +696,7 @@ function createWizardFactory() {
|
|
|
604
696
|
useWizard: useWizard2,
|
|
605
697
|
useWizardContext: useWizardContext2,
|
|
606
698
|
useWizardValue: useWizardValue2,
|
|
699
|
+
useWizardField: useWizardField2,
|
|
607
700
|
useWizardSelector: useWizardSelector2,
|
|
608
701
|
useWizardError: useWizardError2,
|
|
609
702
|
useWizardActions: useWizardActions2,
|
|
@@ -635,21 +728,406 @@ var WizardStepRenderer = ({
|
|
|
635
728
|
return content;
|
|
636
729
|
};
|
|
637
730
|
|
|
731
|
+
// src/store.ts
|
|
732
|
+
import { useCallback as useCallback2, useRef as useRef2, useSyncExternalStore as useSyncExternalStore2 } from "react";
|
|
733
|
+
import {
|
|
734
|
+
WizardStore as WizardStore2,
|
|
735
|
+
getByPath as getByPath3,
|
|
736
|
+
setByPath as setByPath3
|
|
737
|
+
} from "@wizzard-packages/core";
|
|
738
|
+
import { MemoryAdapter as MemoryAdapter2 } from "@wizzard-packages/persistence";
|
|
739
|
+
var UNSET2 = /* @__PURE__ */ Symbol("wizard_store_unset");
|
|
740
|
+
var META_KEY = "__wizzard_meta__";
|
|
741
|
+
var applyStoredMeta = (store, adapter) => {
|
|
742
|
+
const meta = adapter.getStep(META_KEY);
|
|
743
|
+
if (!meta) return;
|
|
744
|
+
if (meta.currentStepId) {
|
|
745
|
+
store.dispatch({
|
|
746
|
+
type: "SET_CURRENT_STEP_ID",
|
|
747
|
+
payload: { stepId: meta.currentStepId }
|
|
748
|
+
});
|
|
749
|
+
}
|
|
750
|
+
if (meta.visited) {
|
|
751
|
+
store.dispatch({
|
|
752
|
+
type: "SET_VISITED_STEPS",
|
|
753
|
+
payload: { steps: new Set(meta.visited) }
|
|
754
|
+
});
|
|
755
|
+
}
|
|
756
|
+
if (meta.completed) {
|
|
757
|
+
store.dispatch({
|
|
758
|
+
type: "SET_COMPLETED_STEPS",
|
|
759
|
+
payload: { steps: new Set(meta.completed) }
|
|
760
|
+
});
|
|
761
|
+
}
|
|
762
|
+
if (meta.history) {
|
|
763
|
+
store.dispatch({
|
|
764
|
+
type: "SET_HISTORY",
|
|
765
|
+
payload: { history: meta.history }
|
|
766
|
+
});
|
|
767
|
+
}
|
|
768
|
+
};
|
|
769
|
+
var ensureInitialStep = (store, activeSteps, initialStepId) => {
|
|
770
|
+
const snapshot = store.getSnapshot();
|
|
771
|
+
if (snapshot.currentStepId || activeSteps.length === 0) return;
|
|
772
|
+
const startId = initialStepId && activeSteps.some((s) => s.id === initialStepId) ? initialStepId : activeSteps[0].id;
|
|
773
|
+
store.dispatch({
|
|
774
|
+
type: "SET_CURRENT_STEP_ID",
|
|
775
|
+
payload: { stepId: startId }
|
|
776
|
+
});
|
|
777
|
+
if (snapshot.history.length === 0) {
|
|
778
|
+
store.dispatch({
|
|
779
|
+
type: "SET_HISTORY",
|
|
780
|
+
payload: { history: [startId] }
|
|
781
|
+
});
|
|
782
|
+
}
|
|
783
|
+
const currentVisited = new Set(snapshot.visitedSteps);
|
|
784
|
+
if (!currentVisited.has(startId)) {
|
|
785
|
+
currentVisited.add(startId);
|
|
786
|
+
store.dispatch({
|
|
787
|
+
type: "SET_VISITED_STEPS",
|
|
788
|
+
payload: { steps: currentVisited }
|
|
789
|
+
});
|
|
790
|
+
}
|
|
791
|
+
};
|
|
792
|
+
var resolveAndSetActiveSteps = async (store, data, initialStepId) => {
|
|
793
|
+
const resolved = await store.resolveActiveSteps(data);
|
|
794
|
+
store.dispatch({
|
|
795
|
+
type: "SET_ACTIVE_STEPS",
|
|
796
|
+
payload: { steps: resolved }
|
|
797
|
+
});
|
|
798
|
+
ensureInitialStep(store, resolved, initialStepId);
|
|
799
|
+
const snapshot = store.getSnapshot();
|
|
800
|
+
if (resolved.length > 0 && snapshot.isLoading) {
|
|
801
|
+
store.updateMeta({ isLoading: false });
|
|
802
|
+
}
|
|
803
|
+
};
|
|
804
|
+
var createWizardActions = (store, config, persistenceAdapter, initialData) => {
|
|
805
|
+
let currentConfig = config;
|
|
806
|
+
const validationDebounceRef = { current: null };
|
|
807
|
+
const stepsMap = /* @__PURE__ */ new Map();
|
|
808
|
+
currentConfig.steps.forEach((step) => stepsMap.set(step.id, step));
|
|
809
|
+
const resolveActiveStepsHelper = (data) => store.resolveActiveSteps(data);
|
|
810
|
+
const validateStep = (stepId) => store.validateStep(stepId);
|
|
811
|
+
const setData = (path, value, options) => {
|
|
812
|
+
const prevData = store.getSnapshot().data;
|
|
813
|
+
if (getByPath3(prevData, path) === value) return;
|
|
814
|
+
const baseData = setByPath3(prevData, path, value);
|
|
815
|
+
const { newData, hasClearing, statusChanged, nextCompletedSteps, nextVisitedSteps } = applyStepDependencies(currentConfig, store, baseData, [path]);
|
|
816
|
+
if (statusChanged) {
|
|
817
|
+
store.dispatch({
|
|
818
|
+
type: "SET_COMPLETED_STEPS",
|
|
819
|
+
payload: { steps: nextCompletedSteps }
|
|
820
|
+
});
|
|
821
|
+
store.dispatch({
|
|
822
|
+
type: "SET_VISITED_STEPS",
|
|
823
|
+
payload: { steps: nextVisitedSteps }
|
|
824
|
+
});
|
|
825
|
+
}
|
|
826
|
+
if (!hasClearing) {
|
|
827
|
+
store.dispatch({
|
|
828
|
+
type: "SET_DATA",
|
|
829
|
+
payload: {
|
|
830
|
+
path,
|
|
831
|
+
value,
|
|
832
|
+
options: { ...options, __from_set_data__: true }
|
|
833
|
+
}
|
|
834
|
+
});
|
|
835
|
+
} else {
|
|
836
|
+
store.dispatch({
|
|
837
|
+
type: "UPDATE_DATA",
|
|
838
|
+
payload: {
|
|
839
|
+
data: newData,
|
|
840
|
+
options: { replace: true, __from_set_data__: true, path }
|
|
841
|
+
}
|
|
842
|
+
});
|
|
843
|
+
}
|
|
844
|
+
const snapshot = store.getSnapshot();
|
|
845
|
+
const currentStepId = snapshot.currentStepId;
|
|
846
|
+
if (currentStepId) {
|
|
847
|
+
store.deleteError(currentStepId, path);
|
|
848
|
+
const step = stepsMap.get(currentStepId);
|
|
849
|
+
const mode = step?.validationMode || currentConfig.validationMode || "onStepChange";
|
|
850
|
+
if (mode === "onChange") {
|
|
851
|
+
const debounceMs = options?.debounceValidation ?? currentConfig.validationDebounceTime ?? 300;
|
|
852
|
+
if (validationDebounceRef.current) {
|
|
853
|
+
clearTimeout(validationDebounceRef.current);
|
|
854
|
+
}
|
|
855
|
+
validationDebounceRef.current = setTimeout(() => {
|
|
856
|
+
void validateStep(currentStepId);
|
|
857
|
+
}, debounceMs);
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
};
|
|
861
|
+
const updateData = (data, options) => {
|
|
862
|
+
const prev = store.getSnapshot().data;
|
|
863
|
+
const baseData = options?.replace ? data : { ...prev, ...data };
|
|
864
|
+
const { newData, statusChanged, nextCompletedSteps, nextVisitedSteps } = applyStepDependencies(
|
|
865
|
+
currentConfig,
|
|
866
|
+
store,
|
|
867
|
+
baseData,
|
|
868
|
+
Object.keys(data)
|
|
869
|
+
);
|
|
870
|
+
if (statusChanged) {
|
|
871
|
+
store.dispatch({
|
|
872
|
+
type: "SET_COMPLETED_STEPS",
|
|
873
|
+
payload: { steps: nextCompletedSteps }
|
|
874
|
+
});
|
|
875
|
+
store.dispatch({
|
|
876
|
+
type: "SET_VISITED_STEPS",
|
|
877
|
+
payload: { steps: nextVisitedSteps }
|
|
878
|
+
});
|
|
879
|
+
}
|
|
880
|
+
store.update(newData, Object.keys(data));
|
|
881
|
+
if (options?.persist) {
|
|
882
|
+
store.save(store.getSnapshot().currentStepId);
|
|
883
|
+
}
|
|
884
|
+
};
|
|
885
|
+
const reset = () => {
|
|
886
|
+
store.setInitialData(initialData || {});
|
|
887
|
+
store.update(initialData || {});
|
|
888
|
+
store.updateErrors({});
|
|
889
|
+
store.dispatch({
|
|
890
|
+
type: "SET_VISITED_STEPS",
|
|
891
|
+
payload: { steps: /* @__PURE__ */ new Set() }
|
|
892
|
+
});
|
|
893
|
+
store.dispatch({
|
|
894
|
+
type: "SET_COMPLETED_STEPS",
|
|
895
|
+
payload: { steps: /* @__PURE__ */ new Set() }
|
|
896
|
+
});
|
|
897
|
+
store.dispatch({
|
|
898
|
+
type: "SET_ERROR_STEPS",
|
|
899
|
+
payload: { steps: /* @__PURE__ */ new Set() }
|
|
900
|
+
});
|
|
901
|
+
const snapshot = store.getSnapshot();
|
|
902
|
+
if (snapshot.activeSteps.length > 0) {
|
|
903
|
+
const startId = snapshot.activeSteps[0].id;
|
|
904
|
+
store.dispatch({
|
|
905
|
+
type: "SET_CURRENT_STEP_ID",
|
|
906
|
+
payload: { stepId: startId }
|
|
907
|
+
});
|
|
908
|
+
store.dispatch({
|
|
909
|
+
type: "SET_HISTORY",
|
|
910
|
+
payload: { history: [startId] }
|
|
911
|
+
});
|
|
912
|
+
} else {
|
|
913
|
+
store.dispatch({
|
|
914
|
+
type: "SET_CURRENT_STEP_ID",
|
|
915
|
+
payload: { stepId: "" }
|
|
916
|
+
});
|
|
917
|
+
store.dispatch({
|
|
918
|
+
type: "SET_HISTORY",
|
|
919
|
+
payload: { history: [] }
|
|
920
|
+
});
|
|
921
|
+
}
|
|
922
|
+
persistenceAdapter.clear();
|
|
923
|
+
currentConfig.analytics?.onEvent("wizard_reset", { data: initialData });
|
|
924
|
+
};
|
|
925
|
+
const goToStep = (stepId, providedActiveSteps, options) => {
|
|
926
|
+
return store.goToStep(stepId, {
|
|
927
|
+
validate: options?.validate ?? true,
|
|
928
|
+
providedActiveSteps
|
|
929
|
+
});
|
|
930
|
+
};
|
|
931
|
+
const goToNextStep = async () => {
|
|
932
|
+
const snapshot = store.getSnapshot();
|
|
933
|
+
const currentStepId = snapshot.currentStepId;
|
|
934
|
+
if (!currentStepId) return;
|
|
935
|
+
const step = stepsMap.get(currentStepId);
|
|
936
|
+
const shouldVal = step?.autoValidate ?? currentConfig.autoValidate ?? !!step?.validationAdapter;
|
|
937
|
+
if (shouldVal) {
|
|
938
|
+
const ok = await validateStep(currentStepId);
|
|
939
|
+
if (!ok) return;
|
|
940
|
+
}
|
|
941
|
+
const resolvedSteps = await resolveActiveStepsHelper(snapshot.data);
|
|
942
|
+
const idx = resolvedSteps.findIndex((s) => s.id === currentStepId);
|
|
943
|
+
if (idx !== -1 && idx < resolvedSteps.length - 1) {
|
|
944
|
+
const nextStepId = resolvedSteps[idx + 1].id;
|
|
945
|
+
const success = await goToStep(nextStepId, resolvedSteps, {
|
|
946
|
+
validate: false
|
|
947
|
+
});
|
|
948
|
+
if (success) {
|
|
949
|
+
const currentSnapshot = store.getSnapshot();
|
|
950
|
+
if (!currentSnapshot.errorSteps.has(currentStepId)) {
|
|
951
|
+
const nextComp = new Set(currentSnapshot.completedSteps);
|
|
952
|
+
nextComp.add(currentStepId);
|
|
953
|
+
store.dispatch({
|
|
954
|
+
type: "SET_COMPLETED_STEPS",
|
|
955
|
+
payload: { steps: nextComp }
|
|
956
|
+
});
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
};
|
|
961
|
+
const goToPrevStep = async () => {
|
|
962
|
+
const snapshot = store.getSnapshot();
|
|
963
|
+
const idx = snapshot.activeSteps.findIndex((s) => s.id === snapshot.currentStepId);
|
|
964
|
+
if (idx > 0) {
|
|
965
|
+
await goToStep(snapshot.activeSteps[idx - 1].id);
|
|
966
|
+
}
|
|
967
|
+
};
|
|
968
|
+
const setStepData = (_stepId, data) => {
|
|
969
|
+
const next = { ...store.getSnapshot().data, ...data };
|
|
970
|
+
store.update(next, Object.keys(data));
|
|
971
|
+
};
|
|
972
|
+
const handleStepChange = (field, value) => {
|
|
973
|
+
if (store.getSnapshot().currentStepId) {
|
|
974
|
+
setData(field, value);
|
|
975
|
+
}
|
|
976
|
+
};
|
|
977
|
+
const validateAll = async () => {
|
|
978
|
+
const result = await store.validateAll();
|
|
979
|
+
return result;
|
|
980
|
+
};
|
|
981
|
+
const save = (ids) => {
|
|
982
|
+
if (ids === true) {
|
|
983
|
+
currentConfig.steps.forEach((s) => store.save(s.id));
|
|
984
|
+
} else if (!ids) {
|
|
985
|
+
store.save();
|
|
986
|
+
} else {
|
|
987
|
+
(Array.isArray(ids) ? ids : [ids]).forEach((id) => store.save(id));
|
|
988
|
+
}
|
|
989
|
+
};
|
|
990
|
+
const clearStorage = () => persistenceAdapter.clear();
|
|
991
|
+
const getData = (path, defaultValue) => {
|
|
992
|
+
return getByPath3(store.getSnapshot().data, path, defaultValue);
|
|
993
|
+
};
|
|
994
|
+
const updateConfig = (nextConfig) => {
|
|
995
|
+
currentConfig = { ...currentConfig, ...nextConfig };
|
|
996
|
+
stepsMap.clear();
|
|
997
|
+
currentConfig.steps.forEach((step) => stepsMap.set(step.id, step));
|
|
998
|
+
store.updateMeta({ config: currentConfig });
|
|
999
|
+
};
|
|
1000
|
+
return {
|
|
1001
|
+
goToNextStep,
|
|
1002
|
+
goToPrevStep,
|
|
1003
|
+
goToStep,
|
|
1004
|
+
setStepData,
|
|
1005
|
+
handleStepChange,
|
|
1006
|
+
validateStep,
|
|
1007
|
+
validateAll,
|
|
1008
|
+
save,
|
|
1009
|
+
clearStorage,
|
|
1010
|
+
reset,
|
|
1011
|
+
setData,
|
|
1012
|
+
updateData,
|
|
1013
|
+
getData,
|
|
1014
|
+
updateConfig
|
|
1015
|
+
};
|
|
1016
|
+
};
|
|
1017
|
+
var createWizardStore = (options) => {
|
|
1018
|
+
const initialData = options.initialData || {};
|
|
1019
|
+
const store = new WizardStore2(initialData, options.config.middlewares);
|
|
1020
|
+
const persistenceAdapter = options.config.persistence?.adapter || new MemoryAdapter2();
|
|
1021
|
+
store.injectPersistence(persistenceAdapter);
|
|
1022
|
+
store.dispatch({
|
|
1023
|
+
type: "INIT",
|
|
1024
|
+
payload: { data: initialData, config: options.config }
|
|
1025
|
+
});
|
|
1026
|
+
store.hydrate();
|
|
1027
|
+
applyStoredMeta(store, persistenceAdapter);
|
|
1028
|
+
void resolveAndSetActiveSteps(store, store.getSnapshot().data, options.initialStepId);
|
|
1029
|
+
return {
|
|
1030
|
+
store,
|
|
1031
|
+
actions: createWizardActions(store, options.config, persistenceAdapter, initialData)
|
|
1032
|
+
};
|
|
1033
|
+
};
|
|
1034
|
+
var useWizardStoreState = (store) => {
|
|
1035
|
+
return useSyncExternalStore2(store.subscribe, store.getSnapshot, store.getSnapshot);
|
|
1036
|
+
};
|
|
1037
|
+
var useWizardStoreValue = (store, path, options) => {
|
|
1038
|
+
const lastStateRef = useRef2(UNSET2);
|
|
1039
|
+
const lastValueRef = useRef2(UNSET2);
|
|
1040
|
+
const getSnapshot = useCallback2(() => {
|
|
1041
|
+
const data = store.getSnapshot().data;
|
|
1042
|
+
if (data === lastStateRef.current && lastValueRef.current !== UNSET2) {
|
|
1043
|
+
return lastValueRef.current;
|
|
1044
|
+
}
|
|
1045
|
+
const value = getByPath3(data, path);
|
|
1046
|
+
if (lastValueRef.current !== UNSET2 && (options?.isEqual || Object.is)(lastValueRef.current, value)) {
|
|
1047
|
+
lastStateRef.current = data;
|
|
1048
|
+
return lastValueRef.current;
|
|
1049
|
+
}
|
|
1050
|
+
lastStateRef.current = data;
|
|
1051
|
+
lastValueRef.current = value;
|
|
1052
|
+
return value;
|
|
1053
|
+
}, [store, path, options?.isEqual]);
|
|
1054
|
+
return useSyncExternalStore2(store.subscribe, getSnapshot, getSnapshot);
|
|
1055
|
+
};
|
|
1056
|
+
var useWizardStoreField = (store, setData, path, options) => {
|
|
1057
|
+
const value = useWizardStoreValue(store, path, options);
|
|
1058
|
+
const setValue = useCallback2(
|
|
1059
|
+
(next) => {
|
|
1060
|
+
setData(path, next);
|
|
1061
|
+
},
|
|
1062
|
+
[setData, path]
|
|
1063
|
+
);
|
|
1064
|
+
return [value, setValue];
|
|
1065
|
+
};
|
|
1066
|
+
var useWizardStoreError = (store, path) => {
|
|
1067
|
+
const getSnapshot = useCallback2(() => {
|
|
1068
|
+
const errors = store.getSnapshot().errors;
|
|
1069
|
+
for (const [_, stepErrors] of Object.entries(errors)) {
|
|
1070
|
+
const typed = stepErrors;
|
|
1071
|
+
if (typed[path]) return typed[path];
|
|
1072
|
+
}
|
|
1073
|
+
return void 0;
|
|
1074
|
+
}, [store, path]);
|
|
1075
|
+
return useSyncExternalStore2(store.subscribe, getSnapshot, getSnapshot);
|
|
1076
|
+
};
|
|
1077
|
+
var useWizardStoreSelector = (store, selector, options) => {
|
|
1078
|
+
const lastResultRef = useRef2(UNSET2);
|
|
1079
|
+
const getSnapshot = useCallback2(() => {
|
|
1080
|
+
const full = store.getSnapshot();
|
|
1081
|
+
const res = selector(full);
|
|
1082
|
+
if (lastResultRef.current !== UNSET2 && (options?.isEqual || Object.is)(lastResultRef.current, res)) {
|
|
1083
|
+
return lastResultRef.current;
|
|
1084
|
+
}
|
|
1085
|
+
lastResultRef.current = res;
|
|
1086
|
+
return res;
|
|
1087
|
+
}, [store, selector, options?.isEqual]);
|
|
1088
|
+
return useSyncExternalStore2(store.subscribe, getSnapshot, getSnapshot);
|
|
1089
|
+
};
|
|
1090
|
+
var createWizardHooks = (store, actions) => ({
|
|
1091
|
+
useWizardState: () => useWizardStoreState(store),
|
|
1092
|
+
useWizardValue: (path, options) => useWizardStoreValue(store, path, options),
|
|
1093
|
+
useWizardField: (path, options) => {
|
|
1094
|
+
if (!actions) {
|
|
1095
|
+
throw new Error("useWizardField requires actions. Pass actions to createWizardHooks.");
|
|
1096
|
+
}
|
|
1097
|
+
return useWizardStoreField(store, actions.setData, path, options);
|
|
1098
|
+
},
|
|
1099
|
+
useWizardError: (path) => useWizardStoreError(store, path),
|
|
1100
|
+
useWizardSelector: (selector, options) => useWizardStoreSelector(store, selector, options)
|
|
1101
|
+
});
|
|
1102
|
+
|
|
638
1103
|
// src/index.ts
|
|
639
|
-
import { WizardStore as
|
|
1104
|
+
import { WizardStore as WizardStore3 } from "@wizzard-packages/core";
|
|
640
1105
|
import { loggerMiddleware } from "@wizzard-packages/middleware";
|
|
641
1106
|
export {
|
|
642
1107
|
WizardProvider,
|
|
643
1108
|
WizardStepRenderer,
|
|
644
|
-
|
|
1109
|
+
WizardStore3 as WizardStore,
|
|
645
1110
|
createWizardFactory,
|
|
1111
|
+
createWizardHooks,
|
|
1112
|
+
createWizardStore,
|
|
646
1113
|
loggerMiddleware,
|
|
647
1114
|
useWizard,
|
|
648
1115
|
useWizardActions,
|
|
1116
|
+
useWizardAllErrors,
|
|
649
1117
|
useWizardContext,
|
|
1118
|
+
useWizardCurrentStep,
|
|
650
1119
|
useWizardError,
|
|
1120
|
+
useWizardField,
|
|
1121
|
+
useWizardFlatErrors,
|
|
1122
|
+
useWizardMeta,
|
|
651
1123
|
useWizardSelector,
|
|
652
1124
|
useWizardState,
|
|
1125
|
+
useWizardSteps,
|
|
1126
|
+
useWizardStoreError,
|
|
1127
|
+
useWizardStoreField,
|
|
1128
|
+
useWizardStoreSelector,
|
|
1129
|
+
useWizardStoreState,
|
|
1130
|
+
useWizardStoreValue,
|
|
653
1131
|
useWizardValue
|
|
654
1132
|
};
|
|
655
1133
|
//# sourceMappingURL=index.js.map
|