@wizzard-packages/react 0.1.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,21 +1,102 @@
1
+ // src/factory.tsx
2
+ import {
3
+ shallowEqual as shallowEqual2
4
+ } from "@wizzard-packages/core";
5
+
1
6
  // src/context/WizardContext.tsx
7
+ import {
8
+ WizardStore,
9
+ getByPath as getByPath2,
10
+ setByPath as setByPath2
11
+ } from "@wizzard-packages/core";
12
+ import { MemoryAdapter } from "@wizzard-packages/persistence";
2
13
  import {
3
14
  createContext,
15
+ useCallback,
4
16
  useContext,
5
17
  useEffect,
6
18
  useMemo,
19
+ useRef,
7
20
  useState,
8
- useCallback,
9
- useSyncExternalStore,
10
- useRef
21
+ useSyncExternalStore
11
22
  } from "react";
23
+
24
+ // src/internal/dependencies.ts
12
25
  import {
13
- WizardStore,
14
26
  getByPath,
15
27
  setByPath
16
28
  } from "@wizzard-packages/core";
17
- import { MemoryAdapter } from "@wizzard-packages/persistence";
29
+ var applyStepDependencies = (config, store, baseData, changedPaths) => {
30
+ let currentData = { ...baseData };
31
+ const allClearedPaths = /* @__PURE__ */ new Set();
32
+ const snapshot = store.getSnapshot();
33
+ const nextCompletedSteps = new Set(snapshot.completedSteps);
34
+ const nextVisitedSteps = new Set(snapshot.visitedSteps);
35
+ let statusChanged = false;
36
+ const processDependencies = (paths) => {
37
+ const newlyClearedPaths = [];
38
+ config.steps.forEach((step) => {
39
+ const isDependent = step.dependsOn?.some(
40
+ (p) => paths.some((path) => path === p || p.startsWith(path + ".") || path.startsWith(p + "."))
41
+ );
42
+ if (!isDependent) return;
43
+ if (nextCompletedSteps.delete(step.id)) {
44
+ statusChanged = true;
45
+ }
46
+ if (nextVisitedSteps.delete(step.id)) {
47
+ statusChanged = true;
48
+ }
49
+ if (!step.clearData) return;
50
+ if (typeof step.clearData === "function") {
51
+ const patch = step.clearData(currentData, paths);
52
+ Object.keys(patch).forEach((key) => {
53
+ if (currentData[key] !== patch[key]) {
54
+ currentData[key] = patch[key];
55
+ newlyClearedPaths.push(key);
56
+ allClearedPaths.add(key);
57
+ }
58
+ });
59
+ } else {
60
+ const pathsToClear = Array.isArray(step.clearData) ? step.clearData : [step.clearData];
61
+ pathsToClear.forEach((p) => {
62
+ const val = getByPath(currentData, p);
63
+ if (val !== void 0) {
64
+ currentData = setByPath(currentData, p, void 0);
65
+ newlyClearedPaths.push(p);
66
+ allClearedPaths.add(p);
67
+ }
68
+ });
69
+ }
70
+ });
71
+ if (newlyClearedPaths.length > 0) {
72
+ processDependencies(newlyClearedPaths);
73
+ }
74
+ };
75
+ processDependencies(changedPaths);
76
+ return {
77
+ newData: currentData,
78
+ hasClearing: allClearedPaths.size > 0,
79
+ clearedPaths: Array.from(allClearedPaths),
80
+ statusChanged,
81
+ nextCompletedSteps,
82
+ nextVisitedSteps
83
+ };
84
+ };
85
+
86
+ // src/context/WizardContext.tsx
18
87
  import { jsx } from "react/jsx-runtime";
88
+ var UNSET = /* @__PURE__ */ Symbol("wizard_unset");
89
+ var shallowEqual = (a, b) => {
90
+ if (a === b) return true;
91
+ if (!a || !b) return false;
92
+ const aKeys = Object.keys(a);
93
+ const bKeys = Object.keys(b);
94
+ if (aKeys.length !== bKeys.length) return false;
95
+ for (const key of aKeys) {
96
+ if (!Object.is(a[key], b[key])) return false;
97
+ }
98
+ return true;
99
+ };
19
100
  var WizardStateContext = createContext(void 0);
20
101
  var WizardActionsContext = createContext(void 0);
21
102
  var WizardStoreContext = createContext(void 0);
@@ -35,9 +116,10 @@ function WizardProvider({
35
116
  return localConfig.persistence?.adapter || new MemoryAdapter();
36
117
  }, [localConfig.persistence?.adapter]);
