@wizzard-packages/react 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/index.cjs +680 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +116 -0
- package/dist/index.d.ts +116 -0
- package/dist/index.js +655 -0
- package/dist/index.js.map +1 -0
- package/package.json +48 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Aziz
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,680 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
WizardProvider: () => WizardProvider,
|
|
24
|
+
WizardStepRenderer: () => WizardStepRenderer,
|
|
25
|
+
WizardStore: () => import_core2.WizardStore,
|
|
26
|
+
createWizardFactory: () => createWizardFactory,
|
|
27
|
+
loggerMiddleware: () => import_middleware.loggerMiddleware,
|
|
28
|
+
useWizard: () => useWizard,
|
|
29
|
+
useWizardActions: () => useWizardActions,
|
|
30
|
+
useWizardContext: () => useWizardContext,
|
|
31
|
+
useWizardError: () => useWizardError,
|
|
32
|
+
useWizardSelector: () => useWizardSelector,
|
|
33
|
+
useWizardState: () => useWizardState,
|
|
34
|
+
useWizardValue: () => useWizardValue
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(index_exports);
|
|
37
|
+
|
|
38
|
+
// src/context/WizardContext.tsx
|
|
39
|
+
var import_react = require("react");
|
|
40
|
+
var import_core = require("@wizzard-packages/core");
|
|
41
|
+
var import_persistence = require("@wizzard-packages/persistence");
|
|
42
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
43
|
+
var WizardStateContext = (0, import_react.createContext)(void 0);
|
|
44
|
+
var WizardActionsContext = (0, import_react.createContext)(void 0);
|
|
45
|
+
var WizardStoreContext = (0, import_react.createContext)(void 0);
|
|
46
|
+
function WizardProvider({
|
|
47
|
+
config,
|
|
48
|
+
initialData,
|
|
49
|
+
initialStepId,
|
|
50
|
+
children
|
|
51
|
+
}) {
|
|
52
|
+
const [localConfig, setLocalConfig] = (0, import_react.useState)(config);
|
|
53
|
+
const storeRef = (0, import_react.useRef)(null);
|
|
54
|
+
if (!storeRef.current) {
|
|
55
|
+
storeRef.current = new import_core.WizardStore(initialData || {}, config.middlewares);
|
|
56
|
+
}
|
|
57
|
+
const isInitialized = (0, import_react.useRef)(false);
|
|
58
|
+
const persistenceAdapter = (0, import_react.useMemo)(() => {
|
|
59
|
+
return localConfig.persistence?.adapter || new import_persistence.MemoryAdapter();
|
|
60
|
+
}, [localConfig.persistence?.adapter]);
|
|
61
|
+
const persistenceMode = localConfig.persistence?.mode || "onStepChange";
|
|
62
|
+
const META_KEY = "__wizzard_meta__";
|
|
63
|
+
const snapshot = (0, import_react.useSyncExternalStore)(
|
|
64
|
+
storeRef.current.subscribe,
|
|
65
|
+
storeRef.current.getSnapshot
|
|
66
|
+
);
|
|
67
|
+
const {
|
|
68
|
+
activeSteps,
|
|
69
|
+
currentStepId,
|
|
70
|
+
history,
|
|
71
|
+
visitedSteps,
|
|
72
|
+
completedSteps,
|
|
73
|
+
data,
|
|
74
|
+
errors: _errors
|
|
75
|
+
} = snapshot;
|
|
76
|
+
const stepsMap = (0, import_react.useMemo)(() => {
|
|
77
|
+
const map = /* @__PURE__ */ new Map();
|
|
78
|
+
localConfig.steps.forEach((step) => map.set(step.id, step));
|
|
79
|
+
return map;
|
|
80
|
+
}, [localConfig.steps]);
|
|
81
|
+
(0, import_react.useEffect)(() => {
|
|
82
|
+
setLocalConfig(config);
|
|
83
|
+
}, [config]);
|
|
84
|
+
const activeStepsIndexMap = (0, import_react.useMemo)(() => {
|
|
85
|
+
const map = /* @__PURE__ */ new Map();
|
|
86
|
+
activeSteps.forEach((s, i) => map.set(s.id, i));
|
|
87
|
+
return map;
|
|
88
|
+
}, [activeSteps]);
|
|
89
|
+
const stateRef = (0, import_react.useRef)({
|
|
90
|
+
config: localConfig,
|
|
91
|
+
stepsMap,
|
|
92
|
+
activeSteps,
|
|
93
|
+
activeStepsIndexMap,
|
|
94
|
+
visitedSteps,
|
|
95
|
+
completedSteps,
|
|
96
|
+
persistenceMode,
|
|
97
|
+
persistenceAdapter,
|
|
98
|
+
currentStepId,
|
|
99
|
+
history
|
|
100
|
+
});
|
|
101
|
+
const validationDebounceRef = (0, import_react.useRef)(null);
|
|
102
|
+
(0, import_react.useEffect)(() => {
|
|
103
|
+
stateRef.current = {
|
|
104
|
+
config: localConfig,
|
|
105
|
+
stepsMap,
|
|
106
|
+
activeSteps,
|
|
107
|
+
activeStepsIndexMap,
|
|
108
|
+
visitedSteps,
|
|
109
|
+
completedSteps,
|
|
110
|
+
persistenceMode,
|
|
111
|
+
persistenceAdapter,
|
|
112
|
+
currentStepId,
|
|
113
|
+
history
|
|
114
|
+
};
|
|
115
|
+
});
|
|
116
|
+
(0, import_react.useEffect)(() => {
|
|
117
|
+
return () => {
|
|
118
|
+
if (validationDebounceRef.current) {
|
|
119
|
+
clearTimeout(validationDebounceRef.current);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
}, []);
|
|
123
|
+
const trackEvent = (0, import_react.useCallback)(
|
|
124
|
+
(name, payload) => {
|
|
125
|
+
localConfig.analytics?.onEvent(name, payload);
|
|
126
|
+
},
|
|
127
|
+
[localConfig.analytics]
|
|
128
|
+
);
|
|
129
|
+
const resolveActiveStepsHelper = (0, import_react.useCallback)(
|
|
130
|
+
(data2) => storeRef.current.resolveActiveSteps(data2),
|
|
131
|
+
[]
|
|
132
|
+
);
|
|
133
|
+
const validateStep = (0, import_react.useCallback)((stepId) => storeRef.current.validateStep(stepId), []);
|
|
134
|
+
const goToStep = (0, import_react.useCallback)(
|
|
135
|
+
async (stepId, providedActiveSteps, options = { validate: true }) => {
|
|
136
|
+
return storeRef.current.goToStep(stepId, {
|
|
137
|
+
validate: options.validate,
|
|
138
|
+
providedActiveSteps
|
|
139
|
+
});
|
|
140
|
+
},
|
|
141
|
+
[]
|
|
142
|
+
);
|
|
143
|
+
const goToNextStep = (0, import_react.useCallback)(async () => {
|
|
144
|
+
const { currentStepId: currentStepId2 } = stateRef.current;
|
|
145
|
+
if (!currentStepId2) return;
|
|
146
|
+
const currentData = storeRef.current.getSnapshot().data;
|
|
147
|
+
const step = stepsMap.get(currentStepId2);
|
|
148
|
+
const shouldVal = step?.autoValidate ?? localConfig.autoValidate ?? !!step?.validationAdapter;
|
|
149
|
+
if (shouldVal) {
|
|
150
|
+
const ok = await validateStep(currentStepId2);
|
|
151
|
+
if (!ok) return;
|
|
152
|
+
}
|
|
153
|
+
const resolvedSteps = await resolveActiveStepsHelper(currentData);
|
|
154
|
+
const idx = resolvedSteps.findIndex((s) => s.id === currentStepId2);
|
|
155
|
+
if (idx !== -1 && idx < resolvedSteps.length - 1) {
|
|
156
|
+
const nextStepId = resolvedSteps[idx + 1].id;
|
|
157
|
+
const success = await goToStep(nextStepId, resolvedSteps, {
|
|
158
|
+
validate: false
|
|
159
|
+
});
|
|
160
|
+
if (success) {
|
|
161
|
+
const currentSnapshot = storeRef.current.getSnapshot();
|
|
162
|
+
if (!currentSnapshot.errorSteps.has(currentStepId2)) {
|
|
163
|
+
const nextComp = new Set(currentSnapshot.completedSteps);
|
|
164
|
+
nextComp.add(currentStepId2);
|
|
165
|
+
storeRef.current.dispatch({
|
|
166
|
+
type: "SET_COMPLETED_STEPS",
|
|
167
|
+
payload: { steps: nextComp }
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}, [goToStep, resolveActiveStepsHelper, validateStep, stepsMap, localConfig]);
|
|
173
|
+
const goToPrevStep = (0, import_react.useCallback)(async () => {
|
|
174
|
+
const { currentStepId: currentStepId2, activeSteps: activeSteps2, activeStepsIndexMap: activeStepsIndexMap2 } = stateRef.current;
|
|
175
|
+
const idx = activeStepsIndexMap2.get(currentStepId2) ?? -1;
|
|
176
|
+
if (idx > 0) await goToStep(activeSteps2[idx - 1].id);
|
|
177
|
+
}, [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);
|
|
230
|
+
if (statusChanged) {
|
|
231
|
+
storeRef.current.dispatch({
|
|
232
|
+
type: "SET_COMPLETED_STEPS",
|
|
233
|
+
payload: { steps: nextComp }
|
|
234
|
+
});
|
|
235
|
+
storeRef.current.dispatch({
|
|
236
|
+
type: "SET_VISITED_STEPS",
|
|
237
|
+
payload: { steps: nextVis }
|
|
238
|
+
});
|
|
239
|
+
}
|
|
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
|
+
if (!hasClearing) {
|
|
256
|
+
storeRef.current.dispatch({
|
|
257
|
+
type: "SET_DATA",
|
|
258
|
+
payload: {
|
|
259
|
+
path,
|
|
260
|
+
value,
|
|
261
|
+
options: { ...options, __from_set_data__: true }
|
|
262
|
+
}
|
|
263
|
+
});
|
|
264
|
+
} else {
|
|
265
|
+
storeRef.current.dispatch({
|
|
266
|
+
type: "UPDATE_DATA",
|
|
267
|
+
payload: {
|
|
268
|
+
data: newData,
|
|
269
|
+
options: { replace: true, __from_set_data__: true, path }
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
if (currentStepId2) {
|
|
274
|
+
storeRef.current.deleteError(currentStepId2, path);
|
|
275
|
+
const step = stepsMap2.get(currentStepId2);
|
|
276
|
+
const mode = step?.validationMode || localConfig.validationMode || "onStepChange";
|
|
277
|
+
if (mode === "onChange") {
|
|
278
|
+
const debounceMs = options?.debounceValidation ?? localConfig.validationDebounceTime ?? 300;
|
|
279
|
+
if (validationDebounceRef.current) {
|
|
280
|
+
clearTimeout(validationDebounceRef.current);
|
|
281
|
+
}
|
|
282
|
+
validationDebounceRef.current = setTimeout(() => {
|
|
283
|
+
validateStep(currentStepId2);
|
|
284
|
+
}, debounceMs);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
},
|
|
288
|
+
[localConfig, validateStep, handleStepDependencies]
|
|
289
|
+
);
|
|
290
|
+
const updateData = (0, import_react.useCallback)(
|
|
291
|
+
(data2, options) => {
|
|
292
|
+
const prev = storeRef.current.getSnapshot().data;
|
|
293
|
+
const baseData = options?.replace ? data2 : { ...prev, ...data2 };
|
|
294
|
+
const { newData } = handleStepDependencies(Object.keys(data2), baseData);
|
|
295
|
+
storeRef.current.update(newData, Object.keys(data2));
|
|
296
|
+
if (options?.persist) {
|
|
297
|
+
if (storeRef.current.save) {
|
|
298
|
+
storeRef.current.save(storeRef.current.getSnapshot().currentStepId);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
},
|
|
302
|
+
[handleStepDependencies]
|
|
303
|
+
);
|
|
304
|
+
const reset = (0, import_react.useCallback)(() => {
|
|
305
|
+
storeRef.current.setInitialData(initialData || {});
|
|
306
|
+
storeRef.current.update(initialData || {});
|
|
307
|
+
storeRef.current.updateErrors({});
|
|
308
|
+
storeRef.current.dispatch({
|
|
309
|
+
type: "SET_VISITED_STEPS",
|
|
310
|
+
payload: { steps: /* @__PURE__ */ new Set() }
|
|
311
|
+
});
|
|
312
|
+
storeRef.current.dispatch({
|
|
313
|
+
type: "SET_COMPLETED_STEPS",
|
|
314
|
+
payload: { steps: /* @__PURE__ */ new Set() }
|
|
315
|
+
});
|
|
316
|
+
storeRef.current.dispatch({
|
|
317
|
+
type: "SET_ERROR_STEPS",
|
|
318
|
+
payload: { steps: /* @__PURE__ */ new Set() }
|
|
319
|
+
});
|
|
320
|
+
if (activeSteps.length > 0) {
|
|
321
|
+
const startId = activeSteps[0].id;
|
|
322
|
+
storeRef.current.dispatch({
|
|
323
|
+
type: "SET_CURRENT_STEP_ID",
|
|
324
|
+
payload: { stepId: startId }
|
|
325
|
+
});
|
|
326
|
+
storeRef.current.dispatch({
|
|
327
|
+
type: "SET_HISTORY",
|
|
328
|
+
payload: { history: [startId] }
|
|
329
|
+
});
|
|
330
|
+
} else {
|
|
331
|
+
storeRef.current.dispatch({
|
|
332
|
+
type: "SET_CURRENT_STEP_ID",
|
|
333
|
+
payload: { stepId: "" }
|
|
334
|
+
});
|
|
335
|
+
storeRef.current.dispatch({
|
|
336
|
+
type: "SET_HISTORY",
|
|
337
|
+
payload: { history: [] }
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
persistenceAdapter.clear();
|
|
341
|
+
trackEvent("wizard_reset", { data: initialData });
|
|
342
|
+
}, [initialData, activeSteps, persistenceAdapter, trackEvent]);
|
|
343
|
+
const stateValue = (0, import_react.useMemo)(
|
|
344
|
+
() => ({
|
|
345
|
+
...snapshot,
|
|
346
|
+
config: localConfig
|
|
347
|
+
}),
|
|
348
|
+
[snapshot, localConfig]
|
|
349
|
+
);
|
|
350
|
+
const actionsValue = (0, import_react.useMemo)(
|
|
351
|
+
() => ({
|
|
352
|
+
goToNextStep,
|
|
353
|
+
goToPrevStep,
|
|
354
|
+
goToStep: (sid, optionsOrUndefined, thirdArg) => {
|
|
355
|
+
let finalOptions = optionsOrUndefined;
|
|
356
|
+
if (thirdArg && optionsOrUndefined === void 0) {
|
|
357
|
+
finalOptions = thirdArg;
|
|
358
|
+
}
|
|
359
|
+
return goToStep(sid, void 0, finalOptions);
|
|
360
|
+
},
|
|
361
|
+
setStepData: (_stepId, data2) => {
|
|
362
|
+
const next = { ...storeRef.current.getSnapshot().data, ...data2 };
|
|
363
|
+
storeRef.current.update(next, Object.keys(data2));
|
|
364
|
+
},
|
|
365
|
+
handleStepChange: (f, v) => {
|
|
366
|
+
if (stateRef.current.currentStepId) setData(f, v);
|
|
367
|
+
},
|
|
368
|
+
validateStep: (sid) => validateStep(sid),
|
|
369
|
+
validateAll: async () => {
|
|
370
|
+
storeRef.current.updateMeta({ isBusy: true });
|
|
371
|
+
const data2 = storeRef.current.getSnapshot().data;
|
|
372
|
+
const active = await resolveActiveStepsHelper(data2);
|
|
373
|
+
const results = await Promise.all(
|
|
374
|
+
active.map((s) => validateStep(s.id))
|
|
375
|
+
);
|
|
376
|
+
storeRef.current.updateMeta({ isBusy: false });
|
|
377
|
+
return {
|
|
378
|
+
isValid: results.every(Boolean),
|
|
379
|
+
errors: storeRef.current.getSnapshot().errors
|
|
380
|
+
};
|
|
381
|
+
},
|
|
382
|
+
save: (ids) => {
|
|
383
|
+
if (ids === true) {
|
|
384
|
+
localConfig.steps.forEach(
|
|
385
|
+
(s) => storeRef.current.save(s.id)
|
|
386
|
+
);
|
|
387
|
+
} else if (!ids) {
|
|
388
|
+
storeRef.current.save();
|
|
389
|
+
} else {
|
|
390
|
+
(Array.isArray(ids) ? ids : [ids]).forEach((id) => storeRef.current.save(id));
|
|
391
|
+
}
|
|
392
|
+
},
|
|
393
|
+
clearStorage: () => persistenceAdapter.clear(),
|
|
394
|
+
reset,
|
|
395
|
+
setData,
|
|
396
|
+
updateData,
|
|
397
|
+
getData: (p, d) => (0, import_core.getByPath)(storeRef.current.getSnapshot().data, p, d),
|
|
398
|
+
updateConfig: (nc) => {
|
|
399
|
+
setLocalConfig((prev) => ({ ...prev, ...nc }));
|
|
400
|
+
}
|
|
401
|
+
}),
|
|
402
|
+
[
|
|
403
|
+
goToNextStep,
|
|
404
|
+
goToPrevStep,
|
|
405
|
+
goToStep,
|
|
406
|
+
validateStep,
|
|
407
|
+
reset,
|
|
408
|
+
setData,
|
|
409
|
+
updateData,
|
|
410
|
+
persistenceAdapter,
|
|
411
|
+
localConfig,
|
|
412
|
+
resolveActiveStepsHelper
|
|
413
|
+
]
|
|
414
|
+
);
|
|
415
|
+
(0, import_react.useEffect)(() => {
|
|
416
|
+
if (!isInitialized.current) {
|
|
417
|
+
storeRef.current.injectPersistence(persistenceAdapter);
|
|
418
|
+
storeRef.current.dispatch({
|
|
419
|
+
type: "INIT",
|
|
420
|
+
payload: { data: initialData || {}, config: localConfig }
|
|
421
|
+
});
|
|
422
|
+
storeRef.current.hydrate();
|
|
423
|
+
isInitialized.current = true;
|
|
424
|
+
} else {
|
|
425
|
+
storeRef.current.updateMeta({ config: localConfig });
|
|
426
|
+
}
|
|
427
|
+
}, [initialData, localConfig, persistenceAdapter]);
|
|
428
|
+
(0, import_react.useEffect)(() => {
|
|
429
|
+
let isMounted = true;
|
|
430
|
+
const timeoutId = setTimeout(async () => {
|
|
431
|
+
const resolved = await resolveActiveStepsHelper(data);
|
|
432
|
+
if (isMounted) {
|
|
433
|
+
storeRef.current.dispatch({
|
|
434
|
+
type: "SET_ACTIVE_STEPS",
|
|
435
|
+
payload: { steps: resolved }
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
}, 200);
|
|
439
|
+
return () => {
|
|
440
|
+
isMounted = false;
|
|
441
|
+
clearTimeout(timeoutId);
|
|
442
|
+
};
|
|
443
|
+
}, [data, resolveActiveStepsHelper]);
|
|
444
|
+
const hasHydratedRef = (0, import_react.useRef)(false);
|
|
445
|
+
(0, import_react.useEffect)(() => {
|
|
446
|
+
if (hasHydratedRef.current) return;
|
|
447
|
+
hasHydratedRef.current = true;
|
|
448
|
+
const meta = persistenceAdapter.getStep(META_KEY);
|
|
449
|
+
if (meta) {
|
|
450
|
+
if (meta.currentStepId) {
|
|
451
|
+
storeRef.current.dispatch({
|
|
452
|
+
type: "SET_CURRENT_STEP_ID",
|
|
453
|
+
payload: { stepId: meta.currentStepId }
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
if (meta.visited)
|
|
457
|
+
storeRef.current.dispatch({
|
|
458
|
+
type: "SET_VISITED_STEPS",
|
|
459
|
+
payload: { steps: new Set(meta.visited) }
|
|
460
|
+
});
|
|
461
|
+
if (meta.completed)
|
|
462
|
+
storeRef.current.dispatch({
|
|
463
|
+
type: "SET_COMPLETED_STEPS",
|
|
464
|
+
payload: { steps: new Set(meta.completed) }
|
|
465
|
+
});
|
|
466
|
+
if (meta.history) {
|
|
467
|
+
storeRef.current.dispatch({
|
|
468
|
+
type: "SET_HISTORY",
|
|
469
|
+
payload: { history: meta.history }
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
const currentSnapshot = storeRef.current.getSnapshot();
|
|
474
|
+
const currentActiveSteps = currentSnapshot.activeSteps;
|
|
475
|
+
if (!currentSnapshot.currentStepId && currentActiveSteps.length > 0) {
|
|
476
|
+
const startId = initialStepId && currentActiveSteps.some((s) => s.id === initialStepId) ? initialStepId : currentActiveSteps[0].id;
|
|
477
|
+
storeRef.current.dispatch({
|
|
478
|
+
type: "SET_CURRENT_STEP_ID",
|
|
479
|
+
payload: { stepId: startId }
|
|
480
|
+
});
|
|
481
|
+
if (currentSnapshot.history.length === 0) {
|
|
482
|
+
storeRef.current.dispatch({
|
|
483
|
+
type: "SET_HISTORY",
|
|
484
|
+
payload: { history: [startId] }
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
const currentVisited = new Set(currentSnapshot.visitedSteps);
|
|
488
|
+
if (!currentVisited.has(startId)) {
|
|
489
|
+
currentVisited.add(startId);
|
|
490
|
+
storeRef.current.dispatch({
|
|
491
|
+
type: "SET_VISITED_STEPS",
|
|
492
|
+
payload: { steps: currentVisited }
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
if (currentActiveSteps.length > 0 && currentSnapshot.isLoading) {
|
|
497
|
+
storeRef.current.updateMeta({ isLoading: false });
|
|
498
|
+
}
|
|
499
|
+
}, [activeSteps, initialStepId, persistenceAdapter]);
|
|
500
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(WizardStoreContext.Provider, { value: storeRef.current, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(WizardStateContext.Provider, { value: stateValue, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(WizardActionsContext.Provider, { value: actionsValue, children }) }) });
|
|
501
|
+
}
|
|
502
|
+
function useWizardState() {
|
|
503
|
+
const context = (0, import_react.useContext)(WizardStateContext);
|
|
504
|
+
if (!context) throw new Error("useWizardState must be used within a WizardProvider");
|
|
505
|
+
return context;
|
|
506
|
+
}
|
|
507
|
+
function useWizardValue(path, options) {
|
|
508
|
+
const store = (0, import_react.useContext)(WizardStoreContext);
|
|
509
|
+
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);
|
|
512
|
+
const getSnapshot = (0, import_react.useCallback)(() => {
|
|
513
|
+
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)) {
|
|
517
|
+
lastStateRef.current = data;
|
|
518
|
+
return lastValueRef.current;
|
|
519
|
+
}
|
|
520
|
+
lastStateRef.current = data;
|
|
521
|
+
lastValueRef.current = value;
|
|
522
|
+
return value;
|
|
523
|
+
}, [store, path, options?.isEqual]);
|
|
524
|
+
return (0, import_react.useSyncExternalStore)(store.subscribe, getSnapshot);
|
|
525
|
+
}
|
|
526
|
+
function useWizardError(path) {
|
|
527
|
+
const store = (0, import_react.useContext)(WizardStoreContext);
|
|
528
|
+
if (!store) throw new Error("useWizardError must be used within a WizardProvider");
|
|
529
|
+
const getSnapshot = (0, import_react.useCallback)(() => {
|
|
530
|
+
const errors = store.getSnapshot().errors;
|
|
531
|
+
for (const [_, stepErrors] of Object.entries(errors)) {
|
|
532
|
+
const typed = stepErrors;
|
|
533
|
+
if (typed[path]) return typed[path];
|
|
534
|
+
}
|
|
535
|
+
return void 0;
|
|
536
|
+
}, [store, path]);
|
|
537
|
+
return (0, import_react.useSyncExternalStore)(store.subscribe, getSnapshot);
|
|
538
|
+
}
|
|
539
|
+
function useWizardSelector(selector, options) {
|
|
540
|
+
const store = (0, import_react.useContext)(WizardStoreContext);
|
|
541
|
+
if (!store) throw new Error("useWizardSelector must be used within a WizardProvider");
|
|
542
|
+
const lastResultRef = (0, import_react.useRef)(null);
|
|
543
|
+
const getSnapshot = (0, import_react.useCallback)(() => {
|
|
544
|
+
const full = store.getSnapshot();
|
|
545
|
+
const res = selector(full);
|
|
546
|
+
if (lastResultRef.current !== null && (options?.isEqual || Object.is)(lastResultRef.current, res)) {
|
|
547
|
+
return lastResultRef.current;
|
|
548
|
+
}
|
|
549
|
+
lastResultRef.current = res;
|
|
550
|
+
return res;
|
|
551
|
+
}, [store, selector, options?.isEqual]);
|
|
552
|
+
return (0, import_react.useSyncExternalStore)(store.subscribe, getSnapshot);
|
|
553
|
+
}
|
|
554
|
+
function useWizardActions() {
|
|
555
|
+
const context = (0, import_react.useContext)(WizardActionsContext);
|
|
556
|
+
if (!context) throw new Error("useWizardActions must be used within a WizardProvider");
|
|
557
|
+
return context;
|
|
558
|
+
}
|
|
559
|
+
function useWizardContext() {
|
|
560
|
+
const state = useWizardState();
|
|
561
|
+
const actions = useWizardActions();
|
|
562
|
+
const store = (0, import_react.useContext)(WizardStoreContext);
|
|
563
|
+
const data = useWizardSelector((s) => s.data);
|
|
564
|
+
const allErrors = useWizardSelector((s) => s.errors);
|
|
565
|
+
const errors = (0, import_react.useMemo)(() => {
|
|
566
|
+
const flat = {};
|
|
567
|
+
Object.values(allErrors).forEach((stepErrors) => {
|
|
568
|
+
Object.assign(flat, stepErrors);
|
|
569
|
+
});
|
|
570
|
+
return flat;
|
|
571
|
+
}, [allErrors]);
|
|
572
|
+
const { data: _d, errors: _e, ...stateProps } = state;
|
|
573
|
+
return (0, import_react.useMemo)(
|
|
574
|
+
() => ({
|
|
575
|
+
...stateProps,
|
|
576
|
+
...actions,
|
|
577
|
+
data,
|
|
578
|
+
allErrors,
|
|
579
|
+
errors,
|
|
580
|
+
store
|
|
581
|
+
}),
|
|
582
|
+
[stateProps, actions, data, allErrors, errors, store]
|
|
583
|
+
);
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
// src/hooks/useWizard.ts
|
|
587
|
+
var useWizard = () => {
|
|
588
|
+
return useWizardContext();
|
|
589
|
+
};
|
|
590
|
+
|
|
591
|
+
// src/factory.tsx
|
|
592
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
593
|
+
function createWizardFactory() {
|
|
594
|
+
const WizardProvider2 = ({
|
|
595
|
+
config,
|
|
596
|
+
initialData,
|
|
597
|
+
children
|
|
598
|
+
}) => {
|
|
599
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(WizardProvider, { config, initialData, children });
|
|
600
|
+
};
|
|
601
|
+
const useWizard2 = () => {
|
|
602
|
+
return useWizard();
|
|
603
|
+
};
|
|
604
|
+
const useWizardContext2 = () => {
|
|
605
|
+
return useWizardContext();
|
|
606
|
+
};
|
|
607
|
+
const useWizardValue2 = (path, options) => {
|
|
608
|
+
return useWizardValue(path, options);
|
|
609
|
+
};
|
|
610
|
+
const useWizardSelector2 = (selector, options) => {
|
|
611
|
+
return useWizardSelector(selector, options);
|
|
612
|
+
};
|
|
613
|
+
const useWizardError2 = (path) => {
|
|
614
|
+
return useWizardError(path);
|
|
615
|
+
};
|
|
616
|
+
const useWizardActions2 = () => {
|
|
617
|
+
return useWizardActions();
|
|
618
|
+
};
|
|
619
|
+
const useWizardState2 = () => {
|
|
620
|
+
return useWizardState();
|
|
621
|
+
};
|
|
622
|
+
const useBreadcrumbs = () => {
|
|
623
|
+
return useWizardState().breadcrumbs;
|
|
624
|
+
};
|
|
625
|
+
const createStep = (config) => config;
|
|
626
|
+
return {
|
|
627
|
+
WizardProvider: WizardProvider2,
|
|
628
|
+
useWizard: useWizard2,
|
|
629
|
+
useWizardContext: useWizardContext2,
|
|
630
|
+
useWizardValue: useWizardValue2,
|
|
631
|
+
useWizardSelector: useWizardSelector2,
|
|
632
|
+
useWizardError: useWizardError2,
|
|
633
|
+
useWizardActions: useWizardActions2,
|
|
634
|
+
useWizardState: useWizardState2,
|
|
635
|
+
useBreadcrumbs,
|
|
636
|
+
createStep
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
// src/components/WizardStepRenderer.tsx
|
|
641
|
+
var import_react2 = require("react");
|
|
642
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
643
|
+
var WizardStepRenderer = ({
|
|
644
|
+
wrapper: Wrapper,
|
|
645
|
+
fallback = null
|
|
646
|
+
}) => {
|
|
647
|
+
const { currentStep } = useWizardContext();
|
|
648
|
+
const StepComponent = (0, import_react2.useMemo)(() => {
|
|
649
|
+
if (!currentStep?.component) return null;
|
|
650
|
+
return currentStep.component;
|
|
651
|
+
}, [currentStep]);
|
|
652
|
+
if (!currentStep || !StepComponent) {
|
|
653
|
+
return null;
|
|
654
|
+
}
|
|
655
|
+
const content = /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react2.Suspense, { fallback, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(StepComponent, {}) });
|
|
656
|
+
if (Wrapper) {
|
|
657
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Wrapper, { children: content }, currentStep.id);
|
|
658
|
+
}
|
|
659
|
+
return content;
|
|
660
|
+
};
|
|
661
|
+
|
|
662
|
+
// src/index.ts
|
|
663
|
+
var import_core2 = require("@wizzard-packages/core");
|
|
664
|
+
var import_middleware = require("@wizzard-packages/middleware");
|
|
665
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
666
|
+
0 && (module.exports = {
|
|
667
|
+
WizardProvider,
|
|
668
|
+
WizardStepRenderer,
|
|
669
|
+
WizardStore,
|
|
670
|
+
createWizardFactory,
|
|
671
|
+
loggerMiddleware,
|
|
672
|
+
useWizard,
|
|
673
|
+
useWizardActions,
|
|
674
|
+
useWizardContext,
|
|
675
|
+
useWizardError,
|
|
676
|
+
useWizardSelector,
|
|
677
|
+
useWizardState,
|
|
678
|
+
useWizardValue
|
|
679
|
+
});
|
|
680
|
+
//# sourceMappingURL=index.cjs.map
|