@tduniec/plugin-template-designer-foundation 0.1.1
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/CHANGELOG.md +13 -0
- package/README.md +13 -0
- package/dist/api/useScaffolderActions.esm.js +59 -0
- package/dist/api/useScaffolderActions.esm.js.map +1 -0
- package/dist/components/FieldEditorDialog.esm.js +55 -0
- package/dist/components/FieldEditorDialog.esm.js.map +1 -0
- package/dist/components/Nodes/ActionNode.esm.js +613 -0
- package/dist/components/Nodes/ActionNode.esm.js.map +1 -0
- package/dist/components/Nodes/OutputNode.esm.js +373 -0
- package/dist/components/Nodes/OutputNode.esm.js.map +1 -0
- package/dist/components/Nodes/ParameterInputNode.esm.js +320 -0
- package/dist/components/Nodes/ParameterInputNode.esm.js.map +1 -0
- package/dist/components/Nodes/ParameterTitlesNode.esm.js +251 -0
- package/dist/components/Nodes/ParameterTitlesNode.esm.js.map +1 -0
- package/dist/components/Nodes/ParametersNode.esm.js +147 -0
- package/dist/components/Nodes/ParametersNode.esm.js.map +1 -0
- package/dist/components/Nodes/action/schema.esm.js +68 -0
- package/dist/components/Nodes/action/schema.esm.js.map +1 -0
- package/dist/components/Nodes/action/useActionInputs.esm.js +71 -0
- package/dist/components/Nodes/action/useActionInputs.esm.js.map +1 -0
- package/dist/components/Nodes/common/AutoWidthPopper.esm.js +11 -0
- package/dist/components/Nodes/common/AutoWidthPopper.esm.js.map +1 -0
- package/dist/components/Nodes/common/nodeInteraction.esm.js +20 -0
- package/dist/components/Nodes/common/nodeInteraction.esm.js.map +1 -0
- package/dist/components/Nodes/output/useOutputController.esm.js +125 -0
- package/dist/components/Nodes/output/useOutputController.esm.js.map +1 -0
- package/dist/components/TemplateDesigner/TemplateLanding.esm.js +157 -0
- package/dist/components/TemplateDesigner/TemplateLanding.esm.js.map +1 -0
- package/dist/components/TemplateDesigner/TemplateWorkspace.esm.js +416 -0
- package/dist/components/TemplateDesigner/TemplateWorkspace.esm.js.map +1 -0
- package/dist/components/TemplateDesigner/codemirrorTheme.esm.js +30 -0
- package/dist/components/TemplateDesigner/codemirrorTheme.esm.js.map +1 -0
- package/dist/components/TemplateDesigner/useFieldEditor.esm.js +95 -0
- package/dist/components/TemplateDesigner/useFieldEditor.esm.js.map +1 -0
- package/dist/components/TemplateDesignerIcon.esm.js +33 -0
- package/dist/components/TemplateDesignerIcon.esm.js.map +1 -0
- package/dist/components/designerFlowConfig.esm.js +13 -0
- package/dist/components/designerFlowConfig.esm.js.map +1 -0
- package/dist/designerFlow/DesignerFlow.esm.js +828 -0
- package/dist/designerFlow/DesignerFlow.esm.js.map +1 -0
- package/dist/designerFlow/handlers.esm.js +317 -0
- package/dist/designerFlow/handlers.esm.js.map +1 -0
- package/dist/designerFlow/model.esm.js +166 -0
- package/dist/designerFlow/model.esm.js.map +1 -0
- package/dist/designerFlow/nodeLayout.esm.js +108 -0
- package/dist/designerFlow/nodeLayout.esm.js.map +1 -0
- package/dist/designerFlow/parameterTransforms.esm.js +124 -0
- package/dist/designerFlow/parameterTransforms.esm.js.map +1 -0
- package/dist/designerFlow/utils/stableComparators.esm.js +69 -0
- package/dist/designerFlow/utils/stableComparators.esm.js.map +1 -0
- package/dist/foundation/actionNodeCustomization.esm.js +20 -0
- package/dist/foundation/actionNodeCustomization.esm.js.map +1 -0
- package/dist/foundation/actionNodeRegistry.esm.js +30 -0
- package/dist/foundation/actionNodeRegistry.esm.js.map +1 -0
- package/dist/foundation/featureFlags.esm.js +6 -0
- package/dist/foundation/featureFlags.esm.js.map +1 -0
- package/dist/foundation/templateSources.esm.js +16 -0
- package/dist/foundation/templateSources.esm.js.map +1 -0
- package/dist/index.d.ts +382 -0
- package/dist/index.esm.js +25 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/state/templateUtils.esm.js +46 -0
- package/dist/state/templateUtils.esm.js.map +1 -0
- package/dist/state/useParameterSections.esm.js +162 -0
- package/dist/state/useParameterSections.esm.js.map +1 -0
- package/dist/state/useTemplateState.esm.js +627 -0
- package/dist/state/useTemplateState.esm.js.map +1 -0
- package/dist/types/flowNodes.esm.js +8 -0
- package/dist/types/flowNodes.esm.js.map +1 -0
- package/dist/utils/createSequentialEdges.esm.js +15 -0
- package/dist/utils/createSequentialEdges.esm.js.map +1 -0
- package/dist/utils/mocks/mocks.esm.js +120 -0
- package/dist/utils/mocks/mocks.esm.js.map +1 -0
- package/dist/utils/sampleTemplate.esm.js +40 -0
- package/dist/utils/sampleTemplate.esm.js.map +1 -0
- package/dist/utils/yamlJsonConversion.esm.js +47 -0
- package/dist/utils/yamlJsonConversion.esm.js.map +1 -0
- package/package.json +103 -0
|
@@ -0,0 +1,828 @@
|
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { useRef, useMemo, useState, useCallback, useEffect, createElement } from 'react';
|
|
3
|
+
import { useNodesState, applyNodeChanges, applyEdgeChanges, addEdge, ReactFlow } from '@xyflow/react';
|
|
4
|
+
import '@xyflow/react/dist/style.css';
|
|
5
|
+
import { buildNodesFromModel, stableStringify, collectParameterReferences, collectStepOutputReferences, extractStepsFromNodes, extractParametersFromNodes, extractOutputFromNodes } from './model.esm.js';
|
|
6
|
+
import { createSequentialEdges } from '../utils/createSequentialEdges.esm.js';
|
|
7
|
+
import { buildNodeHashMap, buildEdgeHashMap, mergeNodesWithStability, mergeEdgesWithStability } from './utils/stableComparators.esm.js';
|
|
8
|
+
import { createHandleReorderAndAlignNodes, createHandleUpdateField, createHandleUpdateInput, createHandleRemoveInputKey, createHandleUpdateOutput, createHandleUpdateSections, createHandleAddNode, createHandleRemoveNode } from './handlers.esm.js';
|
|
9
|
+
import { resolveNodeHeightForTracking, alignNodes } from './nodeLayout.esm.js';
|
|
10
|
+
import { nodeDefaults, FLOW_LAYOUT } from '../components/designerFlowConfig.esm.js';
|
|
11
|
+
import { useScaffolderActions } from '../api/useScaffolderActions.esm.js';
|
|
12
|
+
|
|
13
|
+
const EMPTY_EDGES = [];
|
|
14
|
+
const EMIT_DEBOUNCE_MS = 1200;
|
|
15
|
+
const VIEWPORT_TUNING = {
|
|
16
|
+
alignDebounceMs: 120,
|
|
17
|
+
// Debounce view/align updates so typing isn't interrupted by layout thrash.
|
|
18
|
+
centerDurationMs: 280,
|
|
19
|
+
fitFallbackDelayMs: 50
|
|
20
|
+
};
|
|
21
|
+
if (typeof window !== "undefined" && !window.__rfResizeObserverPatched) {
|
|
22
|
+
window.__rfResizeObserverPatched = true;
|
|
23
|
+
if (typeof window.ResizeObserver === "function") {
|
|
24
|
+
const OriginalResizeObserver = window.ResizeObserver;
|
|
25
|
+
window.ResizeObserver = class extends OriginalResizeObserver {
|
|
26
|
+
constructor(callback) {
|
|
27
|
+
super((entries, observer) => {
|
|
28
|
+
window.requestAnimationFrame(() => callback(entries, observer));
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
const shouldSwallow = (message) => typeof message === "string" && message.includes("ResizeObserver loop completed with undelivered");
|
|
34
|
+
const swallowResizeObserverError = (event) => {
|
|
35
|
+
const message = event?.message || event?.error?.message || String(event);
|
|
36
|
+
if (shouldSwallow(message)) {
|
|
37
|
+
event.preventDefault();
|
|
38
|
+
event.stopImmediatePropagation();
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
return void 0;
|
|
42
|
+
};
|
|
43
|
+
const swallowResizeObserverRejection = (event) => {
|
|
44
|
+
const message = event.reason?.message ?? String(event.reason);
|
|
45
|
+
if (shouldSwallow(message)) {
|
|
46
|
+
event.preventDefault();
|
|
47
|
+
event.stopImmediatePropagation();
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
return void 0;
|
|
51
|
+
};
|
|
52
|
+
const swallowLoopEvent = (event) => {
|
|
53
|
+
event.preventDefault();
|
|
54
|
+
event.stopImmediatePropagation();
|
|
55
|
+
};
|
|
56
|
+
const originalOnError = window.onerror;
|
|
57
|
+
window.onerror = function handleResizeObserverOnError(message, source, lineno, colno, error) {
|
|
58
|
+
if (shouldSwallow(
|
|
59
|
+
typeof message === "string" ? message : error?.message ?? String(message)
|
|
60
|
+
)) {
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
if (typeof originalOnError === "function") {
|
|
64
|
+
return originalOnError(message, source, lineno, colno, error);
|
|
65
|
+
}
|
|
66
|
+
return void 0;
|
|
67
|
+
};
|
|
68
|
+
const originalOnUnhandledRejection = window.onunhandledrejection;
|
|
69
|
+
window.onunhandledrejection = function handleResizeObserverOnUnhandled(event) {
|
|
70
|
+
const reason = event?.reason;
|
|
71
|
+
const message = reason?.message ?? (typeof reason === "string" ? reason : "");
|
|
72
|
+
if (shouldSwallow(message)) {
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
if (typeof originalOnUnhandledRejection === "function") {
|
|
76
|
+
return originalOnUnhandledRejection(event);
|
|
77
|
+
}
|
|
78
|
+
return void 0;
|
|
79
|
+
};
|
|
80
|
+
window.addEventListener("error", swallowResizeObserverError, true);
|
|
81
|
+
window.addEventListener(
|
|
82
|
+
"unhandledrejection",
|
|
83
|
+
swallowResizeObserverRejection,
|
|
84
|
+
true
|
|
85
|
+
);
|
|
86
|
+
window.addEventListener(
|
|
87
|
+
"resizeobserverlooperror",
|
|
88
|
+
swallowLoopEvent,
|
|
89
|
+
true
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
const shallowArrayEqual = (a, b) => {
|
|
93
|
+
if (a === b) {
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
if (!a || !b || a.length !== b.length) {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
for (let i = 0; i < a.length; i += 1) {
|
|
100
|
+
if (a[i] !== b[i]) {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return true;
|
|
105
|
+
};
|
|
106
|
+
const FIXED_X_POSITION = FLOW_LAYOUT.fixedXPosition;
|
|
107
|
+
const VERTICAL_SPACING = FLOW_LAYOUT.verticalSpacing;
|
|
108
|
+
function DesignerFlow({
|
|
109
|
+
steps = [],
|
|
110
|
+
parameters,
|
|
111
|
+
output,
|
|
112
|
+
onStepsChange,
|
|
113
|
+
onParametersChange,
|
|
114
|
+
onOutputChange,
|
|
115
|
+
actionNodeComponent,
|
|
116
|
+
parametersNodeComponent,
|
|
117
|
+
outputNodeComponent,
|
|
118
|
+
decorateNodes,
|
|
119
|
+
decorateEdges,
|
|
120
|
+
nodeDefaults: nodeDefaults$1 = nodeDefaults
|
|
121
|
+
}) {
|
|
122
|
+
const nodeDataHashRef = useRef({});
|
|
123
|
+
const edgeDataHashRef = useRef({});
|
|
124
|
+
const scaffolderActionsCache = useScaffolderActions();
|
|
125
|
+
const {
|
|
126
|
+
ids: scaffolderActionIds,
|
|
127
|
+
inputsById: scaffolderActionInputsById,
|
|
128
|
+
outputsById: scaffolderActionOutputsById,
|
|
129
|
+
inputRequiredById: scaffolderActionInputRequiredById
|
|
130
|
+
} = scaffolderActionsCache;
|
|
131
|
+
const normalizedParametersProp = parameters ?? void 0;
|
|
132
|
+
const normalizedOutputProp = output ?? null;
|
|
133
|
+
const pendingFocusNodeIdRef = useRef(null);
|
|
134
|
+
const hasMountedRef = useRef(false);
|
|
135
|
+
const lastNodeCountRef = useRef(0);
|
|
136
|
+
const initialNodes = useMemo(() => {
|
|
137
|
+
const built = buildNodesFromModel(
|
|
138
|
+
steps,
|
|
139
|
+
normalizedParametersProp,
|
|
140
|
+
normalizedOutputProp,
|
|
141
|
+
{
|
|
142
|
+
scaffolderActionIds,
|
|
143
|
+
scaffolderActionInputsById,
|
|
144
|
+
scaffolderActionOutputsById,
|
|
145
|
+
scaffolderActionInputRequiredById
|
|
146
|
+
}
|
|
147
|
+
);
|
|
148
|
+
const nodes2 = decorateNodes ? decorateNodes(built) : built;
|
|
149
|
+
nodeDataHashRef.current = buildNodeHashMap(nodes2);
|
|
150
|
+
return nodes2;
|
|
151
|
+
}, [
|
|
152
|
+
steps,
|
|
153
|
+
normalizedParametersProp,
|
|
154
|
+
normalizedOutputProp,
|
|
155
|
+
scaffolderActionIds,
|
|
156
|
+
scaffolderActionInputsById,
|
|
157
|
+
scaffolderActionOutputsById,
|
|
158
|
+
scaffolderActionInputRequiredById,
|
|
159
|
+
decorateNodes
|
|
160
|
+
]);
|
|
161
|
+
const [nodes, setNodes] = useNodesState(initialNodes);
|
|
162
|
+
const initialEdges = useMemo(() => {
|
|
163
|
+
const edges2 = decorateEdges ? decorateEdges(createSequentialEdges(initialNodes), initialNodes) : createSequentialEdges(initialNodes);
|
|
164
|
+
edgeDataHashRef.current = buildEdgeHashMap(edges2);
|
|
165
|
+
lastNodeCountRef.current = initialNodes.length;
|
|
166
|
+
return edges2;
|
|
167
|
+
}, [decorateEdges, initialNodes]);
|
|
168
|
+
const [edges, setEdges] = useState(initialEdges);
|
|
169
|
+
const modelHash = useMemo(
|
|
170
|
+
() => stableStringify({
|
|
171
|
+
steps,
|
|
172
|
+
parameters: normalizedParametersProp,
|
|
173
|
+
output: normalizedOutputProp
|
|
174
|
+
}),
|
|
175
|
+
[steps, normalizedParametersProp, normalizedOutputProp]
|
|
176
|
+
);
|
|
177
|
+
const cacheFingerprint = useMemo(
|
|
178
|
+
() => stableStringify({
|
|
179
|
+
ids: scaffolderActionIds,
|
|
180
|
+
inputs: scaffolderActionInputsById,
|
|
181
|
+
outputs: scaffolderActionOutputsById,
|
|
182
|
+
inputRequired: scaffolderActionInputRequiredById
|
|
183
|
+
}),
|
|
184
|
+
[
|
|
185
|
+
scaffolderActionIds,
|
|
186
|
+
scaffolderActionInputsById,
|
|
187
|
+
scaffolderActionOutputsById,
|
|
188
|
+
scaffolderActionInputRequiredById
|
|
189
|
+
]
|
|
190
|
+
);
|
|
191
|
+
const lastAppliedModelHashRef = useRef(null);
|
|
192
|
+
const lastEmittedModelHashRef = useRef(null);
|
|
193
|
+
const lastCacheFingerprintRef = useRef(null);
|
|
194
|
+
const nodeHeightsRef = useRef({});
|
|
195
|
+
const lastViewportRef = useRef(null);
|
|
196
|
+
const emitDebounceRef = useRef(null);
|
|
197
|
+
const isDraggingRef = useRef(false);
|
|
198
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
199
|
+
const emitAfterDragRef = useRef(false);
|
|
200
|
+
const pendingInitialFitRef = useRef(true);
|
|
201
|
+
const userMovedViewportRef = useRef(false);
|
|
202
|
+
const layoutInitializedRef = useRef(false);
|
|
203
|
+
const [viewport, setViewport] = useState(() => {
|
|
204
|
+
const existing = lastViewportRef.current;
|
|
205
|
+
if (existing) {
|
|
206
|
+
return existing;
|
|
207
|
+
}
|
|
208
|
+
const fallback = { x: 0, y: 0, zoom: 1 };
|
|
209
|
+
lastViewportRef.current = fallback;
|
|
210
|
+
return fallback;
|
|
211
|
+
});
|
|
212
|
+
const fitViewRafRef = useRef(null);
|
|
213
|
+
const fitViewTimeoutRef = useRef(null);
|
|
214
|
+
const alignDebounceRef = useRef(null);
|
|
215
|
+
const setViewportIfChanged = useCallback((next) => {
|
|
216
|
+
if (!next) {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
const prev = lastViewportRef.current;
|
|
220
|
+
if (prev && prev.x === next.x && prev.y === next.y && prev.zoom === next.zoom) {
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
lastViewportRef.current = next;
|
|
224
|
+
setViewport(next);
|
|
225
|
+
}, []);
|
|
226
|
+
useEffect(() => {
|
|
227
|
+
const isCacheChanged = cacheFingerprint !== lastCacheFingerprintRef.current;
|
|
228
|
+
if (modelHash === lastAppliedModelHashRef.current && !isCacheChanged) {
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
const builtNodes = buildNodesFromModel(
|
|
232
|
+
steps,
|
|
233
|
+
normalizedParametersProp,
|
|
234
|
+
normalizedOutputProp,
|
|
235
|
+
{
|
|
236
|
+
scaffolderActionIds,
|
|
237
|
+
scaffolderActionInputsById,
|
|
238
|
+
scaffolderActionOutputsById,
|
|
239
|
+
scaffolderActionInputRequiredById
|
|
240
|
+
}
|
|
241
|
+
);
|
|
242
|
+
const nextNodes = decorateNodes ? decorateNodes(builtNodes) : builtNodes;
|
|
243
|
+
const isInitialMount = !hasMountedRef.current;
|
|
244
|
+
lastAppliedModelHashRef.current = modelHash;
|
|
245
|
+
lastCacheFingerprintRef.current = cacheFingerprint;
|
|
246
|
+
lastEmittedModelHashRef.current = modelHash;
|
|
247
|
+
setNodes((currentNodes) => {
|
|
248
|
+
const merged = mergeNodesWithStability(
|
|
249
|
+
currentNodes,
|
|
250
|
+
nextNodes,
|
|
251
|
+
nodeDataHashRef
|
|
252
|
+
);
|
|
253
|
+
return merged;
|
|
254
|
+
});
|
|
255
|
+
setEdges((currentEdges) => {
|
|
256
|
+
const newEdges = decorateEdges ? decorateEdges(createSequentialEdges(nextNodes), nextNodes) : createSequentialEdges(nextNodes);
|
|
257
|
+
const merged = mergeEdgesWithStability(
|
|
258
|
+
currentEdges,
|
|
259
|
+
newEdges,
|
|
260
|
+
edgeDataHashRef
|
|
261
|
+
);
|
|
262
|
+
return merged;
|
|
263
|
+
});
|
|
264
|
+
hasMountedRef.current = true;
|
|
265
|
+
lastNodeCountRef.current = nextNodes.length;
|
|
266
|
+
if (isInitialMount) {
|
|
267
|
+
pendingInitialFitRef.current = true;
|
|
268
|
+
}
|
|
269
|
+
}, [
|
|
270
|
+
steps,
|
|
271
|
+
normalizedParametersProp,
|
|
272
|
+
normalizedOutputProp,
|
|
273
|
+
modelHash,
|
|
274
|
+
cacheFingerprint,
|
|
275
|
+
scaffolderActionIds,
|
|
276
|
+
scaffolderActionInputsById,
|
|
277
|
+
scaffolderActionOutputsById,
|
|
278
|
+
scaffolderActionInputRequiredById,
|
|
279
|
+
decorateNodes,
|
|
280
|
+
decorateEdges,
|
|
281
|
+
setNodes,
|
|
282
|
+
setEdges
|
|
283
|
+
]);
|
|
284
|
+
useEffect(() => {
|
|
285
|
+
if (!nodes.length) {
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
if (nodes.some((node) => node.dragging)) {
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
const activeNodeIds = /* @__PURE__ */ new Set();
|
|
292
|
+
let hasMeasuredChange = false;
|
|
293
|
+
nodes.forEach((node) => {
|
|
294
|
+
activeNodeIds.add(node.id);
|
|
295
|
+
const measuredHeight = resolveNodeHeightForTracking(node);
|
|
296
|
+
if (typeof measuredHeight !== "number") {
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
const previousHeight = nodeHeightsRef.current[node.id];
|
|
300
|
+
const heightDelta = Math.abs(
|
|
301
|
+
(previousHeight ?? measuredHeight) - measuredHeight
|
|
302
|
+
);
|
|
303
|
+
if (heightDelta >= 1) {
|
|
304
|
+
nodeHeightsRef.current[node.id] = measuredHeight;
|
|
305
|
+
hasMeasuredChange = true;
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
Object.keys(nodeHeightsRef.current).forEach((id) => {
|
|
309
|
+
if (!activeNodeIds.has(id)) {
|
|
310
|
+
delete nodeHeightsRef.current[id];
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
if (!hasMeasuredChange) {
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
if (!layoutInitializedRef.current) {
|
|
317
|
+
layoutInitializedRef.current = true;
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
if (alignDebounceRef.current) {
|
|
321
|
+
clearTimeout(alignDebounceRef.current);
|
|
322
|
+
}
|
|
323
|
+
alignDebounceRef.current = setTimeout(() => {
|
|
324
|
+
alignDebounceRef.current = null;
|
|
325
|
+
setNodes((currentNodes) => {
|
|
326
|
+
const alignedNodes = alignNodes(
|
|
327
|
+
currentNodes,
|
|
328
|
+
FIXED_X_POSITION,
|
|
329
|
+
VERTICAL_SPACING
|
|
330
|
+
);
|
|
331
|
+
const positionsChanged = alignedNodes.some((node, index) => {
|
|
332
|
+
const previousNode = currentNodes[index];
|
|
333
|
+
if (!previousNode) {
|
|
334
|
+
return true;
|
|
335
|
+
}
|
|
336
|
+
return node.position.x !== previousNode.position.x || node.position.y !== previousNode.position.y;
|
|
337
|
+
});
|
|
338
|
+
return positionsChanged ? alignedNodes : currentNodes;
|
|
339
|
+
});
|
|
340
|
+
}, VIEWPORT_TUNING.alignDebounceMs);
|
|
341
|
+
}, [nodes, setNodes]);
|
|
342
|
+
const parameterReferences = useMemo(
|
|
343
|
+
() => collectParameterReferences(normalizedParametersProp),
|
|
344
|
+
[normalizedParametersProp]
|
|
345
|
+
);
|
|
346
|
+
const stepOutputReferencesByNode = useMemo(
|
|
347
|
+
() => collectStepOutputReferences(nodes, parameterReferences),
|
|
348
|
+
[nodes, parameterReferences]
|
|
349
|
+
);
|
|
350
|
+
const onNodesChange = useCallback(
|
|
351
|
+
(changes) => setNodes((ns) => {
|
|
352
|
+
if (changes.some(
|
|
353
|
+
(change) => change.type === "position" && change.dragging
|
|
354
|
+
)) {
|
|
355
|
+
isDraggingRef.current = true;
|
|
356
|
+
setIsDragging(true);
|
|
357
|
+
} else if (changes.some(
|
|
358
|
+
(change) => change.type === "position" && change.dragging === false
|
|
359
|
+
)) {
|
|
360
|
+
const stillDragging = ns.some((node) => node.dragging);
|
|
361
|
+
isDraggingRef.current = stillDragging;
|
|
362
|
+
setIsDragging(stillDragging);
|
|
363
|
+
}
|
|
364
|
+
return applyNodeChanges(changes, ns);
|
|
365
|
+
}),
|
|
366
|
+
[setNodes]
|
|
367
|
+
);
|
|
368
|
+
const onEdgesChange = useCallback(
|
|
369
|
+
(changes) => setEdges((es) => applyEdgeChanges(changes, es)),
|
|
370
|
+
[setEdges]
|
|
371
|
+
);
|
|
372
|
+
const resolvedNodeTypes = useMemo(
|
|
373
|
+
() => ({
|
|
374
|
+
parametersNode: ((props) => createElement(parametersNodeComponent, {
|
|
375
|
+
data: props.data
|
|
376
|
+
})),
|
|
377
|
+
actionNode: ((props) => createElement(actionNodeComponent, {
|
|
378
|
+
data: props.data
|
|
379
|
+
})),
|
|
380
|
+
outputNode: ((props) => createElement(outputNodeComponent, {
|
|
381
|
+
data: props.data
|
|
382
|
+
}))
|
|
383
|
+
}),
|
|
384
|
+
[actionNodeComponent, outputNodeComponent, parametersNodeComponent]
|
|
385
|
+
);
|
|
386
|
+
const onConnect = useCallback(
|
|
387
|
+
(params) => setEdges((es) => addEdge(params, es)),
|
|
388
|
+
[setEdges]
|
|
389
|
+
);
|
|
390
|
+
const reorderAndAlignNodes = useMemo(
|
|
391
|
+
() => createHandleReorderAndAlignNodes(setNodes, setEdges, {
|
|
392
|
+
fixedXPosition: FIXED_X_POSITION,
|
|
393
|
+
verticalSpacing: VERTICAL_SPACING
|
|
394
|
+
}),
|
|
395
|
+
[setNodes, setEdges]
|
|
396
|
+
);
|
|
397
|
+
const onNodeDragStop = useCallback(
|
|
398
|
+
(_, node) => {
|
|
399
|
+
isDraggingRef.current = false;
|
|
400
|
+
setIsDragging(false);
|
|
401
|
+
reorderAndAlignNodes(node);
|
|
402
|
+
},
|
|
403
|
+
[reorderAndAlignNodes]
|
|
404
|
+
);
|
|
405
|
+
const onUpdateField = useMemo(
|
|
406
|
+
() => createHandleUpdateField(setNodes),
|
|
407
|
+
[setNodes]
|
|
408
|
+
);
|
|
409
|
+
const onUpdateInput = useMemo(
|
|
410
|
+
() => createHandleUpdateInput(setNodes),
|
|
411
|
+
[setNodes]
|
|
412
|
+
);
|
|
413
|
+
const onRemoveInputKey = useMemo(
|
|
414
|
+
() => createHandleRemoveInputKey(setNodes),
|
|
415
|
+
[setNodes]
|
|
416
|
+
);
|
|
417
|
+
const onUpdateOutput = useMemo(
|
|
418
|
+
() => createHandleUpdateOutput(setNodes),
|
|
419
|
+
[setNodes]
|
|
420
|
+
);
|
|
421
|
+
const onUpdateSections = useMemo(
|
|
422
|
+
() => createHandleUpdateSections(setNodes),
|
|
423
|
+
[setNodes]
|
|
424
|
+
);
|
|
425
|
+
const handleAddNode = useMemo(
|
|
426
|
+
() => createHandleAddNode(setNodes, setEdges, {
|
|
427
|
+
fixedXPosition: FIXED_X_POSITION,
|
|
428
|
+
verticalSpacing: VERTICAL_SPACING,
|
|
429
|
+
nodeDefaults: nodeDefaults$1,
|
|
430
|
+
scaffolderActionIds,
|
|
431
|
+
scaffolderActionInputsById,
|
|
432
|
+
scaffolderActionInputRequiredById,
|
|
433
|
+
scaffolderActionOutputsById,
|
|
434
|
+
onNodeAdded: (rfId) => {
|
|
435
|
+
pendingFocusNodeIdRef.current = rfId;
|
|
436
|
+
pendingInitialFitRef.current = false;
|
|
437
|
+
}
|
|
438
|
+
}),
|
|
439
|
+
[
|
|
440
|
+
scaffolderActionIds,
|
|
441
|
+
scaffolderActionInputsById,
|
|
442
|
+
scaffolderActionOutputsById,
|
|
443
|
+
scaffolderActionInputRequiredById,
|
|
444
|
+
nodeDefaults$1,
|
|
445
|
+
setNodes,
|
|
446
|
+
setEdges
|
|
447
|
+
]
|
|
448
|
+
);
|
|
449
|
+
const handleRemoveNode = useMemo(
|
|
450
|
+
() => createHandleRemoveNode(setNodes, setEdges, {
|
|
451
|
+
fixedXPosition: FIXED_X_POSITION,
|
|
452
|
+
verticalSpacing: VERTICAL_SPACING
|
|
453
|
+
}),
|
|
454
|
+
[setNodes, setEdges]
|
|
455
|
+
);
|
|
456
|
+
const emitChanges = useCallback(() => {
|
|
457
|
+
if (!onStepsChange && !onParametersChange && !onOutputChange) {
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
const stepsFromNodes = extractStepsFromNodes(nodes);
|
|
461
|
+
const parametersFromNodes = extractParametersFromNodes(nodes);
|
|
462
|
+
const outputFromNodes = extractOutputFromNodes(nodes);
|
|
463
|
+
const nextHash = stableStringify({
|
|
464
|
+
steps: stepsFromNodes,
|
|
465
|
+
parameters: parametersFromNodes,
|
|
466
|
+
output: outputFromNodes
|
|
467
|
+
});
|
|
468
|
+
if (nextHash === lastEmittedModelHashRef.current) {
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
lastEmittedModelHashRef.current = nextHash;
|
|
472
|
+
onStepsChange?.(stepsFromNodes);
|
|
473
|
+
onParametersChange?.(parametersFromNodes);
|
|
474
|
+
onOutputChange?.(outputFromNodes);
|
|
475
|
+
}, [
|
|
476
|
+
nodes,
|
|
477
|
+
onOutputChange,
|
|
478
|
+
onParametersChange,
|
|
479
|
+
onStepsChange,
|
|
480
|
+
lastEmittedModelHashRef
|
|
481
|
+
]);
|
|
482
|
+
const emitChangesDeferred = useCallback(() => {
|
|
483
|
+
if (emitDebounceRef.current) {
|
|
484
|
+
clearTimeout(emitDebounceRef.current);
|
|
485
|
+
}
|
|
486
|
+
emitDebounceRef.current = setTimeout(() => {
|
|
487
|
+
emitChanges();
|
|
488
|
+
emitDebounceRef.current = null;
|
|
489
|
+
}, EMIT_DEBOUNCE_MS);
|
|
490
|
+
}, [emitChanges]);
|
|
491
|
+
const flushPendingEmit = useCallback(() => {
|
|
492
|
+
if (emitDebounceRef.current) {
|
|
493
|
+
clearTimeout(emitDebounceRef.current);
|
|
494
|
+
emitDebounceRef.current = null;
|
|
495
|
+
}
|
|
496
|
+
emitChanges();
|
|
497
|
+
}, [emitChanges]);
|
|
498
|
+
const ensureNodeDataStability = useCallback(
|
|
499
|
+
(node) => {
|
|
500
|
+
if (node.type === "actionNode") {
|
|
501
|
+
const data = node.data;
|
|
502
|
+
const nextRefs = stepOutputReferencesByNode[node.id] ?? data.stepOutputReferences;
|
|
503
|
+
const refsUnchanged = shallowArrayEqual(
|
|
504
|
+
data.stepOutputReferences,
|
|
505
|
+
nextRefs
|
|
506
|
+
);
|
|
507
|
+
const hasSameHandlers = data.onAddNode === handleAddNode && data.onRemoveNode === handleRemoveNode && data.onUpdateField === onUpdateField && data.onUpdateInput === onUpdateInput && data.onRemoveInputKey === onRemoveInputKey;
|
|
508
|
+
const hasSameCaches = data.scaffolderActionIds === scaffolderActionIds && data.scaffolderActionInputsById === scaffolderActionInputsById && data.scaffolderActionOutputsById === scaffolderActionOutputsById && data.scaffolderActionInputRequiredById === scaffolderActionInputRequiredById;
|
|
509
|
+
if (hasSameHandlers && hasSameCaches && refsUnchanged) {
|
|
510
|
+
return node;
|
|
511
|
+
}
|
|
512
|
+
return {
|
|
513
|
+
...node,
|
|
514
|
+
data: {
|
|
515
|
+
...data,
|
|
516
|
+
onAddNode: handleAddNode,
|
|
517
|
+
onRemoveNode: handleRemoveNode,
|
|
518
|
+
onUpdateField,
|
|
519
|
+
onUpdateInput,
|
|
520
|
+
onRemoveInputKey,
|
|
521
|
+
scaffolderActionIds,
|
|
522
|
+
scaffolderActionInputsById,
|
|
523
|
+
scaffolderActionOutputsById,
|
|
524
|
+
scaffolderActionInputRequiredById,
|
|
525
|
+
stepOutputReferences: refsUnchanged ? data.stepOutputReferences : nextRefs
|
|
526
|
+
}
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
if (node.type === "outputNode") {
|
|
530
|
+
const data = node.data;
|
|
531
|
+
const nextRefs = stepOutputReferencesByNode[node.id] ?? data.stepOutputReferences;
|
|
532
|
+
const refsUnchanged = shallowArrayEqual(
|
|
533
|
+
data.stepOutputReferences,
|
|
534
|
+
nextRefs
|
|
535
|
+
);
|
|
536
|
+
const hasSameHandlers = data.onUpdateOutput === onUpdateOutput && data.onRemoveNode === handleRemoveNode && data.onAddNode === handleAddNode;
|
|
537
|
+
const hasSameCaches = data.scaffolderActionIds === scaffolderActionIds && data.scaffolderActionInputsById === scaffolderActionInputsById && data.scaffolderActionOutputsById === scaffolderActionOutputsById && data.scaffolderActionInputRequiredById === scaffolderActionInputRequiredById;
|
|
538
|
+
if (hasSameHandlers && hasSameCaches && refsUnchanged) {
|
|
539
|
+
return node;
|
|
540
|
+
}
|
|
541
|
+
return {
|
|
542
|
+
...node,
|
|
543
|
+
data: {
|
|
544
|
+
...data,
|
|
545
|
+
onUpdateOutput,
|
|
546
|
+
onRemoveNode: handleRemoveNode,
|
|
547
|
+
onAddNode: handleAddNode,
|
|
548
|
+
scaffolderActionIds,
|
|
549
|
+
scaffolderActionInputsById,
|
|
550
|
+
scaffolderActionOutputsById,
|
|
551
|
+
scaffolderActionInputRequiredById,
|
|
552
|
+
stepOutputReferences: refsUnchanged ? data.stepOutputReferences : nextRefs
|
|
553
|
+
}
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
if (node.type === "parametersNode") {
|
|
557
|
+
const data = node.data;
|
|
558
|
+
const hasSameHandlers = data.onUpdateSections === onUpdateSections && data.onRemoveNode === handleRemoveNode && data.onAddNode === handleAddNode;
|
|
559
|
+
const hasSameCaches = data.scaffolderActionIds === scaffolderActionIds && data.scaffolderActionInputsById === scaffolderActionInputsById && data.scaffolderActionOutputsById === scaffolderActionOutputsById && data.scaffolderActionInputRequiredById === scaffolderActionInputRequiredById;
|
|
560
|
+
if (hasSameHandlers && hasSameCaches) {
|
|
561
|
+
return node;
|
|
562
|
+
}
|
|
563
|
+
return {
|
|
564
|
+
...node,
|
|
565
|
+
data: {
|
|
566
|
+
...data,
|
|
567
|
+
onUpdateSections,
|
|
568
|
+
onRemoveNode: handleRemoveNode,
|
|
569
|
+
onAddNode: handleAddNode,
|
|
570
|
+
scaffolderActionIds,
|
|
571
|
+
scaffolderActionInputsById,
|
|
572
|
+
scaffolderActionOutputsById,
|
|
573
|
+
scaffolderActionInputRequiredById
|
|
574
|
+
}
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
return node;
|
|
578
|
+
},
|
|
579
|
+
[
|
|
580
|
+
handleAddNode,
|
|
581
|
+
handleRemoveNode,
|
|
582
|
+
onUpdateField,
|
|
583
|
+
onUpdateInput,
|
|
584
|
+
onRemoveInputKey,
|
|
585
|
+
onUpdateOutput,
|
|
586
|
+
onUpdateSections,
|
|
587
|
+
scaffolderActionIds,
|
|
588
|
+
scaffolderActionInputsById,
|
|
589
|
+
scaffolderActionOutputsById,
|
|
590
|
+
scaffolderActionInputRequiredById,
|
|
591
|
+
stepOutputReferencesByNode
|
|
592
|
+
]
|
|
593
|
+
);
|
|
594
|
+
useEffect(() => {
|
|
595
|
+
setNodes((currentNodes) => {
|
|
596
|
+
let changed = false;
|
|
597
|
+
const nextNodes = currentNodes.map((node) => {
|
|
598
|
+
const updated = ensureNodeDataStability(node);
|
|
599
|
+
if (updated !== node) {
|
|
600
|
+
changed = true;
|
|
601
|
+
}
|
|
602
|
+
return updated;
|
|
603
|
+
});
|
|
604
|
+
return changed ? nextNodes : currentNodes;
|
|
605
|
+
});
|
|
606
|
+
}, [ensureNodeDataStability, setNodes]);
|
|
607
|
+
useEffect(() => {
|
|
608
|
+
emitChangesDeferred();
|
|
609
|
+
}, [nodes, emitChangesDeferred]);
|
|
610
|
+
useEffect(() => {
|
|
611
|
+
lastEmittedModelHashRef.current = null;
|
|
612
|
+
}, [nodes]);
|
|
613
|
+
useEffect(() => {
|
|
614
|
+
if (!nodes.length) {
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
617
|
+
emitChangesDeferred();
|
|
618
|
+
}, [emitChangesDeferred, modelHash, nodes]);
|
|
619
|
+
useEffect(() => {
|
|
620
|
+
return () => {
|
|
621
|
+
if (emitDebounceRef.current) {
|
|
622
|
+
clearTimeout(emitDebounceRef.current);
|
|
623
|
+
}
|
|
624
|
+
if (fitViewRafRef.current !== null) {
|
|
625
|
+
cancelAnimationFrame(fitViewRafRef.current);
|
|
626
|
+
fitViewRafRef.current = null;
|
|
627
|
+
}
|
|
628
|
+
if (fitViewTimeoutRef.current) {
|
|
629
|
+
clearTimeout(fitViewTimeoutRef.current);
|
|
630
|
+
fitViewTimeoutRef.current = null;
|
|
631
|
+
}
|
|
632
|
+
if (alignDebounceRef.current) {
|
|
633
|
+
clearTimeout(alignDebounceRef.current);
|
|
634
|
+
}
|
|
635
|
+
flushPendingEmit();
|
|
636
|
+
};
|
|
637
|
+
}, [flushPendingEmit]);
|
|
638
|
+
const [reactFlowInstance, setReactFlowInstance] = useState(null);
|
|
639
|
+
const fitFlowToView = useCallback(() => {
|
|
640
|
+
if (!reactFlowInstance || !nodes.length) {
|
|
641
|
+
return;
|
|
642
|
+
}
|
|
643
|
+
if (fitViewRafRef.current !== null) {
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
646
|
+
if (userMovedViewportRef.current && !pendingInitialFitRef.current) {
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
const nodeWithWidth = nodes.find((node) => node.width);
|
|
650
|
+
const nodeWidth = nodeWithWidth?.width ?? 760;
|
|
651
|
+
const padding = Math.max((window.innerWidth - nodeWidth) / 2 - 24, 60);
|
|
652
|
+
const viewOptions = {
|
|
653
|
+
padding,
|
|
654
|
+
minZoom: 0.2
|
|
655
|
+
};
|
|
656
|
+
fitViewRafRef.current = window.requestAnimationFrame(() => {
|
|
657
|
+
fitViewRafRef.current = null;
|
|
658
|
+
try {
|
|
659
|
+
reactFlowInstance.fitView(viewOptions);
|
|
660
|
+
setViewportIfChanged(reactFlowInstance.getViewport());
|
|
661
|
+
} catch {
|
|
662
|
+
}
|
|
663
|
+
});
|
|
664
|
+
if (fitViewTimeoutRef.current) {
|
|
665
|
+
clearTimeout(fitViewTimeoutRef.current);
|
|
666
|
+
}
|
|
667
|
+
fitViewTimeoutRef.current = setTimeout(() => {
|
|
668
|
+
fitViewTimeoutRef.current = null;
|
|
669
|
+
try {
|
|
670
|
+
reactFlowInstance.fitView(viewOptions);
|
|
671
|
+
setViewportIfChanged(reactFlowInstance.getViewport());
|
|
672
|
+
} catch {
|
|
673
|
+
}
|
|
674
|
+
}, VIEWPORT_TUNING.fitFallbackDelayMs);
|
|
675
|
+
}, [nodes, reactFlowInstance, setViewportIfChanged]);
|
|
676
|
+
useEffect(() => {
|
|
677
|
+
if (!reactFlowInstance) {
|
|
678
|
+
return;
|
|
679
|
+
}
|
|
680
|
+
if (viewport === null) {
|
|
681
|
+
setViewportIfChanged(viewport);
|
|
682
|
+
}
|
|
683
|
+
if (!pendingInitialFitRef.current) {
|
|
684
|
+
return;
|
|
685
|
+
}
|
|
686
|
+
pendingInitialFitRef.current = false;
|
|
687
|
+
fitFlowToView();
|
|
688
|
+
}, [
|
|
689
|
+
fitFlowToView,
|
|
690
|
+
nodes,
|
|
691
|
+
edges,
|
|
692
|
+
reactFlowInstance,
|
|
693
|
+
viewport,
|
|
694
|
+
setViewportIfChanged
|
|
695
|
+
]);
|
|
696
|
+
useEffect(() => {
|
|
697
|
+
const swallowResizeObserverError = (event) => {
|
|
698
|
+
const message = event?.message || event?.error?.message || String(event);
|
|
699
|
+
if (typeof message === "string" && message.includes("ResizeObserver loop")) {
|
|
700
|
+
event.preventDefault();
|
|
701
|
+
event.stopImmediatePropagation();
|
|
702
|
+
}
|
|
703
|
+
};
|
|
704
|
+
const swallowResizeObserverRejection = (event) => {
|
|
705
|
+
const message = event.reason?.message ?? String(event.reason);
|
|
706
|
+
if (typeof message === "string" && message.includes("ResizeObserver loop")) {
|
|
707
|
+
event.preventDefault();
|
|
708
|
+
event.stopImmediatePropagation();
|
|
709
|
+
}
|
|
710
|
+
};
|
|
711
|
+
window.addEventListener("error", swallowResizeObserverError, true);
|
|
712
|
+
window.addEventListener(
|
|
713
|
+
"unhandledrejection",
|
|
714
|
+
swallowResizeObserverRejection,
|
|
715
|
+
true
|
|
716
|
+
);
|
|
717
|
+
const swallowLoopErrorEvent = (event) => {
|
|
718
|
+
event.preventDefault();
|
|
719
|
+
event.stopImmediatePropagation();
|
|
720
|
+
};
|
|
721
|
+
window.addEventListener(
|
|
722
|
+
"resizeobserverlooperror",
|
|
723
|
+
swallowLoopErrorEvent,
|
|
724
|
+
true
|
|
725
|
+
);
|
|
726
|
+
return () => {
|
|
727
|
+
window.removeEventListener("error", swallowResizeObserverError, true);
|
|
728
|
+
window.removeEventListener(
|
|
729
|
+
"unhandledrejection",
|
|
730
|
+
swallowResizeObserverRejection,
|
|
731
|
+
true
|
|
732
|
+
);
|
|
733
|
+
window.removeEventListener(
|
|
734
|
+
"resizeobserverlooperror",
|
|
735
|
+
swallowLoopErrorEvent,
|
|
736
|
+
true
|
|
737
|
+
);
|
|
738
|
+
};
|
|
739
|
+
}, []);
|
|
740
|
+
useEffect(() => {
|
|
741
|
+
if (!reactFlowInstance) {
|
|
742
|
+
return void 0;
|
|
743
|
+
}
|
|
744
|
+
window.addEventListener("resize", fitFlowToView);
|
|
745
|
+
return () => {
|
|
746
|
+
window.removeEventListener("resize", fitFlowToView);
|
|
747
|
+
};
|
|
748
|
+
}, [fitFlowToView, reactFlowInstance]);
|
|
749
|
+
useEffect(() => {
|
|
750
|
+
if (!isDragging) {
|
|
751
|
+
if (emitAfterDragRef.current) {
|
|
752
|
+
emitAfterDragRef.current = false;
|
|
753
|
+
lastEmittedModelHashRef.current = null;
|
|
754
|
+
}
|
|
755
|
+
lastEmittedModelHashRef.current = null;
|
|
756
|
+
}
|
|
757
|
+
}, [isDragging]);
|
|
758
|
+
const handleMoveEnd = useCallback(
|
|
759
|
+
(_event, nextViewport) => {
|
|
760
|
+
setViewportIfChanged(nextViewport);
|
|
761
|
+
},
|
|
762
|
+
[setViewportIfChanged]
|
|
763
|
+
);
|
|
764
|
+
const handleMove = useCallback(
|
|
765
|
+
(_, nextViewport) => {
|
|
766
|
+
userMovedViewportRef.current = true;
|
|
767
|
+
setViewportIfChanged(nextViewport);
|
|
768
|
+
},
|
|
769
|
+
[setViewportIfChanged]
|
|
770
|
+
);
|
|
771
|
+
const shouldCullEdges = edges.length > 300 && (viewport?.zoom ?? 1) < 0.3 && !isDragging;
|
|
772
|
+
const renderedEdges = useMemo(
|
|
773
|
+
() => shouldCullEdges ? EMPTY_EDGES : edges,
|
|
774
|
+
[edges, shouldCullEdges]
|
|
775
|
+
);
|
|
776
|
+
useEffect(() => {
|
|
777
|
+
if (!reactFlowInstance) {
|
|
778
|
+
return;
|
|
779
|
+
}
|
|
780
|
+
const pendingId = pendingFocusNodeIdRef.current;
|
|
781
|
+
if (!pendingId) {
|
|
782
|
+
return;
|
|
783
|
+
}
|
|
784
|
+
const target = nodes.find((node) => node.id === pendingId);
|
|
785
|
+
if (!target) {
|
|
786
|
+
return;
|
|
787
|
+
}
|
|
788
|
+
pendingFocusNodeIdRef.current = null;
|
|
789
|
+
const nodeCenterX = target.position.x + (target.width ?? 0) / 2;
|
|
790
|
+
const nodeCenterY = target.position.y + (target.height ?? 0) / 2;
|
|
791
|
+
const zoom = viewport?.zoom ?? lastViewportRef.current?.zoom ?? void 0;
|
|
792
|
+
try {
|
|
793
|
+
reactFlowInstance.setCenter(nodeCenterX, nodeCenterY, {
|
|
794
|
+
zoom,
|
|
795
|
+
duration: VIEWPORT_TUNING.centerDurationMs
|
|
796
|
+
});
|
|
797
|
+
window.requestAnimationFrame(() => {
|
|
798
|
+
setViewportIfChanged(reactFlowInstance.getViewport());
|
|
799
|
+
});
|
|
800
|
+
} catch {
|
|
801
|
+
}
|
|
802
|
+
}, [nodes, reactFlowInstance, viewport, setViewportIfChanged]);
|
|
803
|
+
return /* @__PURE__ */ jsx("div", { style: { width: "100%", height: "100%", minHeight: "100%" }, children: /* @__PURE__ */ jsx(
|
|
804
|
+
ReactFlow,
|
|
805
|
+
{
|
|
806
|
+
nodes,
|
|
807
|
+
edges: renderedEdges,
|
|
808
|
+
nodeTypes: resolvedNodeTypes,
|
|
809
|
+
defaultViewport: viewport ?? {
|
|
810
|
+
x: 0,
|
|
811
|
+
y: 0,
|
|
812
|
+
zoom: 1
|
|
813
|
+
},
|
|
814
|
+
viewport: viewport ?? void 0,
|
|
815
|
+
onNodesChange,
|
|
816
|
+
onEdgesChange,
|
|
817
|
+
onNodeDragStop,
|
|
818
|
+
onConnect,
|
|
819
|
+
onMove: handleMove,
|
|
820
|
+
onlyRenderVisibleElements: true,
|
|
821
|
+
onInit: setReactFlowInstance,
|
|
822
|
+
onMoveEnd: handleMoveEnd
|
|
823
|
+
}
|
|
824
|
+
) });
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
export { DesignerFlow as default };
|
|
828
|
+
//# sourceMappingURL=DesignerFlow.esm.js.map
|