37
118
  const persistenceMode = localConfig.persistence?.mode || "onStepChange";
38
- const META_KEY = "__wizzard_meta__";
119
+ const META_KEY2 = "__wizzard_meta__";
39
120
  const snapshot = useSyncExternalStore(
40
121
  storeRef.current.subscribe,
122
+ storeRef.current.getSnapshot,
41
123
  storeRef.current.getSnapshot
42
124
  );
43
125
  const {
@@ -151,83 +233,23 @@ function WizardProvider({
151
233
  const idx = activeStepsIndexMap2.get(currentStepId2) ?? -1;
152
234
  if (idx > 0) await goToStep(activeSteps2[idx - 1].id);
153
235
  }, [goToStep]);
154
- const handleStepDependencies = useCallback(
155
- (paths, initialData2) => {
156
- let currentData = { ...initialData2 };
157
- const allClearedPaths = /* @__PURE__ */ new Set();
158
- const { completedSteps: completedSteps2, visitedSteps: visitedSteps2 } = storeRef.current.getSnapshot();
159
- const nextComp = new Set(completedSteps2);
160
- const nextVis = new Set(visitedSteps2);
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);
236
+ const setData = useCallback(
237
+ (path, value, options) => {
238
+ const { stepsMap: stepsMap2, currentStepId: currentStepId2 } = stateRef.current;
239
+ const prevData = storeRef.current.getSnapshot().data;
240
+ if (getByPath2(prevData, path) === value) return;
241
+ const baseData = setByPath2(prevData, path, value);
242
+ const { newData, hasClearing, statusChanged, nextCompletedSteps, nextVisitedSteps } = applyStepDependencies(localConfig, storeRef.current, baseData, [path]);
206
243
  if (statusChanged) {
207
244
  storeRef.current.dispatch({
208
245
  type: "SET_COMPLETED_STEPS",
209
- payload: { steps: nextComp }
246
+ payload: { steps: nextCompletedSteps }
210
247
  });
211
248
  storeRef.current.dispatch({
212
249
  type: "SET_VISITED_STEPS",
213
- payload: { steps: nextVis }
250
+ payload: { steps: nextVisitedSteps }
214
251
  });
215
252
  }
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
253
  if (!hasClearing) {
232
254
  storeRef.current.dispatch({
233
255
  type: "SET_DATA",
@@ -261,13 +283,23 @@ function WizardProvider({
261
283
  }
262
284
  }
263
285
  },
264
- [localConfig, validateStep, handleStepDependencies]
286
+ [localConfig, validateStep]
265
287
  );
266
288
  const updateData = useCallback(
267
289
  (data2, options) => {
268
290
  const prev = storeRef.current.getSnapshot().data;
269
291
  const baseData = options?.replace ? data2 : { ...prev, ...data2 };
270
- const { newData } = handleStepDependencies(Object.keys(data2), baseData);
292
+ const { newData, statusChanged, nextCompletedSteps, nextVisitedSteps } = applyStepDependencies(localConfig, storeRef.current, baseData, Object.keys(data2));
293
+ if (statusChanged) {
294
+ storeRef.current.dispatch({
295
+ type: "SET_COMPLETED_STEPS",
296
+ payload: { steps: nextCompletedSteps }
297
+ });
298
+ storeRef.current.dispatch({
299
+ type: "SET_VISITED_STEPS",
300
+ payload: { steps: nextVisitedSteps }
301
+ });
302
+ }
271
303
  storeRef.current.update(newData, Object.keys(data2));
272
304
  if (options?.persist) {
273
305
  if (storeRef.current.save) {
@@ -275,7 +307,7 @@ function WizardProvider({
275
307
  }
276
308
  }
277
309
  },
278
- [handleStepDependencies]
310
+ [localConfig]
279
311
  );
280
312
  const reset = useCallback(() => {
281
313
  storeRef.current.setInitialData(initialData || {});
@@ -370,7 +402,7 @@ function WizardProvider({
370
402
  reset,
371
403
  setData,
372
404
  updateData,
373
- getData: (p, d) => getByPath(storeRef.current.getSnapshot().data, p, d),
405
+ getData: (p, d) => getByPath2(storeRef.current.getSnapshot().data, p, d),
374
406
  updateConfig: (nc) => {
375
407
  setLocalConfig((prev) => ({ ...prev, ...nc }));
376
408
  }
@@ -421,7 +453,7 @@ function WizardProvider({
421
453
  useEffect(() => {
422
454
  if (hasHydratedRef.current) return;
423
455
  hasHydratedRef.current = true;
424
- const meta = persistenceAdapter.getStep(META_KEY);
456
+ const meta = persistenceAdapter.getStep(META_KEY2);
425
457
  if (meta) {
426
458
  if (meta.currentStepId) {
427
459
  storeRef.current.dispatch({
@@ -483,21 +515,37 @@ function useWizardState() {
483
515
  function useWizardValue(path, options) {
484
516
  const store = useContext(WizardStoreContext);
485
517
  if (!store) throw new Error("useWizardValue must be used within a WizardProvider");
486
- const lastStateRef = useRef(null);
487
- const lastValueRef = useRef(null);
518
+ const lastStateRef = useRef(UNSET);
519
+ const lastValueRef = useRef(UNSET);
520
+ const isEqual = typeof options === "function" ? options : options?.isEqual;
521
+ const isEqualRef = useRef(isEqual);
522
+ isEqualRef.current = isEqual;
488
523
  const getSnapshot = useCallback(() => {
489
524
  const data = store.getSnapshot().data;
490
- if (data === lastStateRef.current) return lastValueRef.current;
491
- const value = getByPath(data, path);
492
- if (lastValueRef.current !== void 0 && (options?.isEqual || Object.is)(lastValueRef.current, value)) {
525
+ if (data === lastStateRef.current && lastValueRef.current !== UNSET) {
526
+ return lastValueRef.current;
527
+ }
528
+ const value = getByPath2(data, path);
529
+ if (lastValueRef.current !== UNSET && (isEqualRef.current || Object.is)(lastValueRef.current, value)) {
493
530
  lastStateRef.current = data;
494
531
  return lastValueRef.current;
495
532
  }
496
533
  lastStateRef.current = data;
497
534
  lastValueRef.current = value;
498
535
  return value;
499
- }, [store, path, options?.isEqual]);
500
- return useSyncExternalStore(store.subscribe, getSnapshot);
536
+ }, [store, path]);
537
+ return useSyncExternalStore(store.subscribe, getSnapshot, getSnapshot);
538
+ }
539
+ function useWizardField(path, options) {
540
+ const value = useWizardValue(path, options);
541
+ const { setData } = useWizardActions();
542
+ const setValue = useCallback(
543
+ (next) => {
544
+ setData(path, next);
545
+ },
546
+ [setData, path]
547
+ );
548
+ return [value, setValue];
501
549
  }
502
550
  function useWizardError(path) {
503
551
  const store = useContext(WizardStoreContext);
@@ -510,22 +558,33 @@ function useWizardError(path) {
510
558
  }
511
559
  return void 0;
512
560
  }, [store, path]);
513
- return useSyncExternalStore(store.subscribe, getSnapshot);
561
+ return useSyncExternalStore(store.subscribe, getSnapshot, getSnapshot);
514
562
  }
515
563
  function useWizardSelector(selector, options) {
516
564
  const store = useContext(WizardStoreContext);
517
565
  if (!store) throw new Error("useWizardSelector must be used within a WizardProvider");
518
- const lastResultRef = useRef(null);
566
+ const selectorRef = useRef(selector);
567
+ selectorRef.current = selector;
568
+ const isEqual = typeof options === "function" ? options : options?.isEqual;
569
+ const isEqualRef = useRef(isEqual);
570
+ isEqualRef.current = isEqual;
571
+ const lastStateRef = useRef(UNSET);
572
+ const lastResultRef = useRef(UNSET);
519
573
  const getSnapshot = useCallback(() => {
520
574
  const full = store.getSnapshot();
521
- const res = selector(full);
522
- if (lastResultRef.current !== null && (options?.isEqual || Object.is)(lastResultRef.current, res)) {
575
+ if (full === lastStateRef.current && lastResultRef.current !== UNSET) {
576
+ return lastResultRef.current;
577
+ }
578
+ const res = selectorRef.current(full);
579
+ if (lastResultRef.current !== UNSET && (isEqualRef.current || Object.is)(lastResultRef.current, res)) {
580
+ lastStateRef.current = full;
523
581
  return lastResultRef.current;
524
582
  }
583
+ lastStateRef.current = full;
525
584
  lastResultRef.current = res;
526
585
  return res;
527
- }, [store, selector, options?.isEqual]);
528
- return useSyncExternalStore(store.subscribe, getSnapshot);
586
+ }, [store]);
587
+ return useSyncExternalStore(store.subscribe, getSnapshot, getSnapshot);
529
588
  }
530
589
  function useWizardActions() {
531
590
  const context = useContext(WizardActionsContext);
@@ -558,6 +617,44 @@ function useWizardContext() {
558
617
  [stateProps, actions, data, allErrors, errors, store]
559
618
  );
560
619
  }
620
+ function useWizardCurrentStep() {
621
+ return useWizardSelector((s) => s.currentStep);
622
+ }
623
+ function useWizardSteps() {
624
+ return useWizardSelector((s) => s.activeSteps);
625
+ }
626
+ function useWizardMeta() {
627
+ return useWizardSelector(
628
+ (s) => ({
629
+ currentStepId: s.currentStepId,
630
+ currentStepIndex: s.currentStepIndex,
631
+ isFirstStep: s.isFirstStep,
632
+ isLastStep: s.isLastStep,
633
+ isLoading: s.isLoading,
634
+ isBusy: s.isBusy,
635
+ isDirty: s.isDirty,
636
+ progress: s.progress,
637
+ activeStepsCount: s.activeStepsCount,
638
+ goToStepResult: s.goToStepResult
639
+ }),
640
+ { isEqual: shallowEqual }
641
+ );
642
+ }
643
+ function useWizardAllErrors() {
644
+ return useWizardSelector((s) => s.errors, {
645
+ isEqual: shallowEqual
646
+ });
647
+ }
648
+ function useWizardFlatErrors() {
649
+ const allErrors = useWizardAllErrors();
650
+ return useMemo(() => {
651
+ const flat = {};
652
+ Object.values(allErrors).forEach((stepErrors) => {
653
+ Object.assign(flat, stepErrors);
654
+ });
655
+ return flat;
656
+ }, [allErrors]);
657
+ }
561
658
 
562
659
  // src/hooks/useWizard.ts
563
660
  var useWizard = () => {
@@ -570,9 +667,18 @@ function createWizardFactory() {
570
667
  const WizardProvider2 = ({
571
668
  config,
572
669
  initialData,
670
+ initialStepId,
573
671
  children
574
672
  }) => {
575
- return /* @__PURE__ */ jsx2(WizardProvider, { config, initialData, children });
673
+ return /* @__PURE__ */ jsx2(
674
+ WizardProvider,
675
+ {
676
+ config,
677
+ initialData,
678
+ initialStepId,
679
+ children
680
+ }
681
+ );
576
682
  };
577
683
  const useWizard2 = () => {
578
684
  return useWizard();
@@ -583,9 +689,17 @@ function createWizardFactory() {
583
689
  const useWizardValue2 = (path, options) => {
584
690
  return useWizardValue(path, options);
585
691
  };
692
+ const useWizardField2 = (path, options) => {
693
+ const value = useWizardValue2(path, options);
694
+ const { setData } = useWizardActions2();
695
+ return [value, (next) => setData(path, next)];
696
+ };
586
697
  const useWizardSelector2 = (selector, options) => {
587
698
  return useWizardSelector(selector, options);
588
699
  };
700
+ const useWizardShallowSelector = (selector) => {
701
+ return useWizardSelector2(selector, shallowEqual2);
702
+ };
589
703
  const useWizardError2 = (path) => {
590
704
  return useWizardError(path);
591
705
  };
@@ -604,7 +718,9 @@ function createWizardFactory() {
604
718
  useWizard: useWizard2,
605
719
  useWizardContext: useWizardContext2,
606
720
  useWizardValue: useWizardValue2,
721
+ useWizardField: useWizardField2,
607
722
  useWizardSelector: useWizardSelector2,
723
+ useWizardShallowSelector,
608
724
  useWizardError: useWizardError2,
609
725
  useWizardActions: useWizardActions2,
610
726
  useWizardState: useWizardState2,
@@ -635,21 +751,420 @@ var WizardStepRenderer = ({
635
751
  return content;
636
752
  };
637
753
 
754
+ // src/store.ts
755
+ import {
756
+ WizardStore as WizardStore2,
757
+ getByPath as getByPath3,
758
+ setByPath as setByPath3
759
+ } from "@wizzard-packages/core";
760
+ import { MemoryAdapter as MemoryAdapter2 } from "@wizzard-packages/persistence";
761
+ import { useCallback as useCallback2, useRef as useRef2, useSyncExternalStore as useSyncExternalStore2 } from "react";
762
+ var UNSET2 = /* @__PURE__ */ Symbol("wizard_store_unset");
763
+ var META_KEY = "__wizzard_meta__";
764
+ var applyStoredMeta = (store, adapter) => {
765
+ const meta = adapter.getStep(META_KEY);
766
+ if (!meta) return;
767
+ if (meta.currentStepId) {
768
+ store.dispatch({
769
+ type: "SET_CURRENT_STEP_ID",
770
+ payload: { stepId: meta.currentStepId }
771
+ });
772
+ }
773
+ if (meta.visited) {
774
+ store.dispatch({
775
+ type: "SET_VISITED_STEPS",
776
+ payload: { steps: new Set(meta.visited) }
777
+ });
778
+ }
779
+ if (meta.completed) {
780
+ store.dispatch({
781
+ type: "SET_COMPLETED_STEPS",
782
+ payload: { steps: new Set(meta.completed) }
783
+ });
784
+ }
785
+ if (meta.history) {
786
+ store.dispatch({
787
+ type: "SET_HISTORY",
788
+ payload: { history: meta.history }
789
+ });
790
+ }
791
+ };
792
+ var ensureInitialStep = (store, activeSteps, initialStepId) => {
793
+ const snapshot = store.getSnapshot();
794
+ if (snapshot.currentStepId || activeSteps.length === 0) return;
795
+ const startId = initialStepId && activeSteps.some((s) => s.id === initialStepId) ? initialStepId : activeSteps[0].id;
796
+ store.dispatch({
797
+ type: "SET_CURRENT_STEP_ID",
798
+ payload: { stepId: startId }
799
+ });
800
+ if (snapshot.history.length === 0) {
801
+ store.dispatch({
802
+ type: "SET_HISTORY",
803
+ payload: { history: [startId] }
804
+ });
805
+ }
806
+ const currentVisited = new Set(snapshot.visitedSteps);
807
+ if (!currentVisited.has(startId)) {
808
+ currentVisited.add(startId);
809
+ store.dispatch({
810
+ type: "SET_VISITED_STEPS",
811
+ payload: { steps: currentVisited }
812
+ });
813
+ }
814
+ };
815
+ var resolveAndSetActiveSteps = async (store, data, initialStepId) => {
816
+ const resolved = await store.resolveActiveSteps(data);
817
+ store.dispatch({
818
+ type: "SET_ACTIVE_STEPS",
819
+ payload: { steps: resolved }
820
+ });
821
+ ensureInitialStep(store, resolved, initialStepId);
822
+ const snapshot = store.getSnapshot();
823
+ if (resolved.length > 0 && snapshot.isLoading) {
824
+ store.updateMeta({ isLoading: false });
825
+ }
826
+ };
827
+ var createWizardActions = (store, config, persistenceAdapter, initialData) => {
828
+ let currentConfig = config;
829
+ const validationDebounceRef = { current: null };
830
+ const stepsMap = /* @__PURE__ */ new Map();
831
+ currentConfig.steps.forEach((step) => stepsMap.set(step.id, step));
832
+ const resolveActiveStepsHelper = (data) => store.resolveActiveSteps(data);
833
+ const validateStep = (stepId) => store.validateStep(stepId);
834
+ const setData = (path, value, options) => {
835
+ const prevData = store.getSnapshot().data;
836
+ if (getByPath3(prevData, path) === value) return;
837
+ const baseData = setByPath3(prevData, path, value);
838
+ const { newData, hasClearing, statusChanged, nextCompletedSteps, nextVisitedSteps } = applyStepDependencies(currentConfig, store, baseData, [path]);
839
+ if (statusChanged) {
840
+ store.dispatch({
841
+ type: "SET_COMPLETED_STEPS",
842
+ payload: { steps: nextCompletedSteps }
843
+ });
844
+ store.dispatch({
845
+ type: "SET_VISITED_STEPS",
846
+ payload: { steps: nextVisitedSteps }
847
+ });
848
+ }
849
+ if (!hasClearing) {
850
+ store.dispatch({
851
+ type: "SET_DATA",
852
+ payload: {
853
+ path,
854
+ value,
855
+ options: { ...options, __from_set_data__: true }
856
+ }
857
+ });
858
+ } else {
859
+ store.dispatch({
860
+ type: "UPDATE_DATA",
861
+ payload: {
862
+ data: newData,
863
+ options: { replace: true, __from_set_data__: true, path }
864
+ }
865
+ });
866
+ }
867
+ const snapshot = store.getSnapshot();
868
+ const currentStepId = snapshot.currentStepId;
869
+ if (currentStepId) {
870
+ store.deleteError(currentStepId, path);
871
+ const step = stepsMap.get(currentStepId);
872
+ const mode = step?.validationMode || currentConfig.validationMode || "onStepChange";
873
+ if (mode === "onChange") {
874
+ const debounceMs = options?.debounceValidation ?? currentConfig.validationDebounceTime ?? 300;
875
+ if (validationDebounceRef.current) {
876
+ clearTimeout(validationDebounceRef.current);
877
+ }
878
+ validationDebounceRef.current = setTimeout(() => {
879
+ void validateStep(currentStepId);
880
+ }, debounceMs);
881
+ }
882
+ }
883
+ };
884
+ const updateData = (data, options) => {
885
+ const prev = store.getSnapshot().data;
886
+ const baseData = options?.replace ? data : { ...prev, ...data };
887
+ const { newData, statusChanged, nextCompletedSteps, nextVisitedSteps } = applyStepDependencies(
888
+ currentConfig,
889
+ store,
890
+ baseData,
891
+ Object.keys(data)
892
+ );
893
+ if (statusChanged) {
894
+ store.dispatch({
895
+ type: "SET_COMPLETED_STEPS",
896
+ payload: { steps: nextCompletedSteps }
897
+ });
898
+ store.dispatch({
899
+ type: "SET_VISITED_STEPS",
900
+ payload: { steps: nextVisitedSteps }
901
+ });
902
+ }
903
+ store.update(newData, Object.keys(data));
904
+ if (options?.persist) {
905
+ store.save(store.getSnapshot().currentStepId);
906
+ }
907
+ };
908
+ const reset = () => {
909
+ store.setInitialData(initialData || {});
910
+ store.update(initialData || {});
911
+ store.updateErrors({});
912
+ store.dispatch({
913
+ type: "SET_VISITED_STEPS",
914
+ payload: { steps: /* @__PURE__ */ new Set() }
915
+ });
916
+ store.dispatch({
917
+ type: "SET_COMPLETED_STEPS",
918
+ payload: { steps: /* @__PURE__ */ new Set() }
919
+ });
920
+ store.dispatch({
921
+ type: "SET_ERROR_STEPS",
922
+ payload: { steps: /* @__PURE__ */ new Set() }
923
+ });
924
+ const snapshot = store.getSnapshot();
925
+ if (snapshot.activeSteps.length > 0) {
926
+ const startId = snapshot.activeSteps[0].id;
927
+ store.dispatch({
928
+ type: "SET_CURRENT_STEP_ID",
929
+ payload: { stepId: startId }
930
+ });
931
+ store.dispatch({
932
+ type: "SET_HISTORY",
933
+ payload: { history: [startId] }
934
+ });
935
+ } else {
936
+ store.dispatch({
937
+ type: "SET_CURRENT_STEP_ID",
938
+ payload: { stepId: "" }
939
+ });
940
+ store.dispatch({
941
+ type: "SET_HISTORY",
942
+ payload: { history: [] }
943
+ });
944
+ }
945
+ persistenceAdapter.clear();
946
+ currentConfig.analytics?.onEvent("wizard_reset", { data: initialData });
947
+ };
948
+ const goToStep = (stepId, providedActiveSteps, options) => {
949
+ return store.goToStep(stepId, {
950
+ validate: options?.validate ?? true,
951
+ providedActiveSteps
952
+ });
953
+ };
954
+ const goToNextStep = async () => {
955
+ const snapshot = store.getSnapshot();
956
+ const currentStepId = snapshot.currentStepId;
957
+ if (!currentStepId) return;
958
+ const step = stepsMap.get(currentStepId);
959
+ const shouldVal = step?.autoValidate ?? currentConfig.autoValidate ?? !!step?.validationAdapter;
960
+ if (shouldVal) {
961
+ const ok = await validateStep(currentStepId);
962
+ if (!ok) return;
963
+ }
964
+ const resolvedSteps = await resolveActiveStepsHelper(snapshot.data);
965
+ const idx = resolvedSteps.findIndex((s) => s.id === currentStepId);
966
+ if (idx !== -1 && idx < resolvedSteps.length - 1) {
967
+ const nextStepId = resolvedSteps[idx + 1].id;
968
+ const success = await goToStep(nextStepId, resolvedSteps, {
969
+ validate: false
970
+ });
971
+ if (success) {
972
+ const currentSnapshot = store.getSnapshot();
973
+ if (!currentSnapshot.errorSteps.has(currentStepId)) {
974
+ const nextComp = new Set(currentSnapshot.completedSteps);
975
+ nextComp.add(currentStepId);
976
+ store.dispatch({
977
+ type: "SET_COMPLETED_STEPS",
978
+ payload: { steps: nextComp }
979
+ });
980
+ }
981
+ }
982
+ }
983
+ };
984
+ const goToPrevStep = async () => {
985
+ const snapshot = store.getSnapshot();
986
+ const idx = snapshot.activeSteps.findIndex((s) => s.id === snapshot.currentStepId);
987
+ if (idx > 0) {
988
+ await goToStep(snapshot.activeSteps[idx - 1].id);
989
+ }
990
+ };
991
+ const setStepData = (_stepId, data) => {
992
+ const next = { ...store.getSnapshot().data, ...data };
993
+ store.update(next, Object.keys(data));
994
+ };
995
+ const handleStepChange = (field, value) => {
996
+ if (store.getSnapshot().currentStepId) {
997
+ setData(field, value);
998
+ }
999
+ };
1000
+ const validateAll = async () => {
1001
+ const result = await store.validateAll();
1002
+ return result;
1003
+ };
1004
+ const save = (ids) => {
1005
+ if (ids === true) {
1006
+ currentConfig.steps.forEach((s) => store.save(s.id));
1007
+ } else if (!ids) {
1008
+ store.save();
1009
+ } else {
1010
+ (Array.isArray(ids) ? ids : [ids]).forEach((id) => store.save(id));
1011
+ }
1012
+ };
1013
+ const clearStorage = () => persistenceAdapter.clear();
1014
+ const getData = (path, defaultValue) => {
1015
+ return getByPath3(store.getSnapshot().data, path, defaultValue);
1016
+ };
1017
+ const updateConfig = (nextConfig) => {
1018
+ currentConfig = { ...currentConfig, ...nextConfig };
1019
+ stepsMap.clear();
1020
+ currentConfig.steps.forEach((step) => stepsMap.set(step.id, step));
1021
+ store.updateMeta({ config: currentConfig });
1022
+ };
1023
+ return {
1024
+ goToNextStep,
1025
+ goToPrevStep,
1026
+ goToStep,
1027
+ setStepData,
1028
+ handleStepChange,
1029
+ validateStep,
1030
+ validateAll,
1031
+ save,
1032
+ clearStorage,
1033
+ reset,
1034
+ setData,
1035
+ updateData,
1036
+ getData,
1037
+ updateConfig
1038
+ };
1039
+ };
1040
+ var createWizardStore = (options) => {
1041
+ const initialData = options.initialData || {};
1042
+ const store = new WizardStore2(initialData, options.config.middlewares);
1043
+ const persistenceAdapter = options.config.persistence?.adapter || new MemoryAdapter2();
1044
+ store.injectPersistence(persistenceAdapter);
1045
+ store.dispatch({
1046
+ type: "INIT",
1047
+ payload: { data: initialData, config: options.config }
1048
+ });
1049
+ store.hydrate();
1050
+ applyStoredMeta(store, persistenceAdapter);
1051
+ void resolveAndSetActiveSteps(store, store.getSnapshot().data, options.initialStepId);
1052
+ return {
1053
+ store,
1054
+ actions: createWizardActions(store, options.config, persistenceAdapter, initialData)
1055
+ };
1056
+ };
1057
+ var useWizardStoreState = (store) => {
1058
+ return useSyncExternalStore2(store.subscribe, store.getSnapshot, store.getSnapshot);
1059
+ };
1060
+ var useWizardStoreValue = (store, path, options) => {
1061
+ const lastStateRef = useRef2(UNSET2);
1062
+ const lastValueRef = useRef2(UNSET2);
1063
+ const isEqual = typeof options === "function" ? options : options?.isEqual;
1064
+ const isEqualRef = useRef2(isEqual);
1065
+ isEqualRef.current = isEqual;
1066
+ const getSnapshot = useCallback2(() => {
1067
+ const data = store.getSnapshot().data;
1068
+ if (data === lastStateRef.current && lastValueRef.current !== UNSET2) {
1069
+ return lastValueRef.current;
1070
+ }
1071
+ const value = getByPath3(data, path);
1072
+ if (lastValueRef.current !== UNSET2 && (isEqualRef.current || Object.is)(lastValueRef.current, value)) {
1073
+ lastStateRef.current = data;
1074
+ return lastValueRef.current;
1075
+ }
1076
+ lastStateRef.current = data;
1077
+ lastValueRef.current = value;
1078
+ return value;
1079
+ }, [store, path]);
1080
+ return useSyncExternalStore2(store.subscribe, getSnapshot, getSnapshot);
1081
+ };
1082
+ var useWizardStoreField = (store, setData, path, options) => {
1083
+ const value = useWizardStoreValue(store, path, options);
1084
+ const setValue = useCallback2(
1085
+ (next) => {
1086
+ setData(path, next);
1087
+ },
1088
+ [setData, path]
1089
+ );
1090
+ return [value, setValue];
1091
+ };
1092
+ var useWizardStoreError = (store, path) => {
1093
+ const getSnapshot = useCallback2(() => {
1094
+ const errors = store.getSnapshot().errors;
1095
+ for (const [_, stepErrors] of Object.entries(errors)) {
1096
+ const typed = stepErrors;
1097
+ if (typed[path]) return typed[path];
1098
+ }
1099
+ return void 0;
1100
+ }, [store, path]);
1101
+ return useSyncExternalStore2(store.subscribe, getSnapshot, getSnapshot);
1102
+ };
1103
+ var useWizardStoreSelector = (store, selector, options) => {
1104
+ const selectorRef = useRef2(selector);
1105
+ selectorRef.current = selector;
1106
+ const isEqual = typeof options === "function" ? options : options?.isEqual;
1107
+ const isEqualRef = useRef2(isEqual);
1108
+ isEqualRef.current = isEqual;
1109
+ const lastStateRef = useRef2(UNSET2);
1110
+ const lastResultRef = useRef2(UNSET2);
1111
+ const getSnapshot = useCallback2(() => {
1112
+ const full = store.getSnapshot();
1113
+ if (full === lastStateRef.current && lastResultRef.current !== UNSET2) {
1114
+ return lastResultRef.current;
1115
+ }
1116
+ const res = selectorRef.current(full);
1117
+ if (lastResultRef.current !== UNSET2 && (isEqualRef.current || Object.is)(lastResultRef.current, res)) {
1118
+ lastStateRef.current = full;
1119
+ return lastResultRef.current;
1120
+ }
1121
+ lastStateRef.current = full;
1122
+ lastResultRef.current = res;
1123
+ return res;
1124
+ }, [store]);
1125
+ return useSyncExternalStore2(store.subscribe, getSnapshot, getSnapshot);
1126
+ };
1127
+ var createWizardHooks = (store, actions) => ({
1128
+ useWizardState: () => useWizardStoreState(store),
1129
+ useWizardValue: (path, options) => useWizardStoreValue(store, path, options),
1130
+ useWizardField: (path, options) => {
1131
+ if (!actions) {
1132
+ throw new Error("useWizardField requires actions. Pass actions to createWizardHooks.");
1133
+ }
1134
+ return useWizardStoreField(store, actions.setData, path, options);
1135
+ },
1136
+ useWizardError: (path) => useWizardStoreError(store, path),
1137
+ useWizardSelector: (selector, options) => useWizardStoreSelector(store, selector, options)
1138
+ });
1139
+
638
1140
  // src/index.ts
639
- import { WizardStore as WizardStore2 } from "@wizzard-packages/core";
1141
+ import { WizardStore as WizardStore3 } from "@wizzard-packages/core";
640
1142
  import { loggerMiddleware } from "@wizzard-packages/middleware";
641
1143
  export {
642
1144
  WizardProvider,
643
1145
  WizardStepRenderer,
644
- WizardStore2 as WizardStore,
1146
+ WizardStore3 as WizardStore,
645
1147
  createWizardFactory,
1148
+ createWizardHooks,
1149
+ createWizardStore,
646
1150
  loggerMiddleware,
647
1151
  useWizard,
648
1152
  useWizardActions,
1153
+ useWizardAllErrors,
649
1154
  useWizardContext,
1155
+ useWizardCurrentStep,
650
1156
  useWizardError,
1157
+ useWizardField,
1158
+ useWizardFlatErrors,
1159
+ useWizardMeta,
651
1160
  useWizardSelector,
652
1161
  useWizardState,
1162
+ useWizardSteps,
1163
+ useWizardStoreError,
1164
+ useWizardStoreField,
1165
+ useWizardStoreSelector,
1166
+ useWizardStoreState,
1167
+ useWizardStoreValue,
653
1168
  useWizardValue
654
1169
  };
655
1170
  //# sourceMappingURL=index.js.map