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