@flowgram.ai/free-layout-core 0.1.0-alpha.11 → 0.1.0-alpha.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/dist/esm/{chunk-CTGO4RKX.js → chunk-E7ZUQ7LV.js} +1 -1
  2. package/dist/esm/chunk-E7ZUQ7LV.js.map +1 -0
  3. package/dist/esm/{chunk-242F2JCI.js → chunk-U2XMPOSL.js} +2 -1
  4. package/dist/esm/{chunk-242F2JCI.js.map → chunk-U2XMPOSL.js.map} +1 -1
  5. package/dist/esm/index.js +294 -99
  6. package/dist/esm/index.js.map +1 -1
  7. package/dist/esm/typings/index.js +2 -2
  8. package/dist/esm/typings/workflow-json.js +1 -1
  9. package/dist/esm/typings/workflow-line.js +1 -1
  10. package/dist/index.d.mts +22 -9
  11. package/dist/index.d.ts +22 -9
  12. package/dist/index.js +313 -116
  13. package/dist/index.js.map +1 -1
  14. package/dist/typings/index.d.mts +1 -1
  15. package/dist/typings/index.d.ts +1 -1
  16. package/dist/typings/index.js +1 -0
  17. package/dist/typings/index.js.map +1 -1
  18. package/dist/typings/workflow-drag.d.mts +1 -1
  19. package/dist/typings/workflow-drag.d.ts +1 -1
  20. package/dist/typings/workflow-json.d.mts +1 -1
  21. package/dist/typings/workflow-json.d.ts +1 -1
  22. package/dist/typings/workflow-json.js +1 -0
  23. package/dist/typings/workflow-json.js.map +1 -1
  24. package/dist/typings/workflow-line.d.mts +1 -1
  25. package/dist/typings/workflow-line.d.ts +1 -1
  26. package/dist/typings/workflow-line.js.map +1 -1
  27. package/dist/typings/workflow-node.d.mts +1 -1
  28. package/dist/typings/workflow-node.d.ts +1 -1
  29. package/dist/typings/workflow-registry.d.mts +2 -1
  30. package/dist/typings/workflow-registry.d.ts +2 -1
  31. package/dist/typings/workflow-registry.js.map +1 -1
  32. package/dist/{workflow-line-entity-SJhFU8K_.d.mts → workflow-line-entity-DSC3qPV1.d.mts} +128 -39
  33. package/dist/{workflow-line-entity-Z4omkx2m.d.ts → workflow-line-entity-I_VrhJ_t.d.ts} +128 -39
  34. package/package.json +9 -9
  35. package/dist/esm/chunk-CTGO4RKX.js.map +0 -1
