@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/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
- import { MemoryAdapter } from "@wizzard-packages/persistence";
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 META_KEY = "__wizzard_meta__";
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 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);
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: nextComp }
241
+ payload: { steps: nextCompletedSteps }
210
242
  });
211
243
  storeRef.current.dispatch({
212
244
  type: "SET_VISITED_STEPS",
213
- payload: { steps: nextVis }
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, handleStepDependencies]
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 } = handleStepDependencies(Object.keys(data2), baseData);
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
- [handleStepDependencies]
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) => getByPath(storeRef.current.getSnapshot().data, 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(META_KEY);
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(null);
514
+ const lastValueRef = useRef(UNSET);
488
515
  const getSnapshot = useCallback(() => {
489
516
  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)) {
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(null);
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 !== null && (options?.isEqual || Object.is)(lastResultRef.current, res)) {
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(WizardProvider, { config, initialData, children });
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 WizardStore2 } from "@wizzard-packages/core";
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
- WizardStore2 as WizardStore,
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