@pisell/materials 6.12.39 → 6.12.41

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.
Files changed (37) hide show
  1. package/build/lowcode/assets-daily.json +11 -11
  2. package/build/lowcode/assets-dev.json +2 -2
  3. package/build/lowcode/assets-prod.json +11 -11
  4. package/build/lowcode/meta.js +1 -1
  5. package/build/lowcode/render/default/view.js +32 -32
  6. package/build/lowcode/view.js +32 -32
  7. package/es/components/PisellSelectionFlow/PisellSelectionFlow.d.ts +7 -0
  8. package/es/components/PisellSelectionFlow/PisellSelectionFlow.js +392 -0
  9. package/es/components/PisellSelectionFlow/compiler.d.ts +12 -0
  10. package/es/components/PisellSelectionFlow/compiler.js +174 -0
  11. package/es/components/PisellSelectionFlow/context.d.ts +9 -0
  12. package/es/components/PisellSelectionFlow/context.js +12 -0
  13. package/es/components/PisellSelectionFlow/hooks/useFlowDraft.js +35 -0
  14. package/es/components/PisellSelectionFlow/hooks/useFlowModuleLifecycle.js +236 -0
  15. package/es/components/PisellSelectionFlow/hooks/useFlowNavigation.js +320 -0
  16. package/es/components/PisellSelectionFlow/index.d.ts +4 -0
  17. package/es/components/PisellSelectionFlow/types.d.ts +179 -0
  18. package/es/components/PisellSelectionFlow/types.js +10 -0
  19. package/es/components/PisellSelectionFlow/utils.js +15 -0
  20. package/es/index.d.ts +13 -9
  21. package/es/index.js +5 -1
  22. package/lib/components/PisellSelectionFlow/PisellSelectionFlow.d.ts +7 -0
  23. package/lib/components/PisellSelectionFlow/PisellSelectionFlow.js +394 -0
  24. package/lib/components/PisellSelectionFlow/compiler.d.ts +12 -0
  25. package/lib/components/PisellSelectionFlow/compiler.js +178 -0
  26. package/lib/components/PisellSelectionFlow/context.d.ts +9 -0
  27. package/lib/components/PisellSelectionFlow/context.js +16 -0
  28. package/lib/components/PisellSelectionFlow/hooks/useFlowDraft.js +36 -0
  29. package/lib/components/PisellSelectionFlow/hooks/useFlowModuleLifecycle.js +237 -0
  30. package/lib/components/PisellSelectionFlow/hooks/useFlowNavigation.js +321 -0
  31. package/lib/components/PisellSelectionFlow/index.d.ts +4 -0
  32. package/lib/components/PisellSelectionFlow/types.d.ts +179 -0
  33. package/lib/components/PisellSelectionFlow/types.js +10 -0
  34. package/lib/components/PisellSelectionFlow/utils.js +18 -0
  35. package/lib/index.d.ts +13 -9
  36. package/lib/index.js +15 -2
  37. package/package.json +1 -1