package/dist/index.js CHANGED
@@ -59,6 +59,7 @@ __export(src_exports, {
59
59
  WorkflowSelectService: () => WorkflowSelectService,
60
60
  WorkflowSimpleLineContribution: () => WorkflowSimpleLineContribution,
61
61
  bindConfigEntity: () => import_core3.bindConfigEntity,
62
+ buildGroupJSON: () => buildGroupJSON,
62
63
  compose: () => import_utils.compose,
63
64
  composeAsync: () => import_utils.composeAsync,
64
65
  delay: () => import_utils4.delay,
@@ -105,7 +106,7 @@ var import_core25 = require("@flowgram.ai/core");
105
106
  var import_react2 = require("react");
106
107
  var import_reactive = require("@flowgram.ai/reactive");
107
108
  var import_node = require("@flowgram.ai/node");
108
- var import_document12 = require("@flowgram.ai/document");
109
+ var import_document13 = require("@flowgram.ai/document");
109
110
  var import_core21 = require("@flowgram.ai/core");
110
111
 
111
112
  // src/service/workflow-select-service.ts
@@ -117,6 +118,34 @@ var import_utils9 = require("@flowgram.ai/utils");
117
118
  var import_core3 = require("@flowgram.ai/core");
118
119
  var import_utils4 = require("@flowgram.ai/utils");
119
120
 
121
+ // src/utils/build-group-json.ts
122
+ var import_document = require("@flowgram.ai/document");
123
+ var buildGroupJSON = (json) => {
124
+ const { nodes, edges } = json;
125
+ const groupJSONs = nodes.filter(
126
+ (nodeJSON) => nodeJSON.type === import_document.FlowNodeBaseType.GROUP
127
+ );
128
+ const nodeJSONMap = new Map(nodes.map((n) => [n.id, n]));
129
+ const groupNodeJSONs = groupJSONs.map((groupJSON) => {
130
+ const groupBlocks = (groupJSON.data.blockIDs ?? []).map((blockID) => nodeJSONMap.get(blockID)).filter(Boolean);
131
+ const groupEdges = edges?.filter(
132
+ (edge) => groupBlocks.some((block) => block.id === edge.sourceNodeID || block.id === edge.targetNodeID)
133
+ );
134
+ const groupNodeJSON = {
135
+ ...groupJSON,
136
+ blocks: groupBlocks,
137
+ edges: groupEdges
138
+ };
139
+ return groupNodeJSON;
140
+ });
141
+ const groupBlockSet = new Set(groupJSONs.map((groupJSON) => groupJSON.data.blockIDs).flat());
142
+ const processedNodes = nodes.filter((nodeJSON) => !groupBlockSet.has(nodeJSON.id)).concat(groupNodeJSONs);
143
+ return {
144
+ nodes: processedNodes,
145
+ edges
146
+ };
147
+ };
148
+
120
149
  // src/utils/nanoid.ts
121
150
  var import_nanoid = require("nanoid");
122
151
  function nanoid(n) {
@@ -127,8 +156,8 @@ function nanoid(n) {
127
156
  var import_utils = require("@flowgram.ai/utils");
128
157
 
129
158
  // src/utils/fit-view.ts
130
- var import_core = require("@flowgram.ai/core");
131
159
  var import_utils2 = require("@flowgram.ai/utils");
160
+ var import_core = require("@flowgram.ai/core");
132
161
  var fitView = (doc, playgroundConfig, easing = true) => {
133
162
  const bounds = import_utils2.Rectangle.enlarge(
134
163
  doc.getAllNodes().map((node) => node.getData(import_core.TransformData).bounds)
@@ -170,8 +199,8 @@ function domReactToBounds(react) {
170
199
  }
171
200
 
172
201
  // src/entities/workflow-node-entity.ts
173
- var import_document = require("@flowgram.ai/document");
174
- var WorkflowNodeEntity = import_document.FlowNodeEntity;
202
+ var import_document2 = require("@flowgram.ai/document");
203
+ var WorkflowNodeEntity = import_document2.FlowNodeEntity;
175
204
 
176
205
  // src/entities/workflow-line-entity.ts
177
206
  var import_lodash_es2 = require("lodash-es");
@@ -180,26 +209,27 @@ var import_core8 = require("@flowgram.ai/core");
180
209
 
181
210
  // src/entity-datas/workflow-node-ports-data.ts
182
211
  var import_lodash_es = require("lodash-es");
183
- var import_document3 = require("@flowgram.ai/document");
212
+ var import_document4 = require("@flowgram.ai/document");
184
213
  var import_core5 = require("@flowgram.ai/core");
185
214
 
186
215
  // src/entities/workflow-port-entity.ts
187
216
  var import_utils5 = require("@flowgram.ai/utils");
188
- var import_document2 = require("@flowgram.ai/document");
217
+ var import_document3 = require("@flowgram.ai/document");
189
218
  var import_core4 = require("@flowgram.ai/core");
190
219
  var PORT_SIZE = 24;
191
220
  var WorkflowPortEntity = class extends import_core4.Entity {
192
- // relativePosition
193
221
  constructor(opts) {
194
222
  super(opts);
195
223
  this.portID = "";
196
- this._disabled = false;
197
224
  this._hasError = false;
198
225
  this._onErrorChangedEmitter = new import_utils5.Emitter();
199
226
  this.onErrorChanged = this._onErrorChangedEmitter.event;
200
227
  this.portID = opts.portID || "";
201
228
  this.portType = opts.type;
202
- this._disabled = opts.disabled ?? false;
229
+ this._disabled = opts.disabled;
230
+ this._offset = opts.offset;
231
+ this._location = opts.location;
232
+ this._size = opts.size;
203
233
  this.node = opts.node;
204
234
  this.updateTargetElement(opts.targetElement);
205
235
  this.toDispose.push(this.node.getData(import_core4.TransformData).onDataChange(() => this.fireChange()));
@@ -208,21 +238,25 @@ var WorkflowPortEntity = class extends import_core4.Entity {
208
238
  static getPortEntityId(node, portType, portID = "") {
209
239
  return getPortEntityId(node, portType, portID);
210
240
  }
241
+ get position() {
242
+ return this._location;
243
+ }
211
244
  // 获取连线是否为错误态
212
245
  get hasError() {
213
246
  return this._hasError;
214
247
  }
215
248
  // 设置连线的错误态,外部应使用 validate 进行更新
216
249
  set hasError(hasError) {
217
- this._hasError = hasError;
218
- this._onErrorChangedEmitter.fire();
250
+ if (hasError !== this._hasError) {
251
+ this._hasError = hasError;
252
+ this._onErrorChangedEmitter.fire();
253
+ }
219
254
  }
220
255
  validate() {
221
256
  const anyLineHasError = this.allLines.some((line) => {
222
257
  if (line.disposed || line.isHidden) {
223
258
  return false;
224
259
  }
225
- line.validateSelf();
226
260
  return line.hasError;
227
261
  });
228
262
  const isPortHasError = this.node.document.isErrorPort(this);
@@ -231,28 +265,65 @@ var WorkflowPortEntity = class extends import_core4.Entity {
231
265
  isErrorPort() {
232
266
  return this.node.document.isErrorPort(this, this.hasError);
233
267
  }
268
+ get location() {
269
+ if (this._location) {
270
+ return this._location;
271
+ }
272
+ if (this.portType === "input") {
273
+ return "left";
274
+ }
275
+ return "right";
276
+ }
234
277
  get point() {
235
278
  const { targetElement } = this;
236
- const { bounds } = this.node.getData(import_document2.FlowNodeTransformData);
279
+ const { bounds } = this.node.getData(import_document3.FlowNodeTransformData);
280
+ const location2 = this.location;
237
281
  if (targetElement) {
238
282
  const pos = domReactToBounds(targetElement.getBoundingClientRect()).center;
239
- return this.entityManager.getEntity(import_core4.PlaygroundConfigEntity).getPosFromMouseEvent({
283
+ const point2 = this.entityManager.getEntity(import_core4.PlaygroundConfigEntity).getPosFromMouseEvent({
240
284
  clientX: pos.x,
241
285
  clientY: pos.y
242
286
  });
287
+ return {
288
+ x: point2.x,
289
+ y: point2.y,
290
+ location: location2
291
+ };
243
292
  }
244
- if (this.portType === "input") {
245
- return bounds.leftCenter;
293
+ let point = { x: 0, y: 0 };
294
+ const offset = this._offset || { x: 0, y: 0 };
295
+ switch (location2) {
296
+ case "left":
297
+ point = bounds.leftCenter;
298
+ break;
299
+ case "top":
300
+ point = bounds.topCenter;
301
+ break;
302
+ case "right":
303
+ point = bounds.rightCenter;
304
+ break;
305
+ case "bottom":
306
+ point = bounds.bottomCenter;
307
+ break;
246
308
  }
247
- return bounds.rightCenter;
309
+ return {
310
+ x: point.x + offset.x,
311
+ y: point.y + offset.y,
312
+ location: location2
313
+ };
248
314
  }
249
315
  /**
250
- * 点的区域
316
+ * 端口热区
251
317
  */
252
318
  get bounds() {
253
319
  const { point } = this;
254
- const halfSize = PORT_SIZE / 2;
255
- return new import_utils5.Rectangle(point.x - halfSize, point.y - halfSize, PORT_SIZE, PORT_SIZE);
320
+ const size = this._size || { width: PORT_SIZE, height: PORT_SIZE };
321
+ return new import_utils5.Rectangle(
322
+ point.x - size.width / 2,
323
+ point.y - size.height / 2,
324
+ size.width,
325
+ size.height
326
+ );
256
327
  }
257
328
  isHovered(x, y) {
258
329
  return this.bounds.contains(x, y);
@@ -262,7 +333,7 @@ var WorkflowPortEntity = class extends import_core4.Entity {
262
333
  */
263
334
  get relativePosition() {
264
335
  const { point } = this;
265
- const { bounds } = this.node.getData(import_document2.FlowNodeTransformData);
336
+ const { bounds } = this.node.getData(import_document3.FlowNodeTransformData);
266
337
  return {
267
338
  x: point.x - bounds.x,
268
339
  y: point.y - bounds.y
@@ -319,6 +390,32 @@ var WorkflowPortEntity = class extends import_core4.Entity {
319
390
  });
320
391
  return lines;
321
392
  }
393
+ update(data) {
394
+ let changed = false;
395
+ if (data.targetElement !== this.targetElement) {
396
+ this.targetElement = data.targetElement;
397
+ changed = true;
398
+ }
399
+ if (data.location !== this._location) {
400
+ this._location = data.location;
401
+ changed = true;
402
+ }
403
+ if (import_utils5.Compare.isChanged(data.offset, this._offset)) {
404
+ this._offset = data.offset;
405
+ changed = true;
406
+ }
407
+ if (import_utils5.Compare.isChanged(data.size, this._size)) {
408
+ this._size = data.size;
409
+ changed = true;
410
+ }
411
+ if (data.disabled !== this._disabled) {
412
+ this._disabled = data.disabled;
413
+ changed = true;
414
+ }
415
+ if (changed) {
416
+ this.fireChange();
417
+ }
418
+ }
322
419
  dispose() {
323
420
  this.lines.forEach((l) => l.dispose());
324
421
  super.dispose();
@@ -357,22 +454,31 @@ var WorkflowNodePortsData = class extends import_core5.EntityData {
357
454
  return {};
358
455
  }
359
456
  /**
360
- * 更新静态的 ports 数据
457
+ * Update all ports data, includes static ports and dynamic ports
458
+ * @param ports
361
459
  */
362
- updateStaticPorts(ports) {
460
+ updateAllPorts(ports) {
363
461
  const meta = this.entity.getNodeMeta();
364
- this._staticPorts = ports;
462
+ if (ports) {
463
+ this._staticPorts = ports;
464
+ }
365
465
  if (meta.useDynamicPort) {
366
466
  this.updateDynamicPorts();
367
467
  } else {
368
468
  this.updatePorts(this._staticPorts);
369
469
  }
370
470
  }
471
+ /**
472
+ * @deprecated use `updateAllPorts` instead
473
+ */
474
+ updateStaticPorts(ports) {
475
+ this.updateAllPorts(ports);
476
+ }
371
477
  /**
372
478
  * 动态计算点位,通过 dom 的 data-port-key
373
479
  */
374
480
  updateDynamicPorts() {
375
- const domNode = this.entity.getData(import_document3.FlowNodeRenderData).node;
481
+ const domNode = this.entity.getData(import_document4.FlowNodeRenderData).node;
376
482
  const elements = domNode.querySelectorAll("[data-port-id]");
377
483
  const staticPorts = this._staticPorts;
378
484
  const dynamicPorts = [];
@@ -416,7 +522,6 @@ var WorkflowNodePortsData = class extends import_core5.EntityData {
416
522
  port.allLines.forEach((line) => {
417
523
  line.validate();
418
524
  });
419
- port.validate();
420
525
  });
421
526
  }
422
527
  /**
@@ -507,9 +612,7 @@ var WorkflowNodePortsData = class extends import_core5.EntityData {
507
612
  */
508
613
  updatePortEntity(portInfo) {
509
614
  const portEntity = this.getOrCreatePortEntity(portInfo);
510
- if (portInfo.targetElement) {
511
- portEntity.updateTargetElement(portInfo.targetElement);
512
- }
615
+ portEntity.update(portInfo);
513
616
  return portEntity;
514
617
  }
515
618
  };
@@ -547,6 +650,9 @@ var _WorkflowNodeLinesData = class _WorkflowNodeLinesData extends import_core6.E
547
650
  get outputLines() {
548
651
  return this.data.outputLines;
549
652
  }
653
+ get allLines() {
654
+ return this.data.inputLines.concat(this.data.outputLines);
655
+ }
550
656
  /**
551
657
  * 输入节点
552
658
  */
@@ -647,8 +753,8 @@ var WorkflowLineRenderData = class extends import_core7.EntityData {
647
753
  version: "",
648
754
  contributions: /* @__PURE__ */ new Map(),
649
755
  position: {
650
- from: { x: 0, y: 0 },
651
- to: { x: 0, y: 0 }
756
+ from: { x: 0, y: 0, location: "right" },
757
+ to: { x: 0, y: 0, location: "left" }
652
758
  }
653
759
  };
654
760
  }
@@ -694,16 +800,23 @@ var WorkflowLineRenderData = class extends import_core7.EntityData {
694
800
  */
695
801
  updatePosition() {
696
802
  this.data.position.from = this.entity.from.getData(WorkflowNodePortsData).getOutputPoint(this.entity.info.fromPort);
697
- this.data.position.to = this.entity.info.drawingTo ?? this.entity.to?.getData(WorkflowNodePortsData)?.getInputPoint(this.entity.info.toPort) ?? {
698
- x: this.data.position.from.x,
699
- y: this.data.position.from.y
700
- };
803
+ if (this.entity.info.drawingTo) {
804
+ this.data.position.to = this.entity.info.drawingTo;
805
+ } else {
806
+ this.data.position.to = this.entity.to?.getData(WorkflowNodePortsData)?.getInputPoint(this.entity.info.toPort) ?? {
807
+ x: this.data.position.from.x,
808
+ y: this.data.position.from.y,
809
+ location: this.data.position.from.location === "right" ? "left" : "top"
810
+ };
811
+ }
701
812
  this.data.version = [
702
813
  this.lineType,
703
814
  this.data.position.from.x,
704
815
  this.data.position.from.y,
816
+ this.data.position.from.location,
705
817
  this.data.position.to.x,
706
- this.data.position.to.y
818
+ this.data.position.to.y,
819
+ this.data.position.to.location
707
820
  ].join("-");
708
821
  }
709
822
  get currentLine() {
@@ -733,13 +846,16 @@ var POINT_RADIUS = 10;
733
846
  var _WorkflowLineEntity = class _WorkflowLineEntity extends import_core8.Entity {
734
847
  constructor(opts) {
735
848
  super(opts);
849
+ this._onLineDataChangeEmitter = new import_utils8.Emitter();
850
+ this.onLineDataChange = this._onLineDataChangeEmitter.event;
736
851
  this._uiState = {
737
852
  hasError: false,
738
853
  flowing: false,
739
854
  disabled: false,
740
- vertical: false,
741
855
  hideArrow: false,
742
856
  reverse: false,
857
+ shrink: 10,
858
+ curvature: 0.25,
743
859
  highlightColor: "",
744
860
  lockedColor: ""
745
861
  };
@@ -757,11 +873,21 @@ var _WorkflowLineEntity = class _WorkflowLineEntity extends import_core8.Entity
757
873
  to: opts.to,
758
874
  drawingTo: opts.drawingTo,
759
875
  fromPort: opts.fromPort,
760
- toPort: opts.toPort
876
+ toPort: opts.toPort,
877
+ data: opts.data
761
878
  });
762
879
  if (opts.drawingTo) {
763
880
  this.isDrawing = true;
764
881
  }
882
+ this.onEntityChange(() => {
883
+ this.fromPort?.validate();
884
+ this.toPort?.validate();
885
+ });
886
+ this.onDispose(() => {
887
+ this.fromPort?.validate();
888
+ this.toPort?.validate();
889
+ });
890
+ this.toDispose.push(this._onLineDataChangeEmitter);
765
891
  }
766
892
  /**
767
893
  * 转成线条 id
@@ -804,9 +930,13 @@ var _WorkflowLineEntity = class _WorkflowLineEntity extends import_core8.Entity
804
930
  * 更新线条扩展数据
805
931
  * @param data
806
932
  */
807
- set lineData(data) {
808
- this._lineData = data;
809
- this.fireChange();
933
+ set lineData(newValue) {
934
+ const oldValue = this._lineData;
935
+ if (!(0, import_lodash_es2.isEqual)(oldValue, newValue)) {
936
+ this._lineData = newValue;
937
+ this._onLineDataChangeEmitter.fire({ oldValue, newValue });
938
+ this.fireChange();
939
+ }
810
940
  }
811
941
  /**
812
942
  * 获取线条的前置节点
@@ -829,20 +959,17 @@ var _WorkflowLineEntity = class _WorkflowLineEntity extends import_core8.Entity
829
959
  }
830
960
  /**
831
961
  * 获取是否 testrun processing
832
- * @deprecated use `uiState.flowing` instead
962
+ * @deprecated use `flowing` instead
833
963
  */
834
964
  get processing() {
835
965
  return this._uiState.flowing;
836
966
  }
837
967
  /**
838
968
  * 设置 testrun processing 状态
839
- * @deprecated use `uiState.flowing` instead
969
+ * @deprecated use `flowing` instead
840
970
  */
841
971
  set processing(status) {
842
- if (this._uiState.flowing !== status) {
843
- this._uiState.flowing = status;
844
- this.fireChange();
845
- }
972
+ this.flowing = status;
846
973
  }
847
974
  // 获取连线是否为错误态
848
975
  get hasError() {
@@ -867,11 +994,11 @@ var _WorkflowLineEntity = class _WorkflowLineEntity extends import_core8.Entity
867
994
  if (this.toPort === toPort) {
868
995
  return;
869
996
  }
997
+ const prePort = this.toPort;
870
998
  if (toPort && toPort.portType === "input" && this.linesManager.canAddLine(this.fromPort, toPort, true)) {
871
999
  const { node, portID } = toPort;
872
1000
  this._to = node;
873
1001
  this.info.drawingTo = void 0;
874
- this.info.isDefaultLine = false;
875
1002
  this.info.to = node.id;
876
1003
  this.info.toPort = portID;
877
1004
  } else {
@@ -879,6 +1006,9 @@ var _WorkflowLineEntity = class _WorkflowLineEntity extends import_core8.Entity
879
1006
  this.info.to = void 0;
880
1007
  this.info.toPort = "";
881
1008
  }
1009
+ if (prePort) {
1010
+ prePort.validate();
1011
+ }
882
1012
  this.fireChange();
883
1013
  }
884
1014
  /**
@@ -893,7 +1023,6 @@ var _WorkflowLineEntity = class _WorkflowLineEntity extends import_core8.Entity
893
1023
  }
894
1024
  if (!oldDrawingTo || pos.x !== oldDrawingTo.x || pos.y !== oldDrawingTo.y) {
895
1025
  this.info.to = void 0;
896
- this.info.isDefaultLine = false;
897
1026
  this.info.drawingTo = pos;
898
1027
  this.fireChange();
899
1028
  }
@@ -959,13 +1088,25 @@ var _WorkflowLineEntity = class _WorkflowLineEntity extends import_core8.Entity
959
1088
  get flowing() {
960
1089
  return this.linesManager.isFlowingLine(this, this.uiState.flowing);
961
1090
  }
1091
+ set flowing(flowing) {
1092
+ if (this._uiState.flowing !== flowing) {
1093
+ this._uiState.flowing = flowing;
1094
+ this.fireChange();
1095
+ }
1096
+ }
962
1097
  /** 是否禁用 */
963
1098
  get disabled() {
964
1099
  return this.linesManager.isDisabledLine(this, this.uiState.disabled);
965
1100
  }
966
1101
  /** 是否竖向 */
967
1102
  get vertical() {
968
- return this.linesManager.isVerticalLine(this, this.uiState.vertical);
1103
+ const fromLocation = this.fromPort.location;
1104
+ const toLocation = this.toPort?.location;
1105
+ if (toLocation) {
1106
+ return toLocation === "top";
1107
+ } else {
1108
+ return fromLocation === "bottom";
1109
+ }
969
1110
  }
970
1111
  /** 获取线条渲染器类型 */
971
1112
  get renderType() {
@@ -973,7 +1114,7 @@ var _WorkflowLineEntity = class _WorkflowLineEntity extends import_core8.Entity
973
1114
  }
974
1115
  /** 获取线条样式 */
975
1116
  get className() {
976
- return this.linesManager.setLineClassName(this) ?? "";
1117
+ return [this.linesManager.setLineClassName(this), this._uiState.className].filter((s) => !!s).join(" ");
977
1118
  }
978
1119
  get color() {
979
1120
  return this.linesManager.getLineColor(this);
@@ -987,16 +1128,18 @@ var _WorkflowLineEntity = class _WorkflowLineEntity extends import_core8.Entity
987
1128
  this.info = info;
988
1129
  this._from = this.document.getNode(info.from);
989
1130
  this._to = info.to ? this.document.getNode(info.to) : void 0;
1131
+ this._lineData = info.data;
990
1132
  this.fireChange();
991
1133
  }
992
1134
  }
993
1135
  // 校验连线是否为错误态
994
1136
  validate() {
995
- const { fromPort, toPort } = this;
996
1137
  this.validateSelf();
997
- fromPort?.validate();
998
- toPort?.validate();
999
1138
  }
1139
+ /**
1140
+ * use `validate` instead
1141
+ * @deprecated
1142
+ */
1000
1143
  validateSelf() {
1001
1144
  const { fromPort, toPort } = this;
1002
1145
  if (fromPort) {
@@ -1215,20 +1358,20 @@ WorkflowHoverService = __decorateClass([
1215
1358
  var import_nanoid3 = require("nanoid");
1216
1359
  var import_inversify6 = require("inversify");
1217
1360
  var import_utils16 = require("@flowgram.ai/utils");
1218
- var import_document8 = require("@flowgram.ai/document");
1219
1361
  var import_document9 = require("@flowgram.ai/document");
1362
+ var import_document10 = require("@flowgram.ai/document");
1220
1363
  var import_core15 = require("@flowgram.ai/core");
1221
1364
 
1222
1365
  // src/workflow-lines-manager.ts
1223
1366
  var import_lodash_es3 = require("lodash-es");
1224
1367
  var import_inversify3 = require("inversify");
1225
1368
  var import_utils12 = require("@flowgram.ai/utils");
1226
- var import_document5 = require("@flowgram.ai/document");
1369
+ var import_document6 = require("@flowgram.ai/document");
1227
1370
  var import_core12 = require("@flowgram.ai/core");
1228
1371
 
1229
1372
  // src/workflow-document-option.ts
1230
1373
  var import_form_core2 = require("@flowgram.ai/form-core");
1231
- var import_document4 = require("@flowgram.ai/document");
1374
+ var import_document5 = require("@flowgram.ai/document");
1232
1375
  var import_core11 = require("@flowgram.ai/core");
1233
1376
 
1234
1377
  // src/utils/flow-node-form-data.ts
@@ -1242,6 +1385,7 @@ var WorkflowContentChangeType = /* @__PURE__ */ ((WorkflowContentChangeType2) =>
1242
1385
  WorkflowContentChangeType2["NODE_DATA_CHANGE"] = "NODE_DATA_CHANGE";
1243
1386
  WorkflowContentChangeType2["ADD_LINE"] = "ADD_LINE";
1244
1387
  WorkflowContentChangeType2["DELETE_LINE"] = "DELETE_LINE";
1388
+ WorkflowContentChangeType2["LINE_DATA_CHANGE"] = "LINE_DATA_CHANGE";
1245
1389
  WorkflowContentChangeType2["META_CHANGE"] = "META_CHANGE";
1246
1390
  return WorkflowContentChangeType2;
1247
1391
  })(WorkflowContentChangeType || {});
@@ -1320,7 +1464,7 @@ var WorkflowDocumentOptionsDefault = {
1320
1464
  const nodeMeta = node.getNodeMeta();
1321
1465
  const subCanvas = nodeMeta.subCanvas?.(node);
1322
1466
  if (subCanvas?.isCanvas === false) {
1323
- const canvasNodeTransform = subCanvas.canvasNode.getData(import_document4.FlowNodeTransformData);
1467
+ const canvasNodeTransform = subCanvas.canvasNode.getData(import_document5.FlowNodeTransformData);
1324
1468
  const { x, y } = canvasNodeTransform.transform.position;
1325
1469
  metaData.canvasPosition = { x, y };
1326
1470
  }
@@ -1415,6 +1559,9 @@ var WorkflowLinesManager = class {
1415
1559
  WorkflowLineEntity.portInfoToLineId(portInfo)
1416
1560
  );
1417
1561
  }
1562
+ getLineById(id) {
1563
+ return this.entityManager.getEntityById(id);
1564
+ }
1418
1565
  replaceLine(oldPortInfo, newPortInfo) {
1419
1566
  const oldLine = this.getLine(oldPortInfo);
1420
1567
  if (oldLine) {
@@ -1423,7 +1570,7 @@ var WorkflowLinesManager = class {
1423
1570
  return this.createLine(newPortInfo);
1424
1571
  }
1425
1572
  createLine(options) {
1426
- const { from, to, drawingTo, fromPort, toPort } = options;
1573
+ const { from, to, drawingTo, fromPort, toPort, data } = options;
1427
1574
  const available = Boolean(from && to);
1428
1575
  const key = options.key || WorkflowLineEntity.portInfoToLineId(options);
1429
1576
  let line = this.entityManager.getEntityById(key);
@@ -1446,7 +1593,8 @@ var WorkflowLinesManager = class {
1446
1593
  fromPort,
1447
1594
  toPort,
1448
1595
  to,
1449
- drawingTo
1596
+ drawingTo,
1597
+ data
1450
1598
  });
1451
1599
  this.registerData(line);
1452
1600
  fromNode.addLine(line);
@@ -1457,7 +1605,6 @@ var WorkflowLinesManager = class {
1457
1605
  }
1458
1606
  fromNode.removeLine(line);
1459
1607
  toNode?.removeLine(line);
1460
- line.validate();
1461
1608
  });
1462
1609
  line.onDispose(() => {
1463
1610
  if (available) {
@@ -1468,6 +1615,14 @@ var WorkflowLinesManager = class {
1468
1615
  });
1469
1616
  }
1470
1617
  });
1618
+ line.onLineDataChange(({ oldValue }) => {
1619
+ this.onAvailableLinesChangeEmitter.fire({
1620
+ type: "LINE_DATA_CHANGE" /* LINE_DATA_CHANGE */,
1621
+ toJSON: () => line.toJSON(),
1622
+ oldValue,
1623
+ entity: line
1624
+ });
1625
+ });
1471
1626
  if (available) {
1472
1627
  this.onAvailableLinesChangeEmitter.fire({
1473
1628
  type: "ADD_LINE" /* ADD_LINE */,
@@ -1531,12 +1686,6 @@ var WorkflowLinesManager = class {
1531
1686
  }
1532
1687
  return defaultValue;
1533
1688
  }
1534
- isVerticalLine(line, defaultValue = false) {
1535
- if (this.options.isVerticalLine) {
1536
- return this.options.isVerticalLine(line);
1537
- }
1538
- return defaultValue;
1539
- }
1540
1689
  setLineRenderType(line) {
1541
1690
  if (this.options.setLineRenderType) {
1542
1691
  return this.options.setLineRenderType(line);
@@ -1580,6 +1729,14 @@ var WorkflowLinesManager = class {
1580
1729
  if (fromPort === toPort || fromPort.node === toPort.node || fromPort.portType !== "output" || toPort.portType !== "input" || toPort.disabled) {
1581
1730
  return false;
1582
1731
  }
1732
+ const fromCanAdd = fromPort.node.getNodeRegistry().canAddLine;
1733
+ const toCanAdd = toPort.node.getNodeRegistry().canAddLine;
1734
+ if (fromCanAdd && !fromCanAdd(fromPort, toPort, this, silent)) {
1735
+ return false;
1736
+ }
1737
+ if (toCanAdd && !toCanAdd(fromPort, toPort, this, silent)) {
1738
+ return false;
1739
+ }
1583
1740
  if (this.options.canAddLine) {
1584
1741
  return this.options.canAddLine(fromPort, toPort, this, silent);
1585
1742
  }
@@ -1652,7 +1809,7 @@ var WorkflowLinesManager = class {
1652
1809
  const allNodes = this.getSortedNodes();
1653
1810
  const zoom = this.entityManager.getEntity(import_core12.PlaygroundConfigEntity)?.config?.zoom || 1;
1654
1811
  const containNodes = allNodes.map((node) => {
1655
- const { bounds } = node.getData(import_document5.FlowNodeTransformData);
1812
+ const { bounds } = node.getData(import_document6.FlowNodeTransformData);
1656
1813
  if (bounds.clone().pad(4 / zoom).contains(pos.x, pos.y)) {
1657
1814
  return node;
1658
1815
  }
@@ -1660,7 +1817,7 @@ var WorkflowLinesManager = class {
1660
1817
  return containNodes;
1661
1818
  }
1662
1819
  getNodeIndex(node) {
1663
- const nodeRenderData = node.getData(import_document5.FlowNodeRenderData);
1820
+ const nodeRenderData = node.getData(import_document6.FlowNodeRenderData);
1664
1821
  return nodeRenderData.stackIndex;
1665
1822
  }
1666
1823
  };
@@ -1685,13 +1842,13 @@ var import_nanoid2 = require("nanoid");
1685
1842
  var import_inversify5 = require("inversify");
1686
1843
  var import_utils14 = require("@flowgram.ai/utils");
1687
1844
  var import_form_core3 = require("@flowgram.ai/form-core");
1688
- var import_document7 = require("@flowgram.ai/document");
1845
+ var import_document8 = require("@flowgram.ai/document");
1689
1846
  var import_core14 = require("@flowgram.ai/core");
1690
1847
 
1691
1848
  // src/layout/free-layout.ts
1692
1849
  var import_inversify4 = require("inversify");
1693
1850
  var import_utils13 = require("@flowgram.ai/utils");
1694
- var import_document6 = require("@flowgram.ai/document");
1851
+ var import_document7 = require("@flowgram.ai/document");
1695
1852
  var import_core13 = require("@flowgram.ai/core");
1696
1853
  var FREE_LAYOUT_KEY = "free-layout";
1697
1854
  var FreeLayout = class {
@@ -1705,12 +1862,12 @@ var FreeLayout = class {
1705
1862
  * 更新布局
1706
1863
  */
1707
1864
  update() {
1708
- if (this.document.root.getData(import_document6.FlowNodeTransformData)?.localDirty) {
1865
+ if (this.document.root.getData(import_document7.FlowNodeTransformData)?.localDirty) {
1709
1866
  this.document.root.clearMemoGlobal();
1710
1867
  }
1711
1868
  }
1712
1869
  syncTransform(node) {
1713
- const transform = node.getData(import_document6.FlowNodeTransformData);
1870
+ const transform = node.getData(import_document7.FlowNodeTransformData);
1714
1871
  if (!transform.localDirty) {
1715
1872
  return;
1716
1873
  }
@@ -1724,7 +1881,7 @@ var FreeLayout = class {
1724
1881
  }
1725
1882
  node.parent.clearMemoGlobal();
1726
1883
  node.parent.clearMemoLocal();
1727
- const parentTransform = node.parent.getData(import_document6.FlowNodeTransformData);
1884
+ const parentTransform = node.parent.getData(import_document7.FlowNodeTransformData);
1728
1885
  parentTransform.transform.fireChange();
1729
1886
  }
1730
1887
  /**
@@ -1748,7 +1905,7 @@ var FreeLayout = class {
1748
1905
  */
1749
1906
  getPadding(node) {
1750
1907
  const { padding } = node.getNodeMeta();
1751
- const transform = node.getData(import_document6.FlowNodeTransformData);
1908
+ const transform = node.getData(import_document7.FlowNodeTransformData);
1752
1909
  if (padding) {
1753
1910
  return typeof padding === "function" ? padding(transform) : padding;
1754
1911
  }
@@ -1816,7 +1973,7 @@ __decorateClass([
1816
1973
  (0, import_inversify4.inject)(import_core13.PlaygroundConfigEntity)
1817
1974
  ], FreeLayout.prototype, "playgroundConfig", 2);
1818
1975
  __decorateClass([
1819
- (0, import_inversify4.inject)(import_document6.FlowDocumentProvider)
1976
+ (0, import_inversify4.inject)(import_document7.FlowDocumentProvider)
1820
1977
  ], FreeLayout.prototype, "documentProvider", 2);
1821
1978
  FreeLayout = __decorateClass([
1822
1979
  (0, import_inversify4.injectable)()
@@ -1825,7 +1982,7 @@ FreeLayout = __decorateClass([
1825
1982
  // src/workflow-document.ts
1826
1983
  var nanoid2 = (0, import_nanoid2.customAlphabet)("1234567890", 5);
1827
1984
  var WorkflowDocumentProvider = Symbol("WorkflowDocumentProvider");
1828
- var WorkflowDocument = class extends import_document7.FlowDocument {
1985
+ var WorkflowDocument = class extends import_document8.FlowDocument {
1829
1986
  constructor() {
1830
1987
  super(...arguments);
1831
1988
  this._onContentChangeEmitter = new import_utils14.Emitter();
@@ -1843,6 +2000,11 @@ var WorkflowDocument = class extends import_document7.FlowDocument {
1843
2000
  get loading() {
1844
2001
  return this._loading;
1845
2002
  }
2003
+ /**
2004
+ * use `ctx.tools.fitView()` instead
2005
+ * @deprecated
2006
+ * @param easing
2007
+ */
1846
2008
  async fitView(easing) {
1847
2009
  return fitView(this, this.playgroundConfig, easing).then(() => {
1848
2010
  this.linesManager.forceUpdate();
@@ -1922,7 +2084,7 @@ var WorkflowDocument = class extends import_document7.FlowDocument {
1922
2084
  const { formMeta } = registry;
1923
2085
  const meta = node.getNodeMeta();
1924
2086
  const formData = getFlowNodeFormData(node);
1925
- const transform = node.getData(import_document7.FlowNodeTransformData);
2087
+ const transform = node.getData(import_document8.FlowNodeTransformData);
1926
2088
  const freeLayout = this.layout;
1927
2089
  if (!isExistedNode) {
1928
2090
  transform.onDataChange(() => {
@@ -1964,10 +2126,10 @@ var WorkflowDocument = class extends import_document7.FlowDocument {
1964
2126
  toJSON: () => this.toNodeJSON(node)
1965
2127
  });
1966
2128
  node.onDispose(() => {
1967
- if (!node.parent || node.parent.flowNodeType === import_document7.FlowNodeBaseType.ROOT) {
2129
+ if (!node.parent || node.parent.flowNodeType === import_document8.FlowNodeBaseType.ROOT) {
1968
2130
  return;
1969
2131
  }
1970
- const parentTransform = node.parent.getData(import_document7.FlowNodeTransformData);
2132
+ const parentTransform = node.parent.getData(import_document8.FlowNodeTransformData);
1971
2133
  parentTransform.fireChange();
1972
2134
  });
1973
2135
  let lastDeleteNodeData;
@@ -2132,10 +2294,10 @@ var WorkflowDocument = class extends import_document7.FlowDocument {
2132
2294
  );
2133
2295
  }
2134
2296
  getAllNodes() {
2135
- return this.entityManager.getEntities(WorkflowNodeEntity).filter((n) => n.id !== import_document7.FlowNodeBaseType.ROOT);
2297
+ return this.entityManager.getEntities(WorkflowNodeEntity).filter((n) => n.id !== import_document8.FlowNodeBaseType.ROOT);
2136
2298
  }
2137
2299
  getAllPorts() {
2138
- return this.entityManager.getEntities(WorkflowPortEntity).filter((p) => p.node.id !== import_document7.FlowNodeBaseType.ROOT);
2300
+ return this.entityManager.getEntities(WorkflowPortEntity).filter((p) => p.node.id !== import_document8.FlowNodeBaseType.ROOT);
2139
2301
  }
2140
2302
  /**
2141
2303
  * 获取画布中的非游离节点
@@ -2150,10 +2312,13 @@ var WorkflowDocument = class extends import_document7.FlowDocument {
2150
2312
  from: line.from.id,
2151
2313
  to: line.to.id
2152
2314
  }));
2153
- const startNodeId = allNode.find((node) => node.isStart).id;
2154
- const endNodeId = allNode.find((node) => node.isNodeEnd).id;
2315
+ const startNodeId = allNode.find((node) => node.isStart)?.id;
2316
+ const endNodeId = allNode.find((node) => node.isNodeEnd)?.id;
2155
2317
  const nodeInContainer = allNode.filter((node) => node.parent?.getNodeMeta().isContainer).map((node) => node.id);
2156
- const associatedCache = /* @__PURE__ */ new Set([endNodeId, ...nodeInContainer]);
2318
+ const associatedCache = new Set(nodeInContainer);
2319
+ if (endNodeId) {
2320
+ associatedCache.add(endNodeId);
2321
+ }
2157
2322
  const bfs = (nodeId) => {
2158
2323
  if (associatedCache.has(nodeId)) {
2159
2324
  return;
@@ -2167,7 +2332,9 @@ var WorkflowDocument = class extends import_document7.FlowDocument {
2167
2332
  }, []);
2168
2333
  nextNodes.forEach(bfs);
2169
2334
  };
2170
- bfs(startNodeId);
2335
+ if (startNodeId) {
2336
+ bfs(startNodeId);
2337
+ }
2171
2338
  const associatedNodes = allNode.filter((node) => associatedCache.has(node.id));
2172
2339
  return associatedNodes;
2173
2340
  }
@@ -2289,11 +2456,17 @@ var WorkflowDocument = class extends import_document7.FlowDocument {
2289
2456
  * 导出数据
2290
2457
  */
2291
2458
  toJSON() {
2459
+ if (this.disposed) {
2460
+ throw new Error(
2461
+ "The WorkflowDocument has been disposed and it is no longer possible to call toJSON."
2462
+ );
2463
+ }
2292
2464
  const rootJSON = this.toNodeJSON(this.root);
2293
- return {
2465
+ const json = {
2294
2466
  nodes: rootJSON.blocks ?? [],
2295
2467
  edges: rootJSON.edges ?? []
2296
2468
  };
2469
+ return json;
2297
2470
  }
2298
2471
  dispose() {
2299
2472
  super.dispose();
@@ -2305,10 +2478,11 @@ var WorkflowDocument = class extends import_document7.FlowDocument {
2305
2478
  renderJSON(json, options) {
2306
2479
  const { parent = this.root, isClone = false } = options ?? {};
2307
2480
  const containerID = this.getNodeSubCanvas(parent)?.canvasNode.id ?? parent.id;
2308
- const nodes = json.nodes.map(
2481
+ const processedJSON = buildGroupJSON(json);
2482
+ const nodes = processedJSON.nodes.map(
2309
2483
  (nodeJSON) => this.createWorkflowNode(nodeJSON, isClone, containerID)
2310
2484
  );
2311
- const edges = json.edges.map((edge) => this.createWorkflowLine(edge, containerID)).filter(Boolean);
2485
+ const edges = processedJSON.edges.map((edge) => this.createWorkflowLine(edge, containerID)).filter(Boolean);
2312
2486
  return { nodes, edges };
2313
2487
  }
2314
2488
  getNodeSubCanvas(node) {
@@ -2318,13 +2492,19 @@ var WorkflowDocument = class extends import_document7.FlowDocument {
2318
2492
  return subCanvas;
2319
2493
  }
2320
2494
  getNodeChildren(node) {
2321
- if (!node) return [];
2495
+ if (!node || node.flowNodeType === import_document8.FlowNodeBaseType.GROUP) return [];
2322
2496
  const subCanvas = this.getNodeSubCanvas(node);
2323
- const childrenWithCanvas = subCanvas ? subCanvas.canvasNode.collapsedChildren : node.collapsedChildren;
2324
- const children = childrenWithCanvas.filter((child) => {
2497
+ const realChildren = subCanvas ? subCanvas.canvasNode.blocks : node.blocks;
2498
+ const childrenWithoutSubCanvas = realChildren.filter((child) => {
2325
2499
  const childMeta = child.getNodeMeta();
2326
2500
  return !childMeta.subCanvas?.(node)?.isCanvas;
2327
2501
  }).filter(Boolean);
2502
+ const children = childrenWithoutSubCanvas.map((child) => {
2503
+ if (child.flowNodeType === import_document8.FlowNodeBaseType.GROUP) {
2504
+ return [child, ...child.blocks];
2505
+ }
2506
+ return child;
2507
+ }).flat();
2328
2508
  return children;
2329
2509
  }
2330
2510
  toLineJSON(line) {
@@ -2361,7 +2541,8 @@ var WorkflowDocument = class extends import_document7.FlowDocument {
2361
2541
  from: json.sourceNodeID,
2362
2542
  fromPort: json.sourcePortID,
2363
2543
  to: json.targetNodeID,
2364
- toPort: json.targetPortID
2544
+ toPort: json.targetPortID,
2545
+ data: json.data
2365
2546
  };
2366
2547
  if (!parentId) {
2367
2548
  return this.linesManager.createLine(lineInfo);
@@ -2456,7 +2637,7 @@ var WorkflowDragService = class {
2456
2637
  }
2457
2638
  this.isDragging = true;
2458
2639
  const sameParent = this.childrenOfContainer(selectedNodes);
2459
- if (sameParent && sameParent.flowNodeType !== import_document9.FlowNodeBaseType.ROOT) {
2640
+ if (sameParent && sameParent.flowNodeType !== import_document10.FlowNodeBaseType.ROOT) {
2460
2641
  selectedNodes = [sameParent];
2461
2642
  }
2462
2643
  let startPosition = this.getNodesPosition(selectedNodes);
@@ -2626,7 +2807,7 @@ var WorkflowDragService = class {
2626
2807
  if (!mousePos) {
2627
2808
  return { x: 0, y: 0 };
2628
2809
  }
2629
- if (!subNodeType || !containerNode || containerNode.flowNodeType === import_document9.FlowNodeBaseType.ROOT) {
2810
+ if (!subNodeType || !containerNode || containerNode.flowNodeType === import_document10.FlowNodeBaseType.ROOT) {
2630
2811
  return mousePos;
2631
2812
  }
2632
2813
  const isParentEmpty = !containerNode.children || containerNode.children.length === 0;
@@ -2712,7 +2893,7 @@ var WorkflowDragService = class {
2712
2893
  return offset;
2713
2894
  }
2714
2895
  updateDroppableTransforms() {
2715
- this._droppableTransforms = this.document.getRenderDatas(import_document8.FlowNodeTransformData, false).filter((transform) => {
2896
+ this._droppableTransforms = this.document.getRenderDatas(import_document9.FlowNodeTransformData, false).filter((transform) => {
2716
2897
  const { entity } = transform;
2717
2898
  if (entity.originParent) {
2718
2899
  return this.nodeSelectable(entity) && this.nodeSelectable(entity.originParent);
@@ -2729,7 +2910,7 @@ var WorkflowDragService = class {
2729
2910
  */
2730
2911
  getNodesPosition(nodes) {
2731
2912
  const selectedBounds = import_utils16.Rectangle.enlarge(
2732
- nodes.map((n) => n.getData(import_document8.FlowNodeTransformData).bounds)
2913
+ nodes.map((n) => n.getData(import_document9.FlowNodeTransformData).bounds)
2733
2914
  );
2734
2915
  const position = {
2735
2916
  x: selectedBounds.x,
@@ -2828,10 +3009,16 @@ var WorkflowDragService = class {
2828
3009
  originLine.highlightColor = this.linesManager.lineColor.hidden;
2829
3010
  }
2830
3011
  dragSuccess = true;
3012
+ const pos = config.getPosFromMouseEvent(event);
2831
3013
  line = this.linesManager.createLine({
2832
3014
  from: fromPort.node.id,
2833
3015
  fromPort: fromPort.portID,
2834
- drawingTo: config.getPosFromMouseEvent(event)
3016
+ data: originLine?.lineData,
3017
+ drawingTo: {
3018
+ x: pos.x,
3019
+ y: pos.y,
3020
+ location: fromPort.location === "right" ? "left" : "top"
3021
+ }
2835
3022
  });
2836
3023
  if (!line) {
2837
3024
  return;
@@ -2866,9 +3053,17 @@ var WorkflowDragService = class {
2866
3053
  lineErrorReset = hasError;
2867
3054
  }
2868
3055
  if (line.toPort) {
2869
- line.drawingTo = { x: line.toPort.point.x, y: line.toPort.point.y };
3056
+ line.drawingTo = {
3057
+ x: line.toPort.point.x,
3058
+ y: line.toPort.point.y,
3059
+ location: line.toPort.location
3060
+ };
2870
3061
  } else {
2871
- line.drawingTo = { x: dragPos.x, y: dragPos.y };
3062
+ line.drawingTo = {
3063
+ x: dragPos.x,
3064
+ y: dragPos.y,
3065
+ location: line.fromPort.location === "right" ? "left" : "top"
3066
+ };
2872
3067
  }
2873
3068
  originLine?.validate();
2874
3069
  line.validate();
@@ -2912,7 +3107,8 @@ var WorkflowDragService = class {
2912
3107
  from: fromPort.node.id,
2913
3108
  fromPort: fromPort.portID,
2914
3109
  to: toPort.node.id,
2915
- toPort: toPort.portID
3110
+ toPort: toPort.portID,
3111
+ data: originLine?.lineData
2916
3112
  } : void 0;
2917
3113
  const isReset = originLine && toPort;
2918
3114
  if (isReset && !this.linesManager.canReset(
@@ -3009,7 +3205,7 @@ __decorateClass([
3009
3205
  (0, import_inversify6.inject)(WorkflowSelectService)
3010
3206
  ], WorkflowDragService.prototype, "selectService", 2);
3011
3207
  __decorateClass([
3012
- (0, import_inversify6.inject)(import_document8.FlowOperationBaseService)
3208
+ (0, import_inversify6.inject)(import_document9.FlowOperationBaseService)
3013
3209
  ], WorkflowDragService.prototype, "operationService", 2);
3014
3210
  __decorateClass([
3015
3211
  (0, import_inversify6.inject)(WorkflowDocumentOptions)
@@ -3028,13 +3224,13 @@ var import_core18 = require("@flowgram.ai/core");
3028
3224
  var import_utils17 = require("@flowgram.ai/utils");
3029
3225
 
3030
3226
  // src/utils/layout-to-positions.ts
3031
- var import_document10 = require("@flowgram.ai/document");
3227
+ var import_document11 = require("@flowgram.ai/document");
3032
3228
  var import_core16 = require("@flowgram.ai/core");
3033
3229
  var layoutToPositions = async (nodes, nodePositionMap) => {
3034
3230
  const newNodePositionMap = {};
3035
3231
  nodes.forEach((node) => {
3036
3232
  const transform = node.getData(import_core16.TransformData);
3037
- const nodeTransform = node.getData(import_document10.FlowNodeTransformData);
3233
+ const nodeTransform = node.getData(import_document11.FlowNodeTransformData);
3038
3234
  newNodePositionMap[node.id] = {
3039
3235
  x: transform.position.x,
3040
3236
  y: transform.position.y + nodeTransform.bounds.height / 2
@@ -3130,9 +3326,9 @@ WorkflowResetLayoutService = __decorateClass([
3130
3326
  // src/service/workflow-operation-base-service.ts
3131
3327
  var import_inversify8 = require("inversify");
3132
3328
  var import_utils19 = require("@flowgram.ai/utils");
3133
- var import_document11 = require("@flowgram.ai/document");
3329
+ var import_document12 = require("@flowgram.ai/document");
3134
3330
  var import_core19 = require("@flowgram.ai/core");
3135
- var WorkflowOperationBaseServiceImpl = class extends import_document11.FlowOperationBaseServiceImpl {
3331
+ var WorkflowOperationBaseServiceImpl = class extends import_document12.FlowOperationBaseServiceImpl {
3136
3332
  constructor() {
3137
3333
  super(...arguments);
3138
3334
  this.onNodePostionUpdateEmitter = new import_utils19.Emitter();
@@ -3182,9 +3378,10 @@ function usePlaygroundReadonlyState(listenChange) {
3182
3378
  function checkTargetDraggable(el) {
3183
3379
  return el && el.tagName !== "INPUT" && el.tagName !== "TEXTAREA" && !el.closest(".flow-canvas-not-draggable");
3184
3380
  }
3381
+ var isFirefox = navigator?.userAgent?.includes?.("Firefox");
3185
3382
  function useNodeRender(nodeFromProps) {
3186
3383
  const node = nodeFromProps || (0, import_react2.useContext)(import_core21.PlaygroundEntityContext);
3187
- const renderData = node.getData(import_document12.FlowNodeRenderData);
3384
+ const renderData = node.getData(import_document13.FlowNodeRenderData);
3188
3385
  const portsData = node.getData(WorkflowNodePortsData);
3189
3386
  const readonly = usePlaygroundReadonlyState();
3190
3387
  const dragService = (0, import_core21.useService)(WorkflowDragService);
@@ -3245,7 +3442,6 @@ function useNodeRender(nodeFromProps) {
3245
3442
  );
3246
3443
  const deleteNode = (0, import_react2.useCallback)(() => node.dispose(), [node]);
3247
3444
  (0, import_core21.useListenEvents)(portsData.onDataChange);
3248
- const isFirefox = navigator?.userAgent?.includes?.("Firefox");
3249
3445
  const onFocus = (0, import_react2.useCallback)(() => {
3250
3446
  if (isFirefox) {
3251
3447
  nodeRef.current?.setAttribute("draggable", "false");
@@ -3351,11 +3547,11 @@ function useNodeRender(nodeFromProps) {
3351
3547
  }
3352
3548
 
3353
3549
  // src/hooks/use-current-dom-node.ts
3354
- var import_document13 = require("@flowgram.ai/document");
3550
+ var import_document14 = require("@flowgram.ai/document");
3355
3551
  var import_core22 = require("@flowgram.ai/core");
3356
3552
  function useCurrentDomNode() {
3357
3553
  const entity = (0, import_core22.useEntityFromContext)();
3358
- const renderData = entity.getData(import_document13.FlowNodeRenderData);
3554
+ const renderData = entity.getData(import_document14.FlowNodeRenderData);
3359
3555
  return renderData.node;
3360
3556
  }
3361
3557
 
@@ -3386,16 +3582,16 @@ var InteractiveType = /* @__PURE__ */ ((InteractiveType2) => {
3386
3582
  // src/workflow-document-container-module.ts
3387
3583
  var import_inversify10 = require("inversify");
3388
3584
  var import_utils20 = require("@flowgram.ai/utils");
3389
- var import_document15 = require("@flowgram.ai/document");
3585
+ var import_document16 = require("@flowgram.ai/document");
3390
3586
 
3391
3587
  // src/workflow-document-contribution.ts
3392
3588
  var import_inversify9 = require("inversify");
3393
- var import_document14 = require("@flowgram.ai/document");
3589
+ var import_document15 = require("@flowgram.ai/document");
3394
3590
  var WorkflowDocumentContribution = class {
3395
3591
  registerDocument(document2) {
3396
3592
  document2.registerNodeDatas(
3397
- import_document14.FlowNodeTransformData,
3398
- import_document14.FlowNodeRenderData,
3593
+ import_document15.FlowNodeTransformData,
3594
+ import_document15.FlowNodeRenderData,
3399
3595
  WorkflowNodePortsData,
3400
3596
  WorkflowNodeLinesData
3401
3597
  );
@@ -3430,11 +3626,11 @@ var WorkflowDocumentContainerModule = new import_inversify10.ContainerModule(
3430
3626
  bind(WorkflowResetLayoutService).toSelf().inSingletonScope();
3431
3627
  bind(WorkflowOperationBaseService).to(WorkflowOperationBaseServiceImpl).inSingletonScope();
3432
3628
  bind(URLParams).toDynamicValue(() => getUrlParams()).inSingletonScope();
3433
- (0, import_utils20.bindContributions)(bind, WorkflowDocumentContribution, [import_document15.FlowDocumentContribution]);
3629
+ (0, import_utils20.bindContributions)(bind, WorkflowDocumentContribution, [import_document16.FlowDocumentContribution]);
3434
3630
  bind(WorkflowDocumentOptions).toConstantValue({
3435
3631
  ...WorkflowDocumentOptionsDefault
3436
3632
  });
3437
- rebind(import_document15.FlowDocument).toService(WorkflowDocument);
3633
+ rebind(import_document16.FlowDocument).toService(WorkflowDocument);
3438
3634
  bind(WorkflowDocumentProvider).toDynamicValue((ctx) => () => ctx.container.get(WorkflowDocument)).inSingletonScope();
3439
3635
  }
3440
3636
  );
@@ -3546,6 +3742,7 @@ WorkflowSimpleLineContribution.type = "WorkflowSimpleLineContribution";
3546
3742
  WorkflowSelectService,
3547
3743
  WorkflowSimpleLineContribution,
3548
3744
  bindConfigEntity,
3745
+ buildGroupJSON,
3549
3746
  compose,
3550
3747
  composeAsync,
3551
3748
  delay,