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