@bian-womp/spark-workbench 0.2.83 → 0.2.85
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/lib/cjs/index.cjs +344 -238
- package/lib/cjs/index.cjs.map +1 -1
- package/lib/cjs/src/core/InMemoryWorkbench.d.ts +27 -28
- package/lib/cjs/src/core/InMemoryWorkbench.d.ts.map +1 -1
- package/lib/cjs/src/core/contracts.d.ts +4 -1
- package/lib/cjs/src/core/contracts.d.ts.map +1 -1
- package/lib/cjs/src/core/ui-extensions.d.ts +16 -7
- package/lib/cjs/src/core/ui-extensions.d.ts.map +1 -1
- package/lib/cjs/src/index.d.ts +2 -0
- package/lib/cjs/src/index.d.ts.map +1 -1
- package/lib/cjs/src/misc/DefaultNode.d.ts +0 -14
- package/lib/cjs/src/misc/DefaultNode.d.ts.map +1 -1
- package/lib/cjs/src/misc/DefaultNodeContent.d.ts +4 -0
- package/lib/cjs/src/misc/DefaultNodeContent.d.ts.map +1 -0
- package/lib/cjs/src/misc/DefaultNodeHeader.d.ts +15 -0
- package/lib/cjs/src/misc/DefaultNodeHeader.d.ts.map +1 -0
- package/lib/cjs/src/misc/WorkbenchCanvas.d.ts +2 -0
- package/lib/cjs/src/misc/WorkbenchCanvas.d.ts.map +1 -1
- package/lib/cjs/src/misc/context/WorkbenchContext.provider.d.ts.map +1 -1
- package/lib/cjs/src/misc/hooks.d.ts.map +1 -1
- package/lib/cjs/src/misc/mapping.d.ts +9 -2
- package/lib/cjs/src/misc/mapping.d.ts.map +1 -1
- package/lib/cjs/src/misc/merge-utils.d.ts +6 -1
- package/lib/cjs/src/misc/merge-utils.d.ts.map +1 -1
- package/lib/cjs/src/misc/types.d.ts +4 -0
- package/lib/cjs/src/misc/types.d.ts.map +1 -1
- package/lib/esm/index.js +346 -240
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/src/core/InMemoryWorkbench.d.ts +27 -28
- package/lib/esm/src/core/InMemoryWorkbench.d.ts.map +1 -1
- package/lib/esm/src/core/contracts.d.ts +4 -1
- package/lib/esm/src/core/contracts.d.ts.map +1 -1
- package/lib/esm/src/core/ui-extensions.d.ts +16 -7
- package/lib/esm/src/core/ui-extensions.d.ts.map +1 -1
- package/lib/esm/src/index.d.ts +2 -0
- package/lib/esm/src/index.d.ts.map +1 -1
- package/lib/esm/src/misc/DefaultNode.d.ts +0 -14
- package/lib/esm/src/misc/DefaultNode.d.ts.map +1 -1
- package/lib/esm/src/misc/DefaultNodeContent.d.ts +4 -0
- package/lib/esm/src/misc/DefaultNodeContent.d.ts.map +1 -0
- package/lib/esm/src/misc/DefaultNodeHeader.d.ts +15 -0
- package/lib/esm/src/misc/DefaultNodeHeader.d.ts.map +1 -0
- package/lib/esm/src/misc/WorkbenchCanvas.d.ts +2 -0
- package/lib/esm/src/misc/WorkbenchCanvas.d.ts.map +1 -1
- package/lib/esm/src/misc/context/WorkbenchContext.provider.d.ts.map +1 -1
- package/lib/esm/src/misc/hooks.d.ts.map +1 -1
- package/lib/esm/src/misc/mapping.d.ts +9 -2
- package/lib/esm/src/misc/mapping.d.ts.map +1 -1
- package/lib/esm/src/misc/merge-utils.d.ts +6 -1
- package/lib/esm/src/misc/merge-utils.d.ts.map +1 -1
- package/lib/esm/src/misc/types.d.ts +4 -0
- package/lib/esm/src/misc/types.d.ts.map +1 -1
- package/package.json +4 -4
package/lib/cjs/index.cjs
CHANGED
|
@@ -75,6 +75,13 @@ class DefaultUIExtensionRegistry {
|
|
|
75
75
|
getNodeContextMenuRenderer() {
|
|
76
76
|
return this.nodeContextMenuRenderer;
|
|
77
77
|
}
|
|
78
|
+
registerSelectionContextMenuRenderer(renderer) {
|
|
79
|
+
this.selectionContextMenuRenderer = renderer;
|
|
80
|
+
return this;
|
|
81
|
+
}
|
|
82
|
+
getSelectionContextMenuRenderer() {
|
|
83
|
+
return this.selectionContextMenuRenderer;
|
|
84
|
+
}
|
|
78
85
|
// Layout function overrides
|
|
79
86
|
registerEstimateNodeSize(override) {
|
|
80
87
|
this.estimateNodeSizeOverride = override;
|
|
@@ -126,6 +133,7 @@ class InMemoryWorkbench extends AbstractWorkbench {
|
|
|
126
133
|
this._def = { nodes: [], edges: [] };
|
|
127
134
|
this.listeners = new Map();
|
|
128
135
|
this.positions = {};
|
|
136
|
+
this.sizes = {};
|
|
129
137
|
this.selection = {
|
|
130
138
|
nodes: [],
|
|
131
139
|
edges: [],
|
|
@@ -151,9 +159,11 @@ class InMemoryWorkbench extends AbstractWorkbench {
|
|
|
151
159
|
const defNodeIds = new Set(this._def.nodes.map((n) => n.nodeId));
|
|
152
160
|
const defEdgeIds = new Set(this._def.edges.map((e) => e.id));
|
|
153
161
|
const filteredPositions = Object.fromEntries(Object.entries(this.positions).filter(([id]) => defNodeIds.has(id)));
|
|
162
|
+
const filteredSizes = Object.fromEntries(Object.entries(this.sizes).filter(([id]) => defNodeIds.has(id)));
|
|
154
163
|
const filteredNodes = this.selection.nodes.filter((id) => defNodeIds.has(id));
|
|
155
164
|
const filteredEdges = this.selection.edges.filter((id) => defEdgeIds.has(id));
|
|
156
165
|
this.positions = filteredPositions;
|
|
166
|
+
this.sizes = filteredSizes;
|
|
157
167
|
this.selection = { nodes: filteredNodes, edges: filteredEdges };
|
|
158
168
|
this.emit("graphChanged", { def: this._def });
|
|
159
169
|
this.refreshValidation();
|
|
@@ -210,8 +220,10 @@ class InMemoryWorkbench extends AbstractWorkbench {
|
|
|
210
220
|
params: node.params,
|
|
211
221
|
resolvedHandles: node.resolvedHandles,
|
|
212
222
|
});
|
|
213
|
-
if (
|
|
214
|
-
this.positions[id] =
|
|
223
|
+
if (options?.position)
|
|
224
|
+
this.positions[id] = options.position;
|
|
225
|
+
if (options?.size)
|
|
226
|
+
this.sizes[id] = options.size;
|
|
215
227
|
this.emit("graphChanged", {
|
|
216
228
|
def: this._def,
|
|
217
229
|
change: {
|
|
@@ -229,6 +241,7 @@ class InMemoryWorkbench extends AbstractWorkbench {
|
|
|
229
241
|
this._def.nodes = this._def.nodes.filter((n) => n.nodeId !== nodeId);
|
|
230
242
|
this._def.edges = this._def.edges.filter((e) => e.source.nodeId !== nodeId && e.target.nodeId !== nodeId);
|
|
231
243
|
delete this.positions[nodeId];
|
|
244
|
+
delete this.sizes[nodeId];
|
|
232
245
|
delete this.nodeNames[nodeId];
|
|
233
246
|
this.emit("graphChanged", {
|
|
234
247
|
def: this._def,
|
|
@@ -287,27 +300,38 @@ class InMemoryWorkbench extends AbstractWorkbench {
|
|
|
287
300
|
});
|
|
288
301
|
}
|
|
289
302
|
// Position and selection APIs for React Flow bridge
|
|
290
|
-
setPositions(
|
|
291
|
-
this.positions = { ...this.positions, ...
|
|
303
|
+
setPositions(positions, options) {
|
|
304
|
+
this.positions = { ...this.positions, ...positions };
|
|
305
|
+
this.emit("graphUiChanged", { change: { type: "moveNodes" }, ...options });
|
|
306
|
+
}
|
|
307
|
+
getPositions() {
|
|
308
|
+
return { ...this.positions };
|
|
309
|
+
}
|
|
310
|
+
setSizes(sizes, options) {
|
|
311
|
+
const updatedSizes = { ...this.sizes };
|
|
312
|
+
for (const [nodeId, size] of Object.entries(sizes)) {
|
|
313
|
+
if (size) {
|
|
314
|
+
updatedSizes[nodeId] = size;
|
|
315
|
+
}
|
|
316
|
+
else {
|
|
317
|
+
delete updatedSizes[nodeId];
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
this.sizes = updatedSizes;
|
|
292
321
|
this.emit("graphUiChanged", {
|
|
293
|
-
|
|
294
|
-
change: { type: "moveNodes" },
|
|
322
|
+
change: { type: "resizeNodes" },
|
|
295
323
|
...options,
|
|
296
324
|
});
|
|
297
325
|
}
|
|
298
|
-
|
|
299
|
-
return { ...this.
|
|
326
|
+
getSizes() {
|
|
327
|
+
return { ...this.sizes };
|
|
300
328
|
}
|
|
301
329
|
setSelectionInternal(sel, options) {
|
|
302
330
|
if (lod.isEqual(this.selection, sel))
|
|
303
331
|
return;
|
|
304
332
|
this.selection = { nodes: [...sel.nodes], edges: [...sel.edges] };
|
|
305
333
|
this.emit("selectionChanged", this.selection);
|
|
306
|
-
this.emit("graphUiChanged", {
|
|
307
|
-
def: this._def,
|
|
308
|
-
change: { type: "selection" },
|
|
309
|
-
...options,
|
|
310
|
-
});
|
|
334
|
+
this.emit("graphUiChanged", { change: { type: "selection" }, ...options });
|
|
311
335
|
}
|
|
312
336
|
setSelection(sel, options) {
|
|
313
337
|
this.setSelectionInternal(sel, options);
|
|
@@ -338,10 +362,7 @@ class InMemoryWorkbench extends AbstractWorkbench {
|
|
|
338
362
|
if (lod.isEqual(this.viewport, viewport))
|
|
339
363
|
return;
|
|
340
364
|
this.viewport = { ...viewport };
|
|
341
|
-
this.emit("graphUiChanged", {
|
|
342
|
-
def: this._def,
|
|
343
|
-
change: { type: "viewport" },
|
|
344
|
-
});
|
|
365
|
+
this.emit("graphUiChanged", { change: { type: "viewport" } });
|
|
345
366
|
}
|
|
346
367
|
getViewport() {
|
|
347
368
|
return this.viewport ? { ...this.viewport } : null;
|
|
@@ -353,6 +374,7 @@ class InMemoryWorkbench extends AbstractWorkbench {
|
|
|
353
374
|
const filteredNodes = this.selection.nodes.filter((id) => defNodeIds.has(id));
|
|
354
375
|
const filteredEdges = this.selection.edges.filter((id) => defEdgeIds.has(id));
|
|
355
376
|
const filteredNodeNames = Object.fromEntries(Object.entries(this.nodeNames).filter(([id]) => defNodeIds.has(id)));
|
|
377
|
+
const filteredSizes = Object.fromEntries(Object.entries(this.sizes).filter(([id]) => defNodeIds.has(id)));
|
|
356
378
|
return {
|
|
357
379
|
positions: Object.keys(filteredPositions).length > 0
|
|
358
380
|
? filteredPositions
|
|
@@ -367,6 +389,7 @@ class InMemoryWorkbench extends AbstractWorkbench {
|
|
|
367
389
|
nodeNames: Object.keys(filteredNodeNames).length > 0
|
|
368
390
|
? filteredNodeNames
|
|
369
391
|
: undefined,
|
|
392
|
+
sizes: Object.keys(filteredSizes).length > 0 ? filteredSizes : undefined,
|
|
370
393
|
};
|
|
371
394
|
}
|
|
372
395
|
setUIState(ui) {
|
|
@@ -381,12 +404,27 @@ class InMemoryWorkbench extends AbstractWorkbench {
|
|
|
381
404
|
edges: [...ui.selection.edges],
|
|
382
405
|
};
|
|
383
406
|
this.emit("selectionChanged", this.selection);
|
|
407
|
+
this.emit("graphUiChanged", {
|
|
408
|
+
change: { type: "selection" },
|
|
409
|
+
init: true,
|
|
410
|
+
});
|
|
384
411
|
}
|
|
385
412
|
if (ui.viewport) {
|
|
386
413
|
this.viewport = { ...ui.viewport };
|
|
414
|
+
this.emit("graphUiChanged", { change: { type: "viewport" }, init: true });
|
|
387
415
|
}
|
|
388
416
|
if (ui.nodeNames !== undefined) {
|
|
389
417
|
this.nodeNames = { ...ui.nodeNames };
|
|
418
|
+
for (const [nodeId, name] of Object.entries(ui.nodeNames)) {
|
|
419
|
+
this.emit("graphUiChanged", {
|
|
420
|
+
change: { type: "nodeName", nodeId, name },
|
|
421
|
+
init: true,
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
if (ui.sizes !== undefined) {
|
|
426
|
+
const defNodeIds = new Set(this._def.nodes.map((n) => n.nodeId));
|
|
427
|
+
this.sizes = Object.fromEntries(Object.entries(ui.sizes).filter(([id]) => defNodeIds.has(id)));
|
|
390
428
|
}
|
|
391
429
|
}
|
|
392
430
|
getRuntimeState() {
|
|
@@ -437,6 +475,7 @@ class InMemoryWorkbench extends AbstractWorkbench {
|
|
|
437
475
|
if (selection.nodes.length === 0)
|
|
438
476
|
return null;
|
|
439
477
|
const positions = this.getPositions();
|
|
478
|
+
const sizes = this.getSizes();
|
|
440
479
|
const selectedNodeSet = new Set(selection.nodes);
|
|
441
480
|
// Collect nodes to copy
|
|
442
481
|
const nodesToCopy = this.def.nodes.filter((n) => selectedNodeSet.has(n.nodeId));
|
|
@@ -448,15 +487,16 @@ class InMemoryWorkbench extends AbstractWorkbench {
|
|
|
448
487
|
let maxX = -Infinity;
|
|
449
488
|
let maxY = -Infinity;
|
|
450
489
|
nodesToCopy.forEach((node) => {
|
|
451
|
-
const pos = positions[node.nodeId]
|
|
452
|
-
const size = getNodeSize?.(node.nodeId, node.typeId)
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
490
|
+
const pos = positions[node.nodeId];
|
|
491
|
+
const size = sizes[node.nodeId] || getNodeSize?.(node.nodeId, node.typeId);
|
|
492
|
+
if (pos) {
|
|
493
|
+
minX = Math.min(minX, pos.x);
|
|
494
|
+
minY = Math.min(minY, pos.y);
|
|
495
|
+
if (size) {
|
|
496
|
+
maxX = Math.max(maxX, pos.x + size.width);
|
|
497
|
+
maxY = Math.max(maxY, pos.y + size.height);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
460
500
|
});
|
|
461
501
|
const bounds = { minX, minY, maxX, maxY };
|
|
462
502
|
const centerX = (bounds.minX + bounds.maxX) / 2;
|
|
@@ -466,7 +506,8 @@ class InMemoryWorkbench extends AbstractWorkbench {
|
|
|
466
506
|
const allInputs = runner.getInputs(this.def);
|
|
467
507
|
const selectedEdgeSet = new Set(selection.edges);
|
|
468
508
|
const copiedNodes = nodesToCopy.map((node) => {
|
|
469
|
-
const pos = positions[node.nodeId]
|
|
509
|
+
const pos = positions[node.nodeId];
|
|
510
|
+
const size = sizes[node.nodeId];
|
|
470
511
|
// Get all inbound edges for this node
|
|
471
512
|
const inboundEdges = this.def.edges.filter((e) => e.target.nodeId === node.nodeId);
|
|
472
513
|
// Build set of handles that have inbound edges
|
|
@@ -483,10 +524,13 @@ class InMemoryWorkbench extends AbstractWorkbench {
|
|
|
483
524
|
typeId: node.typeId,
|
|
484
525
|
params: node.params,
|
|
485
526
|
resolvedHandles: node.resolvedHandles,
|
|
486
|
-
position:
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
527
|
+
position: pos
|
|
528
|
+
? {
|
|
529
|
+
x: pos.x - centerX,
|
|
530
|
+
y: pos.y - centerY,
|
|
531
|
+
}
|
|
532
|
+
: undefined,
|
|
533
|
+
size,
|
|
490
534
|
inputs: inputsToCopy,
|
|
491
535
|
originalNodeId: node.nodeId,
|
|
492
536
|
};
|
|
@@ -521,6 +565,7 @@ class InMemoryWorkbench extends AbstractWorkbench {
|
|
|
521
565
|
if (selection.nodes.length === 0)
|
|
522
566
|
return [];
|
|
523
567
|
const positions = this.getPositions();
|
|
568
|
+
const sizes = this.getSizes();
|
|
524
569
|
const newNodes = [];
|
|
525
570
|
// Get inputs without bindings (literal values only)
|
|
526
571
|
const allInputs = runner.getInputs(this.def) || {};
|
|
@@ -529,7 +574,8 @@ class InMemoryWorkbench extends AbstractWorkbench {
|
|
|
529
574
|
const n = this.def.nodes.find((n) => n.nodeId === nodeId);
|
|
530
575
|
if (!n)
|
|
531
576
|
continue;
|
|
532
|
-
const pos = positions[nodeId]
|
|
577
|
+
const pos = positions[nodeId];
|
|
578
|
+
const size = sizes[nodeId];
|
|
533
579
|
const inboundHandles = new Set(this.def.edges
|
|
534
580
|
.filter((e) => e.target.nodeId === nodeId)
|
|
535
581
|
.map((e) => e.target.handle));
|
|
@@ -537,10 +583,11 @@ class InMemoryWorkbench extends AbstractWorkbench {
|
|
|
537
583
|
const newNodeId = this.addNode({
|
|
538
584
|
typeId: n.typeId,
|
|
539
585
|
params: n.params,
|
|
540
|
-
position: { x: pos.x + 24, y: pos.y + 24 },
|
|
541
586
|
resolvedHandles: n.resolvedHandles,
|
|
542
587
|
}, {
|
|
543
588
|
inputs: inputsWithoutBindings,
|
|
589
|
+
position: pos ? { x: pos.x + 24, y: pos.y + 24 } : undefined,
|
|
590
|
+
size,
|
|
544
591
|
copyOutputsFrom: nodeId,
|
|
545
592
|
dry: true,
|
|
546
593
|
});
|
|
@@ -587,8 +634,10 @@ class InMemoryWorkbench extends AbstractWorkbench {
|
|
|
587
634
|
const coerced = await coerceIfNeeded(outputTypeId, inType, unwrap(outputValue));
|
|
588
635
|
newNodeId = this.addNode({
|
|
589
636
|
typeId: singleTarget.nodeTypeId,
|
|
637
|
+
}, {
|
|
638
|
+
inputs: { [singleTarget.inputHandle]: coerced },
|
|
590
639
|
position: { x: pos.x + 180, y: pos.y },
|
|
591
|
-
}
|
|
640
|
+
});
|
|
592
641
|
}
|
|
593
642
|
else if (isArray && arrTarget) {
|
|
594
643
|
const nodeDesc = registry.nodes.get(arrTarget.nodeTypeId);
|
|
@@ -596,8 +645,10 @@ class InMemoryWorkbench extends AbstractWorkbench {
|
|
|
596
645
|
const coerced = await coerceIfNeeded(outputTypeId, inType, unwrap(outputValue));
|
|
597
646
|
newNodeId = this.addNode({
|
|
598
647
|
typeId: arrTarget.nodeTypeId,
|
|
648
|
+
}, {
|
|
599
649
|
position: { x: pos.x + 180, y: pos.y },
|
|
600
|
-
|
|
650
|
+
inputs: { [arrTarget.inputHandle]: coerced },
|
|
651
|
+
});
|
|
601
652
|
}
|
|
602
653
|
else if (isArray && elemTarget) {
|
|
603
654
|
const nodeDesc = registry.nodes.get(elemTarget.nodeTypeId);
|
|
@@ -613,8 +664,10 @@ class InMemoryWorkbench extends AbstractWorkbench {
|
|
|
613
664
|
const row = Math.floor(idx / COLS);
|
|
614
665
|
newNodeId = this.addNode({
|
|
615
666
|
typeId: elemTarget.nodeTypeId,
|
|
667
|
+
}, {
|
|
616
668
|
position: { x: pos.x + (col + 1) * DX, y: pos.y + row * DY },
|
|
617
|
-
|
|
669
|
+
inputs: { [elemTarget.inputHandle]: coercedItems[idx] },
|
|
670
|
+
});
|
|
618
671
|
}
|
|
619
672
|
}
|
|
620
673
|
if (newNodeId) {
|
|
@@ -636,7 +689,8 @@ class InMemoryWorkbench extends AbstractWorkbench {
|
|
|
636
689
|
const n = this.def.nodes.find((n) => n.nodeId === nodeId);
|
|
637
690
|
if (!n)
|
|
638
691
|
return undefined;
|
|
639
|
-
const pos = this.getPositions()[nodeId]
|
|
692
|
+
const pos = this.getPositions()[nodeId];
|
|
693
|
+
const size = this.getSizes()[nodeId];
|
|
640
694
|
// Get inputs without bindings (literal values only)
|
|
641
695
|
const allInputs = runner.getInputs(this.def)[nodeId] || {};
|
|
642
696
|
const inboundHandles = new Set(this.def.edges
|
|
@@ -646,10 +700,11 @@ class InMemoryWorkbench extends AbstractWorkbench {
|
|
|
646
700
|
const newNodeId = this.addNode({
|
|
647
701
|
typeId: n.typeId,
|
|
648
702
|
params: n.params,
|
|
649
|
-
position: { x: pos.x + 24, y: pos.y + 24 },
|
|
650
703
|
resolvedHandles: n.resolvedHandles,
|
|
651
704
|
}, {
|
|
652
705
|
inputs: inputsWithoutBindings,
|
|
706
|
+
position: pos ? { x: pos.x + 24, y: pos.y + 24 } : undefined,
|
|
707
|
+
size,
|
|
653
708
|
copyOutputsFrom: nodeId,
|
|
654
709
|
dry: true,
|
|
655
710
|
});
|
|
@@ -667,17 +722,19 @@ class InMemoryWorkbench extends AbstractWorkbench {
|
|
|
667
722
|
const n = this.def.nodes.find((n) => n.nodeId === nodeId);
|
|
668
723
|
if (!n)
|
|
669
724
|
return undefined;
|
|
670
|
-
const pos = this.getPositions()[nodeId]
|
|
725
|
+
const pos = this.getPositions()[nodeId];
|
|
726
|
+
const size = this.getSizes()[nodeId];
|
|
671
727
|
// Get all inputs (including those with bindings, since edges will be duplicated)
|
|
672
728
|
const inputs = runner.getInputs(this.def)[nodeId] || {};
|
|
673
729
|
// Add the duplicated node
|
|
674
730
|
const newNodeId = this.addNode({
|
|
675
731
|
typeId: n.typeId,
|
|
676
732
|
params: n.params,
|
|
677
|
-
position: { x: pos.x + 24, y: pos.y + 24 },
|
|
678
733
|
resolvedHandles: n.resolvedHandles,
|
|
679
734
|
}, {
|
|
680
735
|
inputs,
|
|
736
|
+
position: pos ? { x: pos.x + 24, y: pos.y + 24 } : undefined,
|
|
737
|
+
size,
|
|
681
738
|
copyOutputsFrom: nodeId,
|
|
682
739
|
dry: true,
|
|
683
740
|
});
|
|
@@ -711,12 +768,15 @@ class InMemoryWorkbench extends AbstractWorkbench {
|
|
|
711
768
|
typeId: nodeData.typeId,
|
|
712
769
|
params: nodeData.params,
|
|
713
770
|
resolvedHandles: nodeData.resolvedHandles,
|
|
714
|
-
position: {
|
|
715
|
-
x: nodeData.position.x + center.x,
|
|
716
|
-
y: nodeData.position.y + center.y,
|
|
717
|
-
},
|
|
718
771
|
}, {
|
|
719
772
|
inputs: nodeData.inputs,
|
|
773
|
+
position: nodeData.position
|
|
774
|
+
? {
|
|
775
|
+
x: nodeData.position.x + center.x,
|
|
776
|
+
y: nodeData.position.y + center.y,
|
|
777
|
+
}
|
|
778
|
+
: undefined,
|
|
779
|
+
size: nodeData.size,
|
|
720
780
|
copyOutputsFrom: nodeData.originalNodeId,
|
|
721
781
|
dry: true,
|
|
722
782
|
});
|
|
@@ -775,8 +835,7 @@ class InMemoryWorkbench extends AbstractWorkbench {
|
|
|
775
835
|
this.nodeNames[nodeId] = name.trim();
|
|
776
836
|
}
|
|
777
837
|
this.emit("graphUiChanged", {
|
|
778
|
-
|
|
779
|
-
change: { type: "nodeName", nodeId },
|
|
838
|
+
change: { type: "nodeName", nodeId, name },
|
|
780
839
|
...options,
|
|
781
840
|
});
|
|
782
841
|
}
|
|
@@ -2196,7 +2255,6 @@ function useWorkbenchBridge(wb) {
|
|
|
2196
2255
|
}, { commit: true });
|
|
2197
2256
|
}, [wb]);
|
|
2198
2257
|
const onNodesChange = React.useCallback((changes) => {
|
|
2199
|
-
// Apply position updates continuously, but mark commit only on drag end
|
|
2200
2258
|
const positions = {};
|
|
2201
2259
|
let commit = false;
|
|
2202
2260
|
changes.forEach((c) => {
|
|
@@ -2206,6 +2264,14 @@ function useWorkbenchBridge(wb) {
|
|
|
2206
2264
|
commit = true;
|
|
2207
2265
|
}
|
|
2208
2266
|
});
|
|
2267
|
+
const sizes = {};
|
|
2268
|
+
changes.forEach((c) => {
|
|
2269
|
+
if (c.type === "dimensions" && c.dimensions) {
|
|
2270
|
+
sizes[c.id] = c.dimensions;
|
|
2271
|
+
if (!c.resizing)
|
|
2272
|
+
commit = true;
|
|
2273
|
+
}
|
|
2274
|
+
});
|
|
2209
2275
|
// Derive next node selection from change set
|
|
2210
2276
|
const current = wb.getSelection();
|
|
2211
2277
|
const nextNodeIds = new Set(current.nodes);
|
|
@@ -2240,7 +2306,12 @@ function useWorkbenchBridge(wb) {
|
|
|
2240
2306
|
});
|
|
2241
2307
|
}
|
|
2242
2308
|
if (Object.keys(positions).length > 0) {
|
|
2243
|
-
wb.setPositions(positions, {
|
|
2309
|
+
wb.setPositions(positions, {
|
|
2310
|
+
commit: commit && !Object.keys(sizes).length,
|
|
2311
|
+
});
|
|
2312
|
+
}
|
|
2313
|
+
if (Object.keys(sizes).length > 0) {
|
|
2314
|
+
wb.setSizes(sizes, { commit });
|
|
2244
2315
|
}
|
|
2245
2316
|
}, [wb]);
|
|
2246
2317
|
const onEdgesDelete = React.useCallback((edges) => edges.forEach((e, idx) => wb.disconnect(e.id, { commit: idx === edges.length - 1 })), [wb]);
|
|
@@ -2430,7 +2501,7 @@ function useQueryParamString(key, defaultValue) {
|
|
|
2430
2501
|
return [val, set];
|
|
2431
2502
|
}
|
|
2432
2503
|
|
|
2433
|
-
function toReactFlow(def, positions, registry, opts) {
|
|
2504
|
+
function toReactFlow(def, positions, sizes, registry, opts) {
|
|
2434
2505
|
const EDGE_STYLE_MISSING = { stroke: "#f59e0b", strokeWidth: 2 }; // amber-500
|
|
2435
2506
|
const EDGE_STYLE_ERROR = { stroke: "#ef4444", strokeWidth: 2 };
|
|
2436
2507
|
const EDGE_STYLE_RUNNING = { stroke: "#3b82f6" };
|
|
@@ -2474,45 +2545,41 @@ function toReactFlow(def, positions, registry, opts) {
|
|
|
2474
2545
|
const createHandleBoundsFn = opts.ui?.getCreateHandleBounds() ?? createHandleBounds;
|
|
2475
2546
|
const createHandleLayoutFn = opts.ui?.getCreateHandleLayout() ?? createHandleLayout;
|
|
2476
2547
|
const estimateNodeSizeFn = opts.ui?.getEstimateNodeSize() ?? estimateNodeSize;
|
|
2477
|
-
const
|
|
2478
|
-
|
|
2479
|
-
const overrideSize = opts.getDefaultNodeSize?.(n.typeId);
|
|
2480
|
-
// If layoutNode is overridden, use it directly; otherwise use default with internal overrides
|
|
2481
|
-
const geom = layoutNodeOverride
|
|
2548
|
+
const computeLayout = (node, overrides) => {
|
|
2549
|
+
return layoutNodeOverride
|
|
2482
2550
|
? layoutNodeOverride({
|
|
2483
|
-
node
|
|
2551
|
+
node,
|
|
2484
2552
|
registry,
|
|
2485
2553
|
showValues: opts.showValues,
|
|
2486
|
-
overrides
|
|
2554
|
+
overrides,
|
|
2487
2555
|
})
|
|
2488
2556
|
: layoutNode({
|
|
2489
|
-
node
|
|
2557
|
+
node,
|
|
2490
2558
|
registry,
|
|
2491
2559
|
showValues: opts.showValues,
|
|
2492
|
-
overrides
|
|
2560
|
+
overrides,
|
|
2493
2561
|
}, {
|
|
2494
2562
|
estimateNodeSize: estimateNodeSizeFn,
|
|
2495
2563
|
createHandleBounds: createHandleBoundsFn,
|
|
2496
2564
|
createHandleLayout: createHandleLayoutFn,
|
|
2497
2565
|
});
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
typeId: sparkGraph.getInputTypeId(inputSource, id),
|
|
2501
|
-
}));
|
|
2502
|
-
const outputHandles = geom.outputOrder.map((id) => ({
|
|
2503
|
-
id,
|
|
2504
|
-
typeId: formatDeclaredTypeSignature(outputSource[id]),
|
|
2505
|
-
}));
|
|
2506
|
-
nodeHandleMap[n.nodeId] = {
|
|
2507
|
-
inputs: new Set(inputHandles.map((h) => h.id)),
|
|
2508
|
-
outputs: new Set(outputHandles.map((h) => h.id)),
|
|
2509
|
-
};
|
|
2510
|
-
// Append placeholder entries for any missing handles (below valid ones)
|
|
2566
|
+
};
|
|
2567
|
+
const calculateDimensionsWithMissingHandles = (geom, extraInputs, extraOutputs) => {
|
|
2511
2568
|
const baseLeftCount = geom.inputOrder.length;
|
|
2512
2569
|
const baseRightCount = geom.outputOrder.length;
|
|
2513
|
-
const
|
|
2514
|
-
const
|
|
2515
|
-
|
|
2570
|
+
const baseRows = Math.max(baseLeftCount, baseRightCount);
|
|
2571
|
+
const newRows = Math.max(baseLeftCount + extraInputs.length, baseRightCount + extraOutputs.length);
|
|
2572
|
+
return {
|
|
2573
|
+
baseLeftCount,
|
|
2574
|
+
baseRightCount,
|
|
2575
|
+
baseRows,
|
|
2576
|
+
newRows,
|
|
2577
|
+
width: geom.width,
|
|
2578
|
+
height: geom.height + Math.max(0, newRows - baseRows) * NODE_ROW_HEIGHT_PX,
|
|
2579
|
+
};
|
|
2580
|
+
};
|
|
2581
|
+
const createMissingHandleLayouts = (extraInputs, extraOutputs, baseLeftCount, baseRightCount) => {
|
|
2582
|
+
const left = extraInputs.map((id, i) => ({
|
|
2516
2583
|
...createHandleLayoutFn({
|
|
2517
2584
|
id,
|
|
2518
2585
|
type: "target",
|
|
@@ -2521,7 +2588,7 @@ function toReactFlow(def, positions, registry, opts) {
|
|
|
2521
2588
|
}),
|
|
2522
2589
|
missing: true,
|
|
2523
2590
|
}));
|
|
2524
|
-
const
|
|
2591
|
+
const right = extraOutputs.map((id, i) => ({
|
|
2525
2592
|
...createHandleLayoutFn({
|
|
2526
2593
|
id,
|
|
2527
2594
|
type: "source",
|
|
@@ -2530,36 +2597,58 @@ function toReactFlow(def, positions, registry, opts) {
|
|
|
2530
2597
|
}),
|
|
2531
2598
|
missing: true,
|
|
2532
2599
|
}));
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
];
|
|
2538
|
-
// Precompute handle bounds (including missing) so edges can render immediately
|
|
2539
|
-
const missingBoundsLeft = extraInputs.map((id, i) => createHandleBoundsFn({
|
|
2600
|
+
return [...left, ...right];
|
|
2601
|
+
};
|
|
2602
|
+
const createMissingHandleBounds = (extraInputs, extraOutputs, baseLeftCount, baseRightCount, nodeWidth) => {
|
|
2603
|
+
const left = extraInputs.map((id, i) => createHandleBoundsFn({
|
|
2540
2604
|
id,
|
|
2541
2605
|
type: "target",
|
|
2542
2606
|
position: react.Position.Left,
|
|
2543
2607
|
rowIndex: baseLeftCount + i,
|
|
2544
|
-
nodeWidth
|
|
2608
|
+
nodeWidth,
|
|
2545
2609
|
}));
|
|
2546
|
-
const
|
|
2610
|
+
const right = extraOutputs.map((id, i) => createHandleBoundsFn({
|
|
2547
2611
|
id,
|
|
2548
2612
|
type: "source",
|
|
2549
2613
|
position: react.Position.Right,
|
|
2550
2614
|
rowIndex: baseRightCount + i,
|
|
2551
|
-
nodeWidth
|
|
2615
|
+
nodeWidth,
|
|
2552
2616
|
}));
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
const
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
const
|
|
2617
|
+
return [...left, ...right];
|
|
2618
|
+
};
|
|
2619
|
+
const nodes = def.nodes.map((n) => {
|
|
2620
|
+
const { inputs: inputSource, outputs: outputSource } = computeEffectiveHandles(n, registry);
|
|
2621
|
+
const overrideSize = opts.getDefaultNodeSize?.(n.typeId);
|
|
2622
|
+
const customSize = sizes?.[n.nodeId];
|
|
2623
|
+
const sizeOverrides = customSize
|
|
2624
|
+
? { ...overrideSize, width: customSize.width, height: customSize.height }
|
|
2625
|
+
: overrideSize;
|
|
2626
|
+
const extraInputs = Array.from(missingInputsByNode[n.nodeId] || []);
|
|
2627
|
+
const extraOutputs = Array.from(missingOutputsByNode[n.nodeId] || []);
|
|
2628
|
+
const geom = computeLayout(n, sizeOverrides);
|
|
2629
|
+
const finalDims = calculateDimensionsWithMissingHandles(geom, extraInputs, extraOutputs);
|
|
2630
|
+
const renderWidth = customSize?.width ?? finalDims.width;
|
|
2631
|
+
const renderHeight = customSize?.height ?? finalDims.height;
|
|
2632
|
+
const initialGeom = customSize ? computeLayout(n, overrideSize) : geom;
|
|
2633
|
+
const initialDims = customSize
|
|
2634
|
+
? calculateDimensionsWithMissingHandles(initialGeom, extraInputs, extraOutputs)
|
|
2635
|
+
: finalDims;
|
|
2636
|
+
const inputHandles = geom.inputOrder.map((id) => ({
|
|
2637
|
+
id,
|
|
2638
|
+
typeId: sparkGraph.getInputTypeId(inputSource, id),
|
|
2639
|
+
}));
|
|
2640
|
+
const outputHandles = geom.outputOrder.map((id) => ({
|
|
2641
|
+
id,
|
|
2642
|
+
typeId: formatDeclaredTypeSignature(outputSource[id]),
|
|
2643
|
+
}));
|
|
2644
|
+
nodeHandleMap[n.nodeId] = {
|
|
2645
|
+
inputs: new Set(inputHandles.map((h) => h.id)),
|
|
2646
|
+
outputs: new Set(outputHandles.map((h) => h.id)),
|
|
2647
|
+
};
|
|
2648
|
+
const missingHandleLayouts = createMissingHandleLayouts(extraInputs, extraOutputs, finalDims.baseLeftCount, finalDims.baseRightCount);
|
|
2649
|
+
const handleLayout = [...geom.handleLayout, ...missingHandleLayouts];
|
|
2650
|
+
const missingHandleBounds = createMissingHandleBounds(extraInputs, extraOutputs, finalDims.baseLeftCount, finalDims.baseRightCount, renderWidth);
|
|
2651
|
+
const handles = [...geom.handles, ...missingHandleBounds];
|
|
2563
2652
|
return {
|
|
2564
2653
|
id: n.nodeId,
|
|
2565
2654
|
data: {
|
|
@@ -2573,8 +2662,10 @@ function toReactFlow(def, positions, registry, opts) {
|
|
|
2573
2662
|
])),
|
|
2574
2663
|
handleLayout,
|
|
2575
2664
|
showValues: opts.showValues,
|
|
2576
|
-
renderWidth
|
|
2577
|
-
renderHeight
|
|
2665
|
+
renderWidth,
|
|
2666
|
+
renderHeight,
|
|
2667
|
+
initialWidth: initialDims.width,
|
|
2668
|
+
initialHeight: initialDims.height,
|
|
2578
2669
|
inputValues: opts.inputs?.[n.nodeId],
|
|
2579
2670
|
inputDefaults: opts.inputDefaults?.[n.nodeId],
|
|
2580
2671
|
outputValues: opts.outputs?.[n.nodeId],
|
|
@@ -2592,11 +2683,13 @@ function toReactFlow(def, positions, registry, opts) {
|
|
|
2592
2683
|
selected: opts.selectedNodeIds
|
|
2593
2684
|
? opts.selectedNodeIds.has(n.nodeId)
|
|
2594
2685
|
: undefined,
|
|
2595
|
-
|
|
2596
|
-
|
|
2686
|
+
measured: {
|
|
2687
|
+
width: renderWidth,
|
|
2688
|
+
height: renderHeight,
|
|
2689
|
+
},
|
|
2597
2690
|
handles,
|
|
2598
|
-
width:
|
|
2599
|
-
height:
|
|
2691
|
+
width: renderWidth,
|
|
2692
|
+
height: renderHeight,
|
|
2600
2693
|
};
|
|
2601
2694
|
});
|
|
2602
2695
|
const edges = def.edges.map((e) => {
|
|
@@ -2803,22 +2896,30 @@ async function upload(parsed, wb, runner) {
|
|
|
2803
2896
|
/**
|
|
2804
2897
|
* Merge UI state from source into target, remapping node IDs using nodeIdMap.
|
|
2805
2898
|
* Preserves target state and adds/updates source state with remapped IDs.
|
|
2899
|
+
* If anchorPos and sourceDef are provided, positions will be offset relative to anchorPos.
|
|
2806
2900
|
*/
|
|
2807
|
-
function mergeUIState(targetUI, sourceUI, nodeIdMap) {
|
|
2901
|
+
function mergeUIState(targetUI, sourceUI, nodeIdMap, anchorPos, sourceDef) {
|
|
2808
2902
|
const result = {
|
|
2809
2903
|
...targetUI,
|
|
2810
2904
|
};
|
|
2811
2905
|
if (!sourceUI)
|
|
2812
2906
|
return result;
|
|
2813
|
-
// Merge positions
|
|
2907
|
+
// Merge positions with optional offset
|
|
2814
2908
|
if (sourceUI.positions) {
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2909
|
+
if (anchorPos && sourceDef) {
|
|
2910
|
+
// Apply offset when anchorPos and sourceDef are provided
|
|
2911
|
+
result.positions = sparkGraph.offsetImportedPositions(targetUI?.positions ?? {}, sourceUI.positions, sourceDef, nodeIdMap, anchorPos);
|
|
2912
|
+
}
|
|
2913
|
+
else {
|
|
2914
|
+
// Simple remapping without offset
|
|
2915
|
+
result.positions = {
|
|
2916
|
+
...(targetUI?.positions || {}),
|
|
2917
|
+
...Object.fromEntries(Object.entries(sourceUI.positions).map(([oldId, pos]) => [
|
|
2918
|
+
nodeIdMap[oldId] || oldId,
|
|
2919
|
+
pos,
|
|
2920
|
+
])),
|
|
2921
|
+
};
|
|
2922
|
+
}
|
|
2822
2923
|
}
|
|
2823
2924
|
// Merge selection: remap node IDs and edge IDs
|
|
2824
2925
|
if (sourceUI.selection) {
|
|
@@ -2841,6 +2942,15 @@ function mergeUIState(targetUI, sourceUI, nodeIdMap) {
|
|
|
2841
2942
|
])),
|
|
2842
2943
|
};
|
|
2843
2944
|
}
|
|
2945
|
+
if (sourceUI.sizes) {
|
|
2946
|
+
result.sizes = {
|
|
2947
|
+
...(targetUI?.sizes || {}),
|
|
2948
|
+
...Object.fromEntries(Object.entries(sourceUI.sizes).map(([oldId, size]) => [
|
|
2949
|
+
nodeIdMap[oldId] || oldId,
|
|
2950
|
+
size,
|
|
2951
|
+
])),
|
|
2952
|
+
};
|
|
2953
|
+
}
|
|
2844
2954
|
return result;
|
|
2845
2955
|
}
|
|
2846
2956
|
|
|
@@ -3098,7 +3208,9 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, overrides, uiVer
|
|
|
3098
3208
|
(type === "graphChanged" || type === "graphUiChanged")) {
|
|
3099
3209
|
const changeType = payload
|
|
3100
3210
|
.change?.type;
|
|
3101
|
-
if (changeType === "moveNode" ||
|
|
3211
|
+
if (changeType === "moveNode" ||
|
|
3212
|
+
changeType === "moveNodes" ||
|
|
3213
|
+
changeType === "resizeNodes")
|
|
3102
3214
|
return prev;
|
|
3103
3215
|
}
|
|
3104
3216
|
const nextNo = prev.length > 0 ? (prev[0]?.no ?? 0) + 1 : 1;
|
|
@@ -3507,6 +3619,9 @@ function WorkbenchProvider({ wb, runner, registry, setRegistry, overrides, uiVer
|
|
|
3507
3619
|
else if (changeType === "moveNodes") {
|
|
3508
3620
|
reason = "move-nodes";
|
|
3509
3621
|
}
|
|
3622
|
+
else if (changeType === "resizeNodes") {
|
|
3623
|
+
reason = "resize-nodes";
|
|
3624
|
+
}
|
|
3510
3625
|
else if (changeType === "selection") {
|
|
3511
3626
|
reason = "selection";
|
|
3512
3627
|
}
|
|
@@ -4264,103 +4379,6 @@ function Inspector({ debug, autoScroll, hideWorkbench, onAutoScrollChange, onHid
|
|
|
4264
4379
|
}, title: "Delete referenced edge", children: "Delete edge" }))] }, i))) })] }))] })) })] }), debug && (jsxRuntime.jsx("div", { className: "mt-3 flex-none min-h-0 h-[50%]", children: jsxRuntime.jsx(DebugEvents, { autoScroll: !!autoScroll, hideWorkbench: !!hideWorkbench, onAutoScrollChange: onAutoScrollChange, onHideWorkbenchChange: onHideWorkbenchChange }) }))] }));
|
|
4265
4380
|
}
|
|
4266
4381
|
|
|
4267
|
-
function NodeHandleItem({ kind, id, type, position, y, isConnectable, className, labelClassName, renderLabel, }) {
|
|
4268
|
-
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(react.Handle, { id: id, type: type, position: position, isConnectable: isConnectable, className: className, style: y !== undefined ? { top: y } : undefined }), renderLabel && (jsxRuntime.jsx("div", { className: labelClassName + (kind === "input" ? " left-2" : " right-2"), style: {
|
|
4269
|
-
top: (y ?? 0) - 8,
|
|
4270
|
-
...(kind === "input"
|
|
4271
|
-
? { right: "50%" }
|
|
4272
|
-
: { left: "50%", textAlign: "right" }),
|
|
4273
|
-
whiteSpace: "nowrap",
|
|
4274
|
-
overflow: "hidden",
|
|
4275
|
-
textOverflow: "ellipsis",
|
|
4276
|
-
}, children: renderLabel({ kind, id }) }))] }));
|
|
4277
|
-
}
|
|
4278
|
-
function NodeHandles({ data, isConnectable, getClassName, renderLabel, labelClassName = "absolute text-[11px] text-gray-700 dark:text-gray-300 pointer-events-none", }) {
|
|
4279
|
-
const layout = data.handleLayout ?? [];
|
|
4280
|
-
const byId = React.useMemo(() => {
|
|
4281
|
-
const m = new Map();
|
|
4282
|
-
for (const h of layout) {
|
|
4283
|
-
// Prefer namespaced key to disambiguate inputs/outputs that share id
|
|
4284
|
-
m.set(`${h.type}:${h.id}`, {
|
|
4285
|
-
position: h.position,
|
|
4286
|
-
y: h.y,
|
|
4287
|
-
type: h.type,
|
|
4288
|
-
missing: h.missing,
|
|
4289
|
-
});
|
|
4290
|
-
// Back-compat: also store by id-only if not already set
|
|
4291
|
-
if (!m.has(h.id))
|
|
4292
|
-
m.set(h.id, {
|
|
4293
|
-
position: h.position,
|
|
4294
|
-
y: h.y,
|
|
4295
|
-
type: h.type,
|
|
4296
|
-
missing: h.missing,
|
|
4297
|
-
});
|
|
4298
|
-
}
|
|
4299
|
-
return m;
|
|
4300
|
-
}, [layout]);
|
|
4301
|
-
const inputIds = React.useMemo(() => new Set((data.inputHandles ?? []).map((h) => h.id)), [data.inputHandles]);
|
|
4302
|
-
const outputIds = React.useMemo(() => new Set((data.outputHandles ?? []).map((h) => h.id)), [data.outputHandles]);
|
|
4303
|
-
const missingInputs = React.useMemo(() => (layout || []).filter((h) => h.type === "target" && (!inputIds.has(h.id) || h.missing)), [layout, inputIds]);
|
|
4304
|
-
const missingOutputs = React.useMemo(() => (layout || []).filter((h) => h.type === "source" && (!outputIds.has(h.id) || h.missing)), [layout, outputIds]);
|
|
4305
|
-
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [(data.inputHandles ?? []).map((h) => {
|
|
4306
|
-
const placed = byId.get(`target:${h.id}`) ?? byId.get(h.id);
|
|
4307
|
-
const position = placed?.position ?? react.Position.Left;
|
|
4308
|
-
const y = placed?.y;
|
|
4309
|
-
const cls = getClassName?.({ kind: "input", id: h.id, type: "target" }) ?? "";
|
|
4310
|
-
return (jsxRuntime.jsx(NodeHandleItem, { kind: "input", id: h.id, type: "target", position: position, y: y, isConnectable: isConnectable, className: cls, labelClassName: labelClassName, renderLabel: renderLabel }, h.id));
|
|
4311
|
-
}), missingInputs.map((h) => {
|
|
4312
|
-
const key = `missing-input:${h.id}`;
|
|
4313
|
-
const position = h.position ?? react.Position.Left;
|
|
4314
|
-
const y = h.y;
|
|
4315
|
-
const cls = "!w-3 !h-3 !bg-amber-400 !border-amber-500 wb-nodrag wb-nowheel";
|
|
4316
|
-
return (jsxRuntime.jsx(NodeHandleItem, { kind: "input", id: h.id, type: "target", position: position, y: y, isConnectable: false, className: `${cls} wb-nodrag wb-nowheel`, labelClassName: labelClassName, renderLabel: renderLabel }, key));
|
|
4317
|
-
}), (data.outputHandles ?? []).map((h) => {
|
|
4318
|
-
const placed = byId.get(`source:${h.id}`) ?? byId.get(h.id);
|
|
4319
|
-
const position = placed?.position ?? react.Position.Right;
|
|
4320
|
-
const y = placed?.y;
|
|
4321
|
-
const cls = getClassName?.({ kind: "output", id: h.id, type: "source" }) ?? "";
|
|
4322
|
-
return (jsxRuntime.jsx(NodeHandleItem, { kind: "output", id: h.id, type: "source", position: position, y: y, isConnectable: isConnectable, className: cls, labelClassName: labelClassName, renderLabel: renderLabel }, h.id));
|
|
4323
|
-
}), missingOutputs.map((h) => {
|
|
4324
|
-
const key = `missing-output:${h.id}`;
|
|
4325
|
-
const position = h.position ?? react.Position.Right;
|
|
4326
|
-
const y = h.y;
|
|
4327
|
-
const cls = "!w-3 !h-3 !bg-amber-400 !border-amber-500 !rounded-none wb-nodrag wb-nowheel";
|
|
4328
|
-
return (jsxRuntime.jsx(NodeHandleItem, { kind: "output", id: h.id, type: "source", position: position, y: y, isConnectable: false, className: cls, labelClassName: labelClassName, renderLabel: renderLabel }, key));
|
|
4329
|
-
})] }));
|
|
4330
|
-
}
|
|
4331
|
-
|
|
4332
|
-
const DefaultNode = React.memo(function DefaultNode({ id, data, selected, isConnectable, }) {
|
|
4333
|
-
const updateNodeInternals = react.useUpdateNodeInternals();
|
|
4334
|
-
const { typeId, showValues } = data;
|
|
4335
|
-
const inputEntries = data.inputHandles ?? [];
|
|
4336
|
-
const outputEntries = data.outputHandles ?? [];
|
|
4337
|
-
React.useEffect(() => {
|
|
4338
|
-
updateNodeInternals(id);
|
|
4339
|
-
}, [
|
|
4340
|
-
id,
|
|
4341
|
-
inputEntries.length,
|
|
4342
|
-
outputEntries.length,
|
|
4343
|
-
showValues,
|
|
4344
|
-
updateNodeInternals,
|
|
4345
|
-
]);
|
|
4346
|
-
const status = data.status ?? { activeRuns: 0 };
|
|
4347
|
-
const validation = data.validation ?? {
|
|
4348
|
-
inputs: [],
|
|
4349
|
-
outputs: [],
|
|
4350
|
-
issues: [],
|
|
4351
|
-
};
|
|
4352
|
-
const containerBorder = getNodeBorderClassNames({
|
|
4353
|
-
selected,
|
|
4354
|
-
status,
|
|
4355
|
-
validation,
|
|
4356
|
-
});
|
|
4357
|
-
return (jsxRuntime.jsxs("div", { className: cx("rounded-lg bg-white/50 !dark:bg-stone-900", containerBorder), style: {
|
|
4358
|
-
position: "relative",
|
|
4359
|
-
minWidth: typeof data.renderWidth === "number" ? data.renderWidth : undefined,
|
|
4360
|
-
minHeight: typeof data.renderHeight === "number" ? data.renderHeight : undefined,
|
|
4361
|
-
}, children: [jsxRuntime.jsx(DefaultNodeHeader, { id: id, typeId: typeId, validation: validation, showId: data.showValues }), jsxRuntime.jsx(DefaultNodeContent, { data: data, isConnectable: isConnectable })] }));
|
|
4362
|
-
});
|
|
4363
|
-
DefaultNode.displayName = "DefaultNode";
|
|
4364
4382
|
function DefaultNodeHeader({ id, typeId, title, validation, right, showId, onInvalidate, }) {
|
|
4365
4383
|
const ctx = useWorkbenchContext();
|
|
4366
4384
|
const [isEditing, setIsEditing] = React.useState(false);
|
|
@@ -4444,6 +4462,72 @@ function DefaultNodeHeader({ id, typeId, title, validation, right, showId, onInv
|
|
|
4444
4462
|
.map((v) => `${v.code}: ${v.message}`)
|
|
4445
4463
|
.join("; ") })), showId && jsxRuntime.jsxs("span", { className: "text-[10px] opacity-70", children: ["(", id, ")"] })] })] }));
|
|
4446
4464
|
}
|
|
4465
|
+
|
|
4466
|
+
function NodeHandleItem({ kind, id, type, position, y, isConnectable, className, labelClassName, renderLabel, }) {
|
|
4467
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(react.Handle, { id: id, type: type, position: position, isConnectable: isConnectable, className: className, style: y !== undefined ? { top: y } : undefined }), renderLabel && (jsxRuntime.jsx("div", { className: labelClassName + (kind === "input" ? " left-2" : " right-2"), style: {
|
|
4468
|
+
top: (y ?? 0) - 8,
|
|
4469
|
+
...(kind === "input"
|
|
4470
|
+
? { right: "50%" }
|
|
4471
|
+
: { left: "50%", textAlign: "right" }),
|
|
4472
|
+
whiteSpace: "nowrap",
|
|
4473
|
+
overflow: "hidden",
|
|
4474
|
+
textOverflow: "ellipsis",
|
|
4475
|
+
}, children: renderLabel({ kind, id }) }))] }));
|
|
4476
|
+
}
|
|
4477
|
+
function NodeHandles({ data, isConnectable, getClassName, renderLabel, labelClassName = "absolute text-[11px] text-gray-700 dark:text-gray-300 pointer-events-none", }) {
|
|
4478
|
+
const layout = data.handleLayout ?? [];
|
|
4479
|
+
const byId = React.useMemo(() => {
|
|
4480
|
+
const m = new Map();
|
|
4481
|
+
for (const h of layout) {
|
|
4482
|
+
// Prefer namespaced key to disambiguate inputs/outputs that share id
|
|
4483
|
+
m.set(`${h.type}:${h.id}`, {
|
|
4484
|
+
position: h.position,
|
|
4485
|
+
y: h.y,
|
|
4486
|
+
type: h.type,
|
|
4487
|
+
missing: h.missing,
|
|
4488
|
+
});
|
|
4489
|
+
// Back-compat: also store by id-only if not already set
|
|
4490
|
+
if (!m.has(h.id))
|
|
4491
|
+
m.set(h.id, {
|
|
4492
|
+
position: h.position,
|
|
4493
|
+
y: h.y,
|
|
4494
|
+
type: h.type,
|
|
4495
|
+
missing: h.missing,
|
|
4496
|
+
});
|
|
4497
|
+
}
|
|
4498
|
+
return m;
|
|
4499
|
+
}, [layout]);
|
|
4500
|
+
const inputIds = React.useMemo(() => new Set((data.inputHandles ?? []).map((h) => h.id)), [data.inputHandles]);
|
|
4501
|
+
const outputIds = React.useMemo(() => new Set((data.outputHandles ?? []).map((h) => h.id)), [data.outputHandles]);
|
|
4502
|
+
const missingInputs = React.useMemo(() => (layout || []).filter((h) => h.type === "target" && (!inputIds.has(h.id) || h.missing)), [layout, inputIds]);
|
|
4503
|
+
const missingOutputs = React.useMemo(() => (layout || []).filter((h) => h.type === "source" && (!outputIds.has(h.id) || h.missing)), [layout, outputIds]);
|
|
4504
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [(data.inputHandles ?? []).map((h) => {
|
|
4505
|
+
const placed = byId.get(`target:${h.id}`) ?? byId.get(h.id);
|
|
4506
|
+
const position = placed?.position ?? react.Position.Left;
|
|
4507
|
+
const y = placed?.y;
|
|
4508
|
+
const cls = getClassName?.({ kind: "input", id: h.id, type: "target" }) ?? "";
|
|
4509
|
+
return (jsxRuntime.jsx(NodeHandleItem, { kind: "input", id: h.id, type: "target", position: position, y: y, isConnectable: isConnectable, className: cls, labelClassName: labelClassName, renderLabel: renderLabel }, h.id));
|
|
4510
|
+
}), missingInputs.map((h) => {
|
|
4511
|
+
const key = `missing-input:${h.id}`;
|
|
4512
|
+
const position = h.position ?? react.Position.Left;
|
|
4513
|
+
const y = h.y;
|
|
4514
|
+
const cls = "!w-3 !h-3 !bg-amber-400 !border-amber-500 wb-nodrag wb-nowheel";
|
|
4515
|
+
return (jsxRuntime.jsx(NodeHandleItem, { kind: "input", id: h.id, type: "target", position: position, y: y, isConnectable: false, className: `${cls} wb-nodrag wb-nowheel`, labelClassName: labelClassName, renderLabel: renderLabel }, key));
|
|
4516
|
+
}), (data.outputHandles ?? []).map((h) => {
|
|
4517
|
+
const placed = byId.get(`source:${h.id}`) ?? byId.get(h.id);
|
|
4518
|
+
const position = placed?.position ?? react.Position.Right;
|
|
4519
|
+
const y = placed?.y;
|
|
4520
|
+
const cls = getClassName?.({ kind: "output", id: h.id, type: "source" }) ?? "";
|
|
4521
|
+
return (jsxRuntime.jsx(NodeHandleItem, { kind: "output", id: h.id, type: "source", position: position, y: y, isConnectable: isConnectable, className: cls, labelClassName: labelClassName, renderLabel: renderLabel }, h.id));
|
|
4522
|
+
}), missingOutputs.map((h) => {
|
|
4523
|
+
const key = `missing-output:${h.id}`;
|
|
4524
|
+
const position = h.position ?? react.Position.Right;
|
|
4525
|
+
const y = h.y;
|
|
4526
|
+
const cls = "!w-3 !h-3 !bg-amber-400 !border-amber-500 !rounded-none wb-nodrag wb-nowheel";
|
|
4527
|
+
return (jsxRuntime.jsx(NodeHandleItem, { kind: "output", id: h.id, type: "source", position: position, y: y, isConnectable: false, className: cls, labelClassName: labelClassName, renderLabel: renderLabel }, key));
|
|
4528
|
+
})] }));
|
|
4529
|
+
}
|
|
4530
|
+
|
|
4447
4531
|
function DefaultNodeContent({ data, isConnectable, }) {
|
|
4448
4532
|
const { showValues, inputValues, inputDefaults, outputValues, toString } = data;
|
|
4449
4533
|
const inputEntries = data.inputHandles ?? [];
|
|
@@ -4496,6 +4580,24 @@ function DefaultNodeContent({ data, isConnectable, }) {
|
|
|
4496
4580
|
} })] }));
|
|
4497
4581
|
}
|
|
4498
4582
|
|
|
4583
|
+
const DefaultNode = React.memo(function DefaultNode({ id, data, selected, isConnectable, }) {
|
|
4584
|
+
const nodeRef = React.useRef(null);
|
|
4585
|
+
const { typeId } = data;
|
|
4586
|
+
const status = data.status ?? { activeRuns: 0 };
|
|
4587
|
+
const validation = data.validation ?? {
|
|
4588
|
+
inputs: [],
|
|
4589
|
+
outputs: [],
|
|
4590
|
+
issues: [],
|
|
4591
|
+
};
|
|
4592
|
+
const containerBorder = getNodeBorderClassNames({
|
|
4593
|
+
selected,
|
|
4594
|
+
status,
|
|
4595
|
+
validation,
|
|
4596
|
+
});
|
|
4597
|
+
return (jsxRuntime.jsxs("div", { ref: nodeRef, className: cx("rounded-lg bg-white/50 !dark:bg-stone-900 w-full h-full relative", containerBorder), children: [jsxRuntime.jsx(react.NodeResizer, { isVisible: selected, minWidth: data.initialWidth, minHeight: data.initialHeight }), jsxRuntime.jsx(DefaultNodeHeader, { id: id, typeId: typeId, validation: validation, showId: data.showValues }), jsxRuntime.jsx(DefaultNodeContent, { data: data, isConnectable: isConnectable })] }));
|
|
4598
|
+
});
|
|
4599
|
+
DefaultNode.displayName = "DefaultNode";
|
|
4600
|
+
|
|
4499
4601
|
// Helper to format shortcut for current platform
|
|
4500
4602
|
function formatShortcut(shortcut) {
|
|
4501
4603
|
const isMac = typeof navigator !== "undefined" &&
|
|
@@ -4776,8 +4878,7 @@ const WorkbenchCanvas = React.forwardRef(({ showValues, toString, toElement, get
|
|
|
4776
4878
|
position: n.position,
|
|
4777
4879
|
type: n.type,
|
|
4778
4880
|
selected: n.selected,
|
|
4779
|
-
|
|
4780
|
-
initialHeight: n.initialHeight,
|
|
4881
|
+
measured: n.measured,
|
|
4781
4882
|
data: n.data && {
|
|
4782
4883
|
typeId: n.data.typeId,
|
|
4783
4884
|
inputHandles: n.data.inputHandles,
|
|
@@ -4811,11 +4912,18 @@ const WorkbenchCanvas = React.forwardRef(({ showValues, toString, toElement, get
|
|
|
4811
4912
|
React.useImperativeHandle(ref, () => ({
|
|
4812
4913
|
fitView: () => {
|
|
4813
4914
|
try {
|
|
4814
|
-
rfInstanceRef.current?.fitView(
|
|
4915
|
+
rfInstanceRef.current?.fitView();
|
|
4916
|
+
}
|
|
4917
|
+
catch (err) {
|
|
4918
|
+
console.warn("Failed to fit view", err);
|
|
4815
4919
|
}
|
|
4816
|
-
catch { }
|
|
4817
4920
|
},
|
|
4818
|
-
|
|
4921
|
+
setViewport: (viewport) => {
|
|
4922
|
+
if (rfInstanceRef.current) {
|
|
4923
|
+
rfInstanceRef.current.setViewport(lod.clone(viewport));
|
|
4924
|
+
}
|
|
4925
|
+
},
|
|
4926
|
+
}), []);
|
|
4819
4927
|
const { onConnect, onNodesChange, onEdgesChange, onEdgesDelete, onNodesDelete, } = useWorkbenchBridge(wb);
|
|
4820
4928
|
const ui = wb.getUI();
|
|
4821
4929
|
const { nodeTypes, resolveNodeType } = React.useMemo(() => {
|
|
@@ -4861,7 +4969,7 @@ const WorkbenchCanvas = React.forwardRef(({ showValues, toString, toElement, get
|
|
|
4861
4969
|
inputsWithDefaults[n.nodeId] = merged;
|
|
4862
4970
|
}
|
|
4863
4971
|
}
|
|
4864
|
-
const out = toReactFlow(wb.def, wb.getPositions(), registry, {
|
|
4972
|
+
const out = toReactFlow(wb.def, wb.getPositions(), wb.getSizes(), registry, {
|
|
4865
4973
|
showValues,
|
|
4866
4974
|
inputs: inputsWithDefaults,
|
|
4867
4975
|
inputDefaults: inputDefaultsMap,
|
|
@@ -5081,7 +5189,7 @@ const WorkbenchCanvas = React.forwardRef(({ showValues, toString, toElement, get
|
|
|
5081
5189
|
setNodeMenuOpen(false);
|
|
5082
5190
|
setSelectionMenuOpen(false);
|
|
5083
5191
|
};
|
|
5084
|
-
const addNodeAt = React.useCallback(async (typeId, opts) => wb.addNode({ typeId
|
|
5192
|
+
const addNodeAt = React.useCallback(async (typeId, opts) => wb.addNode({ typeId }, { inputs: opts.inputs, position: opts.position, commit: true }), [wb]);
|
|
5085
5193
|
const onCloseMenu = React.useCallback(() => {
|
|
5086
5194
|
setMenuOpen(false);
|
|
5087
5195
|
}, []);
|
|
@@ -5333,55 +5441,53 @@ const WorkbenchCanvas = React.forwardRef(({ showValues, toString, toElement, get
|
|
|
5333
5441
|
showToast,
|
|
5334
5442
|
]);
|
|
5335
5443
|
// Get custom renderers from UI extension registry (reactive to uiVersion changes)
|
|
5336
|
-
const { BackgroundRenderer, MinimapRenderer, ControlsRenderer, DefaultContextMenuRenderer, NodeContextMenuRenderer, connectionLineRenderer, } = React.useMemo(() => {
|
|
5444
|
+
const { BackgroundRenderer, MinimapRenderer, ControlsRenderer, DefaultContextMenuRenderer, NodeContextMenuRenderer, SelectionContextMenuRenderer, connectionLineRenderer, } = React.useMemo(() => {
|
|
5337
5445
|
return {
|
|
5338
5446
|
BackgroundRenderer: ui.getBackgroundRenderer(),
|
|
5339
5447
|
MinimapRenderer: ui.getMinimapRenderer(),
|
|
5340
5448
|
ControlsRenderer: ui.getControlsRenderer(),
|
|
5341
5449
|
DefaultContextMenuRenderer: ui.getDefaultContextMenuRenderer(),
|
|
5342
5450
|
NodeContextMenuRenderer: ui.getNodeContextMenuRenderer(),
|
|
5451
|
+
SelectionContextMenuRenderer: ui.getSelectionContextMenuRenderer(),
|
|
5343
5452
|
connectionLineRenderer: ui.getConnectionLineRenderer(),
|
|
5344
5453
|
};
|
|
5345
5454
|
}, [ui, uiVersion]);
|
|
5346
5455
|
const onMoveEnd = React.useCallback(() => {
|
|
5347
5456
|
if (rfInstanceRef.current) {
|
|
5348
5457
|
const viewport = rfInstanceRef.current.getViewport();
|
|
5349
|
-
const viewportData = lod.
|
|
5458
|
+
const viewportData = lod.clone(viewport);
|
|
5350
5459
|
wb.setViewport(viewportData);
|
|
5351
5460
|
}
|
|
5352
5461
|
}, [wb]);
|
|
5353
|
-
|
|
5462
|
+
// Sync viewport when workbench fires graphUiChanged with viewport event
|
|
5354
5463
|
React.useEffect(() => {
|
|
5355
|
-
|
|
5356
|
-
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
|
|
5360
|
-
|
|
5361
|
-
|
|
5362
|
-
|
|
5363
|
-
|
|
5364
|
-
|
|
5365
|
-
|
|
5366
|
-
|
|
5367
|
-
zoom: currentViewport.zoom,
|
|
5368
|
-
});
|
|
5369
|
-
}
|
|
5370
|
-
});
|
|
5464
|
+
const off = wb.on("graphUiChanged", (event) => {
|
|
5465
|
+
if (event.change?.type === "viewport" &&
|
|
5466
|
+
rfInstanceRef.current &&
|
|
5467
|
+
event.init) {
|
|
5468
|
+
const viewport = wb.getViewport();
|
|
5469
|
+
if (viewport) {
|
|
5470
|
+
rfInstanceRef.current.setViewport(lod.clone(viewport));
|
|
5471
|
+
}
|
|
5472
|
+
}
|
|
5473
|
+
});
|
|
5474
|
+
return () => off();
|
|
5475
|
+
}, [wb]);
|
|
5371
5476
|
return (jsxRuntime.jsxs("div", { className: "w-full h-full", onContextMenu: onContextMenu, children: [jsxRuntime.jsx(react.ReactFlowProvider, { children: jsxRuntime.jsxs(react.ReactFlow, { nodes: throttled.nodes, edges: throttled.edges, nodeTypes: nodeTypes, connectionLineComponent: connectionLineRenderer, selectionOnDrag: true, onInit: (inst) => {
|
|
5372
5477
|
rfInstanceRef.current = inst;
|
|
5373
5478
|
const savedViewport = wb.getViewport();
|
|
5374
5479
|
if (savedViewport) {
|
|
5375
|
-
|
|
5376
|
-
inst.setViewport(lod.pick(savedViewport, ["x", "y", "zoom"]));
|
|
5480
|
+
inst.setViewport(lod.clone(savedViewport));
|
|
5377
5481
|
}
|
|
5378
|
-
}, onConnect: onConnect, onEdgesChange: onEdgesChange, onEdgesDelete: onEdgesDelete, onNodesDelete: onNodesDelete, onNodesChange: onNodesChange, onMoveEnd: onMoveEnd, deleteKeyCode: ["Backspace", "Delete"], proOptions: { hideAttribution: true }, noDragClassName: "wb-nodrag", noWheelClassName: "wb-nowheel", noPanClassName: "wb-nopan",
|
|
5482
|
+
}, onConnect: onConnect, onEdgesChange: onEdgesChange, onEdgesDelete: onEdgesDelete, onNodesDelete: onNodesDelete, onNodesChange: onNodesChange, onMoveEnd: onMoveEnd, deleteKeyCode: ["Backspace", "Delete"], proOptions: { hideAttribution: true }, noDragClassName: "wb-nodrag", noWheelClassName: "wb-nowheel", noPanClassName: "wb-nopan", children: [BackgroundRenderer ? (jsxRuntime.jsx(BackgroundRenderer, {})) : (jsxRuntime.jsx(react.Background, { id: "workbench-canvas-background", variant: react.BackgroundVariant.Dots, gap: 12, size: 1 })), MinimapRenderer ? jsxRuntime.jsx(MinimapRenderer, {}) : jsxRuntime.jsx(react.MiniMap, {}), ControlsRenderer ? jsxRuntime.jsx(ControlsRenderer, {}) : jsxRuntime.jsx(react.Controls, {}), DefaultContextMenuRenderer ? (jsxRuntime.jsx(DefaultContextMenuRenderer, { open: menuOpen, clientPos: menuPos, handlers: defaultContextMenuHandlers, registry: registry, nodeIds: nodeIds, ...(enableKeyboardShortcuts !== false
|
|
5379
5483
|
? { enableKeyboardShortcuts, keyboardShortcuts }
|
|
5380
5484
|
: {}) })) : (jsxRuntime.jsx(DefaultContextMenu, { open: menuOpen, clientPos: menuPos, handlers: defaultContextMenuHandlers, registry: registry, nodeIds: nodeIds, enableKeyboardShortcuts: enableKeyboardShortcuts, keyboardShortcuts: keyboardShortcuts })), !!nodeAtMenu &&
|
|
5381
5485
|
nodeContextMenuHandlers &&
|
|
5382
5486
|
(NodeContextMenuRenderer ? (jsxRuntime.jsx(NodeContextMenuRenderer, { open: nodeMenuOpen, clientPos: nodeMenuPos, nodeId: nodeAtMenu, handlers: nodeContextMenuHandlers, canRunPull: canRunPull, bakeableOutputs: bakeableOutputs, ...(enableKeyboardShortcuts !== false
|
|
5383
5487
|
? { enableKeyboardShortcuts, keyboardShortcuts }
|
|
5384
|
-
: {}) })) : (jsxRuntime.jsx(NodeContextMenu, { open: nodeMenuOpen, clientPos: nodeMenuPos, nodeId: nodeAtMenu, handlers: nodeContextMenuHandlers, canRunPull: canRunPull, bakeableOutputs: bakeableOutputs, enableKeyboardShortcuts: enableKeyboardShortcuts, keyboardShortcuts: keyboardShortcuts }))), selectionMenuOpen &&
|
|
5488
|
+
: {}) })) : (jsxRuntime.jsx(NodeContextMenu, { open: nodeMenuOpen, clientPos: nodeMenuPos, nodeId: nodeAtMenu, handlers: nodeContextMenuHandlers, canRunPull: canRunPull, bakeableOutputs: bakeableOutputs, enableKeyboardShortcuts: enableKeyboardShortcuts, keyboardShortcuts: keyboardShortcuts }))), selectionMenuOpen &&
|
|
5489
|
+
selectionMenuPos &&
|
|
5490
|
+
(SelectionContextMenuRenderer ? (jsxRuntime.jsx(SelectionContextMenuRenderer, { open: selectionMenuOpen, clientPos: selectionMenuPos, handlers: selectionContextMenuHandlers, enableKeyboardShortcuts: enableKeyboardShortcuts, keyboardShortcuts: keyboardShortcuts })) : (jsxRuntime.jsx(SelectionContextMenu, { open: selectionMenuOpen, clientPos: selectionMenuPos, handlers: selectionContextMenuHandlers, enableKeyboardShortcuts: enableKeyboardShortcuts, keyboardShortcuts: keyboardShortcuts })))] }) }), toast && (jsxRuntime.jsx(KeyboardShortcutToast, { message: toast.message, onClose: hideToast }, toast.id))] }));
|
|
5385
5491
|
});
|
|
5386
5492
|
|
|
5387
5493
|
function WorkbenchStudioCanvas({ setRegistry, autoScroll, onAutoScrollChange, example, onExampleChange, engine, onEngineChange, backendKind, onBackendKindChange, httpBaseUrl, onHttpBaseUrlChange, wsUrl, onWsUrlChange, debug, onDebugChange, showValues, onShowValuesChange, hideWorkbench, onHideWorkbenchChange, overrides, onInit, onChange, }) {
|