@@ -0,0 +1,236 @@
1
+ import { _objectSpread2 } from "../../../_virtual/_@oxc-project_runtime@0.122.0/helpers/objectSpread2.js";
2
+ import { _asyncToGenerator } from "../../../_virtual/_@oxc-project_runtime@0.122.0/helpers/asyncToGenerator.js";
3
+ import { hasSelectionDraftFieldValue, resolveFlowModuleAdapter } from "../compiler.js";
4
+ import { getSelectionFlowErrorMessage } from "../utils.js";
5
+ import { useCallback, useEffect } from "react";
6
+ //#region src/components/PisellSelectionFlow/hooks/useFlowModuleLifecycle.ts
7
+ /** 负责依赖失效、清理、校正、刷新和异步 latest-wins。 */
8
+ const useFlowModuleLifecycle = ({ registry, draftAdapter, createRuntimeIssue, mountedRef, flowGenerationRef, draftRevisionRef, draftRef, moduleRevisionRef, moduleInitializationRef, moduleDependencyLifecycleRef, pendingModuleChangeRef, compiledStepsRef, moduleStateRef, processDraftChangeRef, commitModuleState, getFreshContext, currentStep, configurationError, compiledSteps, resolvedCurrentStepIndex, draft, moduleState }) => {
9
+ processDraftChangeRef.current = useCallback((change) => {
10
+ const changedFields = new Set(change.changedFields);
11
+ const flowGeneration = flowGenerationRef.current;
12
+ if (!mountedRef.current) return;
13
+ for (const step of compiledStepsRef.current) for (const module of step.modules) {
14
+ if (module.key === change.sourceModuleKey) continue;
15
+ const adapter = resolveFlowModuleAdapter(registry, module.type);
16
+ if (!adapter) continue;
17
+ const dependencyChanged = [...new Set([...adapter.refreshOn || [], ...adapter.hardRequires || []])].some((field) => changedFields.has(field));
18
+ let shouldRefresh = dependencyChanged;
19
+ if (dependencyChanged && adapter.shouldRefresh) try {
20
+ const refreshContext = getFreshContext();
21
+ shouldRefresh = Boolean(refreshContext && adapter.shouldRefresh(refreshContext, change, module));
22
+ } catch (error) {
23
+ const revision = (moduleRevisionRef.current.get(module.key) || 0) + 1;
24
+ moduleRevisionRef.current.set(module.key, revision);
25
+ moduleInitializationRef.current.delete(module.key);
26
+ moduleDependencyLifecycleRef.current.delete(module.key);
27
+ commitModuleState(module.key, {
28
+ status: "error",
29
+ message: getSelectionFlowErrorMessage(error),
30
+ error
31
+ });
32
+ continue;
33
+ }
34
+ if (!shouldRefresh) continue;
35
+ const previousPendingChange = pendingModuleChangeRef.current.get(module.key);
36
+ const lifecycleChange = previousPendingChange ? _objectSpread2(_objectSpread2({}, change), {}, {
37
+ previousDraft: previousPendingChange.previousDraft,
38
+ changedFields: Array.from(new Set([...previousPendingChange.changedFields, ...change.changedFields]))
39
+ }) : change;
40
+ pendingModuleChangeRef.current.set(module.key, lifecycleChange);
41
+ const revision = (moduleRevisionRef.current.get(module.key) || 0) + 1;
42
+ moduleRevisionRef.current.set(module.key, revision);
43
+ commitModuleState(module.key, {
44
+ status: "loading",
45
+ reason: createRuntimeIssue("dependencies-reconciling")
46
+ });
47
+ let dependencyLifecycle;
48
+ const runDependencyLifecycle = () => Promise.resolve().then(_asyncToGenerator(function* () {
49
+ var _adapter$clearDepende, _adapter$reconcile;
50
+ const buildLifecycleContext = () => {
51
+ const freshContext = getFreshContext();
52
+ const isCurrentLifecycle = () => mountedRef.current && flowGenerationRef.current === flowGeneration && moduleRevisionRef.current.get(module.key) === revision;
53
+ if (!freshContext || !isCurrentLifecycle()) return null;
54
+ return _objectSpread2(_objectSpread2({}, freshContext), {}, {
55
+ updateDraft: (update, meta) => {
56
+ if (isCurrentLifecycle()) freshContext.updateDraft(update, meta);
57
+ },
58
+ setModuleState: (moduleKey, state) => {
59
+ if (isCurrentLifecycle()) freshContext.setModuleState(moduleKey, state);
60
+ },
61
+ setModuleStatus: (moduleKey, status, message, error) => {
62
+ if (isCurrentLifecycle()) freshContext.setModuleStatus(moduleKey, status, message, error);
63
+ },
64
+ setModuleData: (moduleKey, value) => {
65
+ if (isCurrentLifecycle()) freshContext.setModuleData(moduleKey, value);
66
+ },
67
+ clearModuleData: (moduleKey) => {
68
+ if (isCurrentLifecycle()) freshContext.clearModuleData(moduleKey);
69
+ }
70
+ });
71
+ };
72
+ const clearContext = buildLifecycleContext();
73
+ if (!clearContext) return false;
74
+ yield (_adapter$clearDepende = adapter.clearDependencies) === null || _adapter$clearDepende === void 0 ? void 0 : _adapter$clearDepende.call(adapter, clearContext, lifecycleChange, module);
75
+ const reconcileContext = buildLifecycleContext();
76
+ if (!reconcileContext) return false;
77
+ yield (_adapter$reconcile = adapter.reconcile) === null || _adapter$reconcile === void 0 ? void 0 : _adapter$reconcile.call(adapter, reconcileContext, lifecycleChange, module);
78
+ if (mountedRef.current && flowGenerationRef.current === flowGeneration && moduleRevisionRef.current.get(module.key) === revision) commitModuleState(module.key, { status: "stale" });
79
+ return true;
80
+ })).catch((error) => {
81
+ if (mountedRef.current && flowGenerationRef.current === flowGeneration && moduleRevisionRef.current.get(module.key) === revision) commitModuleState(module.key, {
82
+ status: "error",
83
+ message: getSelectionFlowErrorMessage(error),
84
+ error
85
+ });
86
+ return false;
87
+ });
88
+ const setLifecyclePromise = () => {
89
+ dependencyLifecycle.status = "pending";
90
+ const promise = runDependencyLifecycle();
91
+ dependencyLifecycle.promise = promise;
92
+ promise.then((success) => {
93
+ if (moduleDependencyLifecycleRef.current.get(module.key) !== dependencyLifecycle) return;
94
+ if (success) {
95
+ moduleDependencyLifecycleRef.current.delete(module.key);
96
+ if (pendingModuleChangeRef.current.get(module.key) === lifecycleChange) pendingModuleChangeRef.current.delete(module.key);
97
+ } else dependencyLifecycle.status = "failed";
98
+ });
99
+ return promise;
100
+ };
101
+ dependencyLifecycle = {
102
+ revision,
103
+ status: "pending",
104
+ promise: Promise.resolve(false),
105
+ retry: setLifecyclePromise
106
+ };
107
+ moduleDependencyLifecycleRef.current.set(module.key, dependencyLifecycle);
108
+ setLifecyclePromise();
109
+ }
110
+ }, [
111
+ commitModuleState,
112
+ createRuntimeIssue,
113
+ getFreshContext,
114
+ registry
115
+ ]);
116
+ const ensureModuleReady = useCallback((module) => {
117
+ if (!mountedRef.current) return Promise.resolve(false);
118
+ const revision = moduleRevisionRef.current.get(module.key) || 0;
119
+ const flowGeneration = flowGenerationRef.current;
120
+ const existing = moduleInitializationRef.current.get(module.key);
121
+ if ((existing === null || existing === void 0 ? void 0 : existing.revision) === revision) return existing.promise;
122
+ const currentState = moduleStateRef.current[module.key];
123
+ const pendingDependencyLifecycle = moduleDependencyLifecycleRef.current.get(module.key);
124
+ if ((currentState === null || currentState === void 0 ? void 0 : currentState.status) === "ready" && (pendingDependencyLifecycle === null || pendingDependencyLifecycle === void 0 ? void 0 : pendingDependencyLifecycle.revision) !== revision) return Promise.resolve(true);
125
+ const isCurrentRun = () => mountedRef.current && flowGenerationRef.current === flowGeneration && (moduleRevisionRef.current.get(module.key) || 0) === revision;
126
+ const getRunContext = () => {
127
+ const freshContext = getFreshContext();
128
+ if (!freshContext || !isCurrentRun()) return null;
129
+ return _objectSpread2(_objectSpread2({}, freshContext), {}, {
130
+ updateDraft: (update, meta) => {
131
+ if (isCurrentRun()) freshContext.updateDraft(update, meta);
132
+ },
133
+ setModuleState: (moduleKey, state) => {
134
+ if (isCurrentRun()) freshContext.setModuleState(moduleKey, state);
135
+ },
136
+ setModuleStatus: (moduleKey, status, message, error) => {
137
+ if (isCurrentRun()) freshContext.setModuleStatus(moduleKey, status, message, error);
138
+ },
139
+ setModuleData: (moduleKey, value) => {
140
+ if (isCurrentRun()) freshContext.setModuleData(moduleKey, value);
141
+ },
142
+ clearModuleData: (moduleKey) => {
143
+ if (isCurrentRun()) freshContext.clearModuleData(moduleKey);
144
+ }
145
+ });
146
+ };
147
+ const run = _asyncToGenerator(function* () {
148
+ var _adapter$hardRequires;
149
+ const adapter = resolveFlowModuleAdapter(registry, module.type);
150
+ if (!adapter) return false;
151
+ const dependencyLifecycle = moduleDependencyLifecycleRef.current.get(module.key);
152
+ if ((dependencyLifecycle === null || dependencyLifecycle === void 0 ? void 0 : dependencyLifecycle.revision) === revision) {
153
+ if (!(dependencyLifecycle.status === "failed" ? yield dependencyLifecycle.retry() : yield dependencyLifecycle.promise) || !isCurrentRun()) return false;
154
+ }
155
+ let context = getRunContext();
156
+ if (!context) return false;
157
+ const missingField = (_adapter$hardRequires = adapter.hardRequires) === null || _adapter$hardRequires === void 0 ? void 0 : _adapter$hardRequires.find((field) => !hasSelectionDraftFieldValue(draftAdapter, draftRef.current, field));
158
+ if (missingField) {
159
+ if (isCurrentRun()) commitModuleState(module.key, {
160
+ status: "stale",
161
+ reason: createRuntimeIssue("waiting-field", { field: missingField })
162
+ });
163
+ return false;
164
+ }
165
+ try {
166
+ var _await$adapter$canIni, _adapter$canInitializ, _moduleStateRef$curre2;
167
+ const canInitialize = (_await$adapter$canIni = yield (_adapter$canInitializ = adapter.canInitialize) === null || _adapter$canInitializ === void 0 ? void 0 : _adapter$canInitializ.call(adapter, context, module)) !== null && _await$adapter$canIni !== void 0 ? _await$adapter$canIni : true;
168
+ if (!isCurrentRun()) return false;
169
+ if (!canInitialize) {
170
+ commitModuleState(module.key, {
171
+ status: "stale",
172
+ reason: createRuntimeIssue("prerequisites-not-ready")
173
+ });
174
+ return false;
175
+ }
176
+ do {
177
+ var _adapter$refresh, _moduleStateRef$curre;
178
+ commitModuleState(module.key, { status: "loading" });
179
+ context = getRunContext();
180
+ if (!context || !isCurrentRun()) return false;
181
+ yield (_adapter$refresh = adapter.refresh) === null || _adapter$refresh === void 0 ? void 0 : _adapter$refresh.call(adapter, context, module);
182
+ if (!isCurrentRun()) return false;
183
+ if (((_moduleStateRef$curre = moduleStateRef.current[module.key]) === null || _moduleStateRef$curre === void 0 ? void 0 : _moduleStateRef$curre.status) === "error") return false;
184
+ } while (((_moduleStateRef$curre2 = moduleStateRef.current[module.key]) === null || _moduleStateRef$curre2 === void 0 ? void 0 : _moduleStateRef$curre2.status) === "stale");
185
+ commitModuleState(module.key, { status: "ready" });
186
+ return true;
187
+ } catch (error) {
188
+ if (isCurrentRun()) commitModuleState(module.key, {
189
+ status: "error",
190
+ message: getSelectionFlowErrorMessage(error),
191
+ error
192
+ });
193
+ return false;
194
+ }
195
+ })();
196
+ const initialization = {
197
+ revision,
198
+ promise: run
199
+ };
200
+ moduleInitializationRef.current.set(module.key, initialization);
201
+ run.finally(() => {
202
+ if (moduleInitializationRef.current.get(module.key) === initialization) moduleInitializationRef.current.delete(module.key);
203
+ });
204
+ return run;
205
+ }, [
206
+ commitModuleState,
207
+ createRuntimeIssue,
208
+ draftAdapter,
209
+ getFreshContext,
210
+ registry
211
+ ]);
212
+ useEffect(() => {
213
+ if (!currentStep || configurationError) return;
214
+ const backgroundModules = compiledSteps.flatMap((step) => step.modules).filter((module) => {
215
+ const adapter = resolveFlowModuleAdapter(registry, module.type);
216
+ return (adapter === null || adapter === void 0 ? void 0 : adapter.initializeWhileInactive) && module.stepIndex < resolvedCurrentStepIndex;
217
+ });
218
+ for (const module of [...currentStep.modules, ...backgroundModules]) {
219
+ var _moduleStateRef$curre3;
220
+ const status = ((_moduleStateRef$curre3 = moduleStateRef.current[module.key]) === null || _moduleStateRef$curre3 === void 0 ? void 0 : _moduleStateRef$curre3.status) || "idle";
221
+ if (status === "idle" || status === "stale") ensureModuleReady(module);
222
+ }
223
+ }, [
224
+ compiledSteps,
225
+ configurationError,
226
+ currentStep,
227
+ draft,
228
+ ensureModuleReady,
229
+ moduleState,
230
+ registry,
231
+ resolvedCurrentStepIndex
232
+ ]);
233
+ return { ensureModuleReady };
234
+ };
235
+ //#endregion
236
+ export { useFlowModuleLifecycle };
@@ -0,0 +1,320 @@
1
+ import { _objectSpread2 } from "../../../_virtual/_@oxc-project_runtime@0.122.0/helpers/objectSpread2.js";
2
+ import { _asyncToGenerator } from "../../../_virtual/_@oxc-project_runtime@0.122.0/helpers/asyncToGenerator.js";
3
+ import { resolveFlowModuleAdapter } from "../compiler.js";
4
+ import { getCompiledStepsFingerprint, getSelectionFlowErrorMessage, normalizeFlowBeforeLeaveResult, normalizeFlowValidationResult } from "../utils.js";
5
+ import { useCallback } from "react";
6
+ //#region src/components/PisellSelectionFlow/hooks/useFlowNavigation.ts
7
+ /** 导航、校验与提交门禁独立于模块加载生命周期。 */
8
+ const useFlowNavigation = ({ registry, draftAdapter, createRuntimeIssue, mountedRef, moduleStateRef, moduleRevisionRef, draftRevisionRef, flowGenerationRef, moduleHandlesRef, configurationErrorRef, compiledStepsRef, currentStepIndexRef, currentStepKeyRef, validatedCompletionRef, navigationRevisionRef, transitionPendingRef, completedRef, completionPromiseRef, isCompletingRef, draftRef, onCompleteRef, ensureModuleReady, commitModuleState, getFreshContext, onValidationFailed, setCurrentStepIndex, setCompletionError, setCompletionReason, setIsCompleting }) => {
9
+ const validateModule = useCallback(function() {
10
+ var _ref = _asyncToGenerator(function* (module) {
11
+ const adapter = resolveFlowModuleAdapter(registry, module.type);
12
+ if (!adapter || !mountedRef.current) return false;
13
+ const ready = yield ensureModuleReady(module);
14
+ if (!mountedRef.current || !ready) {
15
+ const state = moduleStateRef.current[module.key];
16
+ onValidationFailed === null || onValidationFailed === void 0 || onValidationFailed(module, {
17
+ message: state === null || state === void 0 ? void 0 : state.message,
18
+ reason: state === null || state === void 0 ? void 0 : state.reason
19
+ });
20
+ return false;
21
+ }
22
+ const validationRevision = moduleRevisionRef.current.get(module.key) || 0;
23
+ const validationDraftRevision = draftRevisionRef.current;
24
+ const validationGeneration = flowGenerationRef.current;
25
+ const isCurrentValidationRun = () => mountedRef.current && flowGenerationRef.current === validationGeneration && (moduleRevisionRef.current.get(module.key) || 0) === validationRevision;
26
+ const isCurrentValidation = () => isCurrentValidationRun() && draftRevisionRef.current === validationDraftRevision;
27
+ commitModuleState(module.key, { status: "loading" });
28
+ try {
29
+ var _handle$validate;
30
+ const context = getFreshContext();
31
+ if (!context) return false;
32
+ const validationContext = _objectSpread2(_objectSpread2({}, context), {}, {
33
+ updateDraft: (update, meta) => {
34
+ if (isCurrentValidation()) context.updateDraft(update, meta);
35
+ },
36
+ setModuleState: (moduleKey, state) => {
37
+ if (isCurrentValidation()) context.setModuleState(moduleKey, state);
38
+ },
39
+ setModuleStatus: (moduleKey, status, message, error) => {
40
+ if (isCurrentValidation()) context.setModuleStatus(moduleKey, status, message, error);
41
+ },
42
+ setModuleData: (moduleKey, value) => {
43
+ if (isCurrentValidation()) context.setModuleData(moduleKey, value);
44
+ },
45
+ clearModuleData: (moduleKey) => {
46
+ if (isCurrentValidation()) context.clearModuleData(moduleKey);
47
+ }
48
+ });
49
+ const handle = moduleHandlesRef.current.get(module.key) || null;
50
+ const result = normalizeFlowValidationResult(adapter.validate ? yield adapter.validate(validationContext, handle, module) : yield handle === null || handle === void 0 || (_handle$validate = handle.validate) === null || _handle$validate === void 0 ? void 0 : _handle$validate.call(handle));
51
+ if (!isCurrentValidation()) {
52
+ if (isCurrentValidationRun()) commitModuleState(module.key, {
53
+ status: "stale",
54
+ reason: createRuntimeIssue("selection-changed-validation")
55
+ });
56
+ return false;
57
+ }
58
+ if (!result.valid) {
59
+ const fallbackReason = result.message ? void 0 : createRuntimeIssue("module-validation-failed");
60
+ commitModuleState(module.key, {
61
+ status: "error",
62
+ message: result.message,
63
+ reason: fallbackReason
64
+ });
65
+ onValidationFailed === null || onValidationFailed === void 0 || onValidationFailed(module, {
66
+ message: result.message,
67
+ reason: fallbackReason
68
+ });
69
+ return false;
70
+ }
71
+ commitModuleState(module.key, { status: "ready" });
72
+ return true;
73
+ } catch (error) {
74
+ const message = getSelectionFlowErrorMessage(error);
75
+ if (isCurrentValidation()) {
76
+ commitModuleState(module.key, {
77
+ status: "error",
78
+ message,
79
+ error
80
+ });
81
+ onValidationFailed === null || onValidationFailed === void 0 || onValidationFailed(module, { message });
82
+ } else if (isCurrentValidationRun()) commitModuleState(module.key, {
83
+ status: "stale",
84
+ reason: createRuntimeIssue("selection-changed-validation")
85
+ });
86
+ return false;
87
+ }
88
+ });
89
+ return function(_x) {
90
+ return _ref.apply(this, arguments);
91
+ };
92
+ }(), [
93
+ commitModuleState,
94
+ ensureModuleReady,
95
+ createRuntimeIssue,
96
+ getFreshContext,
97
+ onValidationFailed,
98
+ registry
99
+ ]);
100
+ const validateCurrentStep = useCallback(_asyncToGenerator(function* () {
101
+ if (configurationErrorRef.current) return false;
102
+ const step = compiledStepsRef.current[currentStepIndexRef.current];
103
+ if (!step) return false;
104
+ for (const module of step.modules) if (!(yield validateModule(module))) return false;
105
+ return true;
106
+ }), [validateModule]);
107
+ const runBeforeLeaveForCurrentStep = useCallback(_asyncToGenerator(function* () {
108
+ if (configurationErrorRef.current) return false;
109
+ const stepIndex = currentStepIndexRef.current;
110
+ const step = compiledStepsRef.current[stepIndex];
111
+ if (!step) return false;
112
+ for (const module of step.modules) {
113
+ const adapter = resolveFlowModuleAdapter(registry, module.type);
114
+ const handle = moduleHandlesRef.current.get(module.key) || null;
115
+ if (!((adapter === null || adapter === void 0 ? void 0 : adapter.beforeLeave) || (handle === null || handle === void 0 ? void 0 : handle.beforeLeave))) continue;
116
+ const draftRevision = draftRevisionRef.current;
117
+ const moduleRevision = moduleRevisionRef.current.get(module.key) || 0;
118
+ try {
119
+ var _handle$beforeLeave, _compiledStepsRef$cur;
120
+ const context = getFreshContext();
121
+ if (!context) return false;
122
+ const result = normalizeFlowBeforeLeaveResult((adapter === null || adapter === void 0 ? void 0 : adapter.beforeLeave) ? yield adapter.beforeLeave(context, handle, module) : yield handle === null || handle === void 0 || (_handle$beforeLeave = handle.beforeLeave) === null || _handle$beforeLeave === void 0 ? void 0 : _handle$beforeLeave.call(handle));
123
+ if (!mountedRef.current || currentStepIndexRef.current !== stepIndex || ((_compiledStepsRef$cur = compiledStepsRef.current[stepIndex]) === null || _compiledStepsRef$cur === void 0 ? void 0 : _compiledStepsRef$cur.key) !== step.key || draftRevisionRef.current !== draftRevision || (moduleRevisionRef.current.get(module.key) || 0) !== moduleRevision) {
124
+ commitModuleState(module.key, {
125
+ status: "stale",
126
+ reason: createRuntimeIssue("selection-changed-confirmation")
127
+ });
128
+ onValidationFailed === null || onValidationFailed === void 0 || onValidationFailed(module, { reason: createRuntimeIssue("selection-changed-confirmation") });
129
+ return false;
130
+ }
131
+ if (!result.allowed) {
132
+ if (result.message) {
133
+ commitModuleState(module.key, {
134
+ status: "error",
135
+ message: result.message
136
+ });
137
+ onValidationFailed === null || onValidationFailed === void 0 || onValidationFailed(module, { message: result.message });
138
+ }
139
+ return false;
140
+ }
141
+ } catch (error) {
142
+ const message = getSelectionFlowErrorMessage(error);
143
+ commitModuleState(module.key, {
144
+ status: "error",
145
+ message,
146
+ error
147
+ });
148
+ onValidationFailed === null || onValidationFailed === void 0 || onValidationFailed(module, { message });
149
+ return false;
150
+ }
151
+ }
152
+ return true;
153
+ }), [
154
+ commitModuleState,
155
+ createRuntimeIssue,
156
+ getFreshContext,
157
+ onValidationFailed,
158
+ registry
159
+ ]);
160
+ const validateFlowForCompletion = useCallback(_asyncToGenerator(function* () {
161
+ validatedCompletionRef.current = null;
162
+ if (configurationErrorRef.current) return false;
163
+ const currentIndex = currentStepIndexRef.current;
164
+ const allSteps = compiledStepsRef.current;
165
+ const compiledFingerprint = getCompiledStepsFingerprint(allSteps);
166
+ const revisionFingerprint = allSteps.flatMap((step) => step.modules).map((module) => `${module.key}:${moduleRevisionRef.current.get(module.key) || 0}`).join("|");
167
+ const draftRevision = draftRevisionRef.current;
168
+ for (const step of allSteps) {
169
+ if (step.index >= currentIndex) break;
170
+ for (const module of step.modules) {
171
+ const state = moduleStateRef.current[module.key];
172
+ if ((state === null || state === void 0 ? void 0 : state.status) !== "ready") {
173
+ currentStepIndexRef.current = step.index;
174
+ currentStepKeyRef.current = step.key;
175
+ setCurrentStepIndex(step.index);
176
+ onValidationFailed === null || onValidationFailed === void 0 || onValidationFailed(module, {
177
+ message: state === null || state === void 0 ? void 0 : state.message,
178
+ reason: (state === null || state === void 0 ? void 0 : state.reason) || createRuntimeIssue("previous-step-review")
179
+ });
180
+ return false;
181
+ }
182
+ }
183
+ }
184
+ if (!(yield validateCurrentStep())) return false;
185
+ if (configurationErrorRef.current) return false;
186
+ const latestSteps = compiledStepsRef.current;
187
+ const latestCompiledFingerprint = getCompiledStepsFingerprint(latestSteps);
188
+ const latestRevisionFingerprint = latestSteps.flatMap((step) => step.modules).map((module) => `${module.key}:${moduleRevisionRef.current.get(module.key) || 0}`).join("|");
189
+ if (compiledFingerprint !== latestCompiledFingerprint || revisionFingerprint !== latestRevisionFingerprint || draftRevision !== draftRevisionRef.current) {
190
+ const targetStep = latestSteps.find((step) => step.modules.some((module) => {
191
+ var _moduleStateRef$curre;
192
+ return ((_moduleStateRef$curre = moduleStateRef.current[module.key]) === null || _moduleStateRef$curre === void 0 ? void 0 : _moduleStateRef$curre.status) !== "ready";
193
+ })) || latestSteps[0];
194
+ const targetModule = targetStep === null || targetStep === void 0 ? void 0 : targetStep.modules[0];
195
+ if (targetStep && targetModule) {
196
+ currentStepIndexRef.current = targetStep.index;
197
+ currentStepKeyRef.current = targetStep.key;
198
+ setCurrentStepIndex(targetStep.index);
199
+ onValidationFailed === null || onValidationFailed === void 0 || onValidationFailed(targetModule, { reason: createRuntimeIssue("changed-review") });
200
+ }
201
+ return false;
202
+ }
203
+ for (const step of latestSteps) for (const module of step.modules) {
204
+ const state = moduleStateRef.current[module.key];
205
+ if ((state === null || state === void 0 ? void 0 : state.status) === "ready") continue;
206
+ currentStepIndexRef.current = step.index;
207
+ currentStepKeyRef.current = step.key;
208
+ setCurrentStepIndex(step.index);
209
+ onValidationFailed === null || onValidationFailed === void 0 || onValidationFailed(module, {
210
+ message: state === null || state === void 0 ? void 0 : state.message,
211
+ reason: (state === null || state === void 0 ? void 0 : state.reason) || createRuntimeIssue("current-step-review")
212
+ });
213
+ return false;
214
+ }
215
+ validatedCompletionRef.current = {
216
+ draftRevision: draftRevisionRef.current,
217
+ compiledFingerprint: getCompiledStepsFingerprint(latestSteps),
218
+ moduleRevisionFingerprint: latestSteps.flatMap((step) => step.modules).map((module) => `${module.key}:${moduleRevisionRef.current.get(module.key) || 0}`).join("|")
219
+ };
220
+ return true;
221
+ }), [
222
+ createRuntimeIssue,
223
+ onValidationFailed,
224
+ validateCurrentStep
225
+ ]);
226
+ const complete = useCallback(() => {
227
+ if (!mountedRef.current) return Promise.resolve(false);
228
+ if (completedRef.current) return Promise.resolve(true);
229
+ if (completionPromiseRef.current) return completionPromiseRef.current;
230
+ if (transitionPendingRef.current) return Promise.resolve(false);
231
+ transitionPendingRef.current = true;
232
+ const navigationRevision = navigationRevisionRef.current + 1;
233
+ navigationRevisionRef.current = navigationRevision;
234
+ isCompletingRef.current = true;
235
+ setIsCompleting(true);
236
+ const run = _asyncToGenerator(function* () {
237
+ try {
238
+ setCompletionError(void 0);
239
+ setCompletionReason(void 0);
240
+ if (!(yield validateFlowForCompletion())) return false;
241
+ if (!(yield runBeforeLeaveForCurrentStep())) return false;
242
+ const validated = validatedCompletionRef.current;
243
+ const latestSteps = compiledStepsRef.current;
244
+ if (!mountedRef.current || navigationRevisionRef.current !== navigationRevision || !validated || validated.draftRevision !== draftRevisionRef.current || validated.compiledFingerprint !== getCompiledStepsFingerprint(latestSteps) || validated.moduleRevisionFingerprint !== latestSteps.flatMap((step) => step.modules).map((module) => `${module.key}:${moduleRevisionRef.current.get(module.key) || 0}`).join("|")) {
245
+ if (mountedRef.current) setCompletionReason(createRuntimeIssue("changed-confirm-again"));
246
+ return false;
247
+ }
248
+ const snapshot = draftAdapter.createSnapshot ? draftAdapter.createSnapshot(draftRef.current) : draftRef.current;
249
+ const completionResult = yield onCompleteRef.current(snapshot);
250
+ if (!mountedRef.current || navigationRevisionRef.current !== navigationRevision) return false;
251
+ if (completionResult === false) return false;
252
+ completedRef.current = true;
253
+ return true;
254
+ } catch (error) {
255
+ if (mountedRef.current) setCompletionError(getSelectionFlowErrorMessage(error));
256
+ return false;
257
+ } finally {
258
+ isCompletingRef.current = false;
259
+ transitionPendingRef.current = false;
260
+ if (mountedRef.current) setIsCompleting(false);
261
+ }
262
+ })();
263
+ completionPromiseRef.current = run;
264
+ run.finally(() => {
265
+ if (completionPromiseRef.current === run) completionPromiseRef.current = null;
266
+ });
267
+ return run;
268
+ }, [
269
+ draftAdapter,
270
+ createRuntimeIssue,
271
+ runBeforeLeaveForCurrentStep,
272
+ setCompletionReason,
273
+ validateFlowForCompletion
274
+ ]);
275
+ return {
276
+ validateCurrentStep,
277
+ runBeforeLeaveForCurrentStep,
278
+ complete,
279
+ next: useCallback(_asyncToGenerator(function* () {
280
+ if (!mountedRef.current || configurationErrorRef.current || transitionPendingRef.current) return false;
281
+ const currentIndex = currentStepIndexRef.current;
282
+ const allSteps = compiledStepsRef.current;
283
+ if (!allSteps[currentIndex]) return false;
284
+ if (currentIndex >= allSteps.length - 1) return complete();
285
+ const currentStepKey = allSteps[currentIndex].key;
286
+ const navigationRevision = navigationRevisionRef.current + 1;
287
+ navigationRevisionRef.current = navigationRevision;
288
+ transitionPendingRef.current = true;
289
+ try {
290
+ var _compiledStepsRef$cur2, _allSteps$nextIndex;
291
+ if (!(yield validateCurrentStep())) return false;
292
+ if (!(yield runBeforeLeaveForCurrentStep())) return false;
293
+ if (!mountedRef.current || navigationRevisionRef.current !== navigationRevision || currentStepIndexRef.current !== currentIndex || ((_compiledStepsRef$cur2 = compiledStepsRef.current[currentIndex]) === null || _compiledStepsRef$cur2 === void 0 ? void 0 : _compiledStepsRef$cur2.key) !== currentStepKey) return false;
294
+ const nextIndex = currentIndex + 1;
295
+ currentStepIndexRef.current = nextIndex;
296
+ currentStepKeyRef.current = (_allSteps$nextIndex = allSteps[nextIndex]) === null || _allSteps$nextIndex === void 0 ? void 0 : _allSteps$nextIndex.key;
297
+ setCurrentStepIndex(nextIndex);
298
+ return true;
299
+ } finally {
300
+ transitionPendingRef.current = false;
301
+ }
302
+ }), [
303
+ complete,
304
+ runBeforeLeaveForCurrentStep,
305
+ validateCurrentStep
306
+ ]),
307
+ back: useCallback(() => {
308
+ var _compiledStepsRef$cur3;
309
+ if (!mountedRef.current || transitionPendingRef.current || currentStepIndexRef.current <= 0) return false;
310
+ navigationRevisionRef.current += 1;
311
+ const nextIndex = currentStepIndexRef.current - 1;
312
+ currentStepIndexRef.current = nextIndex;
313
+ currentStepKeyRef.current = (_compiledStepsRef$cur3 = compiledStepsRef.current[nextIndex]) === null || _compiledStepsRef$cur3 === void 0 ? void 0 : _compiledStepsRef$cur3.key;
314
+ setCurrentStepIndex(nextIndex);
315
+ return true;
316
+ }, [])
317
+ };
318
+ };
319
+ //#endregion
320
+ export { useFlowNavigation };
@@ -0,0 +1,4 @@
1
+ import { CompiledSelectionFlowModuleConfig, CompiledSelectionFlowStep, FlowModuleBeforeLeaveResult, FlowModuleBeforeLeaveReturn, FlowModuleDataMap, FlowModuleHandle, FlowModuleState, FlowModuleStateMap, FlowModuleStatus, FlowModuleValidationResult, FlowModuleValidationReturn, PisellSelectionFlowController, PisellSelectionFlowProps, SelectionFlowCompileError, SelectionFlowCompileIssue, SelectionFlowCompileIssueCode, SelectionFlowContextValue, SelectionFlowDraftAdapter, SelectionFlowDraftChange, SelectionFlowDraftUpdateMeta, SelectionFlowMessageCode, SelectionFlowMetadata, SelectionFlowModuleAdapter, SelectionFlowModuleConfig, SelectionFlowModuleInput, SelectionFlowModuleRegistry, SelectionFlowRef, SelectionFlowRuntimeIssue, SelectionFlowSnapshot, SelectionFlowStepConfig, SelectionFlowValidationFeedback } from "./types.js";
2
+ import { _default } from "./PisellSelectionFlow.js";
3
+ import { useSelectionFlowContext, useTypedSelectionFlowContext } from "./context.js";
4
+ import { compileSelectionFlow, compileSelectionFlowSteps, hasSelectionDraftFieldValue, isSelectionModuleType, resolveFlowModuleAdapter } from "./compiler.js";