@flowgram.ai/free-layout-core 0.1.0-alpha.12 → 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 +221 -78
  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 +14 -9
  11. package/dist/index.d.ts +14 -9
  12. package/dist/index.js +201 -57
  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-Iq1OHmuK.d.mts → workflow-line-entity-DSC3qPV1.d.mts} +123 -38
  33. package/dist/{workflow-line-entity-LhmV98jq.d.ts → workflow-line-entity-I_VrhJ_t.d.ts} +123 -38
  34. package/package.json +9 -9
  35. package/dist/esm/chunk-CTGO4RKX.js.map +0 -1
package/dist/esm/index.js CHANGED
@@ -7,11 +7,11 @@ import "./chunk-TQLT57GW.js";
7
7
  import "./chunk-CGOMTQ3G.js";
8
8
  import {
9
9
  WorkflowContentChangeType
10
- } from "./chunk-242F2JCI.js";
10
+ } from "./chunk-U2XMPOSL.js";
11
11
  import {
12
12
  LineColors,
13
13
  LineType
14
- } from "./chunk-CTGO4RKX.js";
14
+ } from "./chunk-E7ZUQ7LV.js";
15
15
  import "./chunk-DDJTYHXN.js";
16
16
  import {
17
17
  WorkflowOperationBaseService
@@ -110,8 +110,8 @@ function nanoid(n) {
110
110
  import { compose, composeAsync } from "@flowgram.ai/utils";
111
111
 
112
112
  // src/utils/fit-view.ts
113
- import { TransformData } from "@flowgram.ai/core";
114
113
  import { Rectangle } from "@flowgram.ai/utils";
114
+ import { TransformData } from "@flowgram.ai/core";
115
115
  var fitView = (doc, playgroundConfig, easing = true) => {
116
116
  const bounds = Rectangle.enlarge(
117
117
  doc.getAllNodes().map((node) => node.getData(TransformData).bounds)
@@ -158,7 +158,7 @@ var WorkflowNodeEntity = FlowNodeEntity;
158
158
 
159
159
  // src/entities/workflow-line-entity.ts
160
160
  import { isEqual as isEqual2 } from "lodash-es";
161
- import { domUtils } from "@flowgram.ai/utils";
161
+ import { domUtils, Emitter as Emitter2 } from "@flowgram.ai/utils";
162
162
  import { Entity as Entity2 } from "@flowgram.ai/core";
163
163
 
164
164
  // src/entity-datas/workflow-node-ports-data.ts
@@ -167,7 +167,7 @@ import { FlowNodeRenderData } from "@flowgram.ai/document";
167
167
  import { EntityData, SizeData } from "@flowgram.ai/core";
168
168
 
169
169
  // src/entities/workflow-port-entity.ts
170
- import { Rectangle as Rectangle3, Emitter } from "@flowgram.ai/utils";
170
+ import { Rectangle as Rectangle3, Emitter, Compare } from "@flowgram.ai/utils";
171
171
  import { FlowNodeTransformData } from "@flowgram.ai/document";
172
172
  import {
173
173
  Entity,
@@ -176,17 +176,18 @@ import {
176
176
  } from "@flowgram.ai/core";
177
177
  var PORT_SIZE = 24;
178
178
  var WorkflowPortEntity = class extends Entity {
179
- // relativePosition
180
179
  constructor(opts) {
181
180
  super(opts);
182
181
  this.portID = "";
183
- this._disabled = false;
184
182
  this._hasError = false;
185
183
  this._onErrorChangedEmitter = new Emitter();
186
184
  this.onErrorChanged = this._onErrorChangedEmitter.event;
187
185
  this.portID = opts.portID || "";
188
186
  this.portType = opts.type;
189
- this._disabled = opts.disabled ?? false;
187
+ this._disabled = opts.disabled;
188
+ this._offset = opts.offset;
189
+ this._location = opts.location;
190
+ this._size = opts.size;
190
191
  this.node = opts.node;
191
192
  this.updateTargetElement(opts.targetElement);
192
193
  this.toDispose.push(this.node.getData(TransformData3).onDataChange(() => this.fireChange()));
@@ -195,6 +196,9 @@ var WorkflowPortEntity = class extends Entity {
195
196
  static getPortEntityId(node, portType, portID = "") {
196
197
  return getPortEntityId(node, portType, portID);
197
198
  }
199
+ get position() {
200
+ return this._location;
201
+ }
198
202
  // 获取连线是否为错误态
199
203
  get hasError() {
200
204
  return this._hasError;
@@ -219,28 +223,65 @@ var WorkflowPortEntity = class extends Entity {
219
223
  isErrorPort() {
220
224
  return this.node.document.isErrorPort(this, this.hasError);
221
225
  }
226
+ get location() {
227
+ if (this._location) {
228
+ return this._location;
229
+ }
230
+ if (this.portType === "input") {
231
+ return "left";
232
+ }
233
+ return "right";
234
+ }
222
235
  get point() {
223
236
  const { targetElement } = this;
224
237
  const { bounds } = this.node.getData(FlowNodeTransformData);
238
+ const location2 = this.location;
225
239
  if (targetElement) {
226
240
  const pos = domReactToBounds(targetElement.getBoundingClientRect()).center;
227
- return this.entityManager.getEntity(PlaygroundConfigEntity).getPosFromMouseEvent({
241
+ const point2 = this.entityManager.getEntity(PlaygroundConfigEntity).getPosFromMouseEvent({
228
242
  clientX: pos.x,
229
243
  clientY: pos.y
230
244
  });
245
+ return {
246
+ x: point2.x,
247
+ y: point2.y,
248
+ location: location2
249
+ };
231
250
  }
232
- if (this.portType === "input") {
233
- return bounds.leftCenter;
251
+ let point = { x: 0, y: 0 };
252
+ const offset = this._offset || { x: 0, y: 0 };
253
+ switch (location2) {
254
+ case "left":
255
+ point = bounds.leftCenter;
256
+ break;
257
+ case "top":
258
+ point = bounds.topCenter;
259
+ break;
260
+ case "right":
261
+ point = bounds.rightCenter;
262
+ break;
263
+ case "bottom":
264
+ point = bounds.bottomCenter;
265
+ break;
234
266
  }
235
- return bounds.rightCenter;
267
+ return {
268
+ x: point.x + offset.x,
269
+ y: point.y + offset.y,
270
+ location: location2
271
+ };
236
272
  }
237
273
  /**
238
- * 点的区域
274
+ * 端口热区
239
275
  */
240
276
  get bounds() {
241
277
  const { point } = this;
242
- const halfSize = PORT_SIZE / 2;
243
- return new Rectangle3(point.x - halfSize, point.y - halfSize, PORT_SIZE, PORT_SIZE);
278
+ const size = this._size || { width: PORT_SIZE, height: PORT_SIZE };
279
+ return new Rectangle3(
280
+ point.x - size.width / 2,
281
+ point.y - size.height / 2,
282
+ size.width,
283
+ size.height
284
+ );
244
285
  }
245
286
  isHovered(x, y) {
246
287
  return this.bounds.contains(x, y);
@@ -307,6 +348,32 @@ var WorkflowPortEntity = class extends Entity {
307
348
  });
308
349
  return lines;
309
350
  }
351
+ update(data) {
352
+ let changed = false;
353
+ if (data.targetElement !== this.targetElement) {
354
+ this.targetElement = data.targetElement;
355
+ changed = true;
356
+ }
357
+ if (data.location !== this._location) {
358
+ this._location = data.location;
359
+ changed = true;
360
+ }
361
+ if (Compare.isChanged(data.offset, this._offset)) {
362
+ this._offset = data.offset;
363
+ changed = true;
364
+ }
365
+ if (Compare.isChanged(data.size, this._size)) {
366
+ this._size = data.size;
367
+ changed = true;
368
+ }
369
+ if (data.disabled !== this._disabled) {
370
+ this._disabled = data.disabled;
371
+ changed = true;
372
+ }
373
+ if (changed) {
374
+ this.fireChange();
375
+ }
376
+ }
310
377
  dispose() {
311
378
  this.lines.forEach((l) => l.dispose());
312
379
  super.dispose();
@@ -345,17 +412,26 @@ var WorkflowNodePortsData = class extends EntityData {
345
412
  return {};
346
413
  }
347
414
  /**
348
- * 更新静态的 ports 数据
415
+ * Update all ports data, includes static ports and dynamic ports
416
+ * @param ports
349
417
  */
350
- updateStaticPorts(ports) {
418
+ updateAllPorts(ports) {
351
419
  const meta = this.entity.getNodeMeta();
352
- this._staticPorts = ports;
420
+ if (ports) {
421
+ this._staticPorts = ports;
422
+ }
353
423
  if (meta.useDynamicPort) {
354
424
  this.updateDynamicPorts();
355
425
  } else {
356
426
  this.updatePorts(this._staticPorts);
357
427
  }
358
428
  }
429
+ /**
430
+ * @deprecated use `updateAllPorts` instead
431
+ */
432
+ updateStaticPorts(ports) {
433
+ this.updateAllPorts(ports);
434
+ }
359
435
  /**
360
436
  * 动态计算点位,通过 dom 的 data-port-key
361
437
  */
@@ -494,9 +570,7 @@ var WorkflowNodePortsData = class extends EntityData {
494
570
  */
495
571
  updatePortEntity(portInfo) {
496
572
  const portEntity = this.getOrCreatePortEntity(portInfo);
497
- if (portInfo.targetElement) {
498
- portEntity.updateTargetElement(portInfo.targetElement);
499
- }
573
+ portEntity.update(portInfo);
500
574
  return portEntity;
501
575
  }
502
576
  };
@@ -637,8 +711,8 @@ var WorkflowLineRenderData = class extends EntityData3 {
637
711
  version: "",
638
712
  contributions: /* @__PURE__ */ new Map(),
639
713
  position: {
640
- from: { x: 0, y: 0 },
641
- to: { x: 0, y: 0 }
714
+ from: { x: 0, y: 0, location: "right" },
715
+ to: { x: 0, y: 0, location: "left" }
642
716
  }
643
717
  };
644
718
  }
@@ -684,16 +758,23 @@ var WorkflowLineRenderData = class extends EntityData3 {
684
758
  */
685
759
  updatePosition() {
686
760
  this.data.position.from = this.entity.from.getData(WorkflowNodePortsData).getOutputPoint(this.entity.info.fromPort);
687
- this.data.position.to = this.entity.info.drawingTo ?? this.entity.to?.getData(WorkflowNodePortsData)?.getInputPoint(this.entity.info.toPort) ?? {
688
- x: this.data.position.from.x,
689
- y: this.data.position.from.y
690
- };
761
+ if (this.entity.info.drawingTo) {
762
+ this.data.position.to = this.entity.info.drawingTo;
763
+ } else {
764
+ this.data.position.to = this.entity.to?.getData(WorkflowNodePortsData)?.getInputPoint(this.entity.info.toPort) ?? {
765
+ x: this.data.position.from.x,
766
+ y: this.data.position.from.y,
767
+ location: this.data.position.from.location === "right" ? "left" : "top"
768
+ };
769
+ }
691
770
  this.data.version = [
692
771
  this.lineType,
693
772
  this.data.position.from.x,
694
773
  this.data.position.from.y,
774
+ this.data.position.from.location,
695
775
  this.data.position.to.x,
696
- this.data.position.to.y
776
+ this.data.position.to.y,
777
+ this.data.position.to.location
697
778
  ].join("-");
698
779
  }
699
780
  get currentLine() {
@@ -723,13 +804,16 @@ var POINT_RADIUS = 10;
723
804
  var _WorkflowLineEntity = class _WorkflowLineEntity extends Entity2 {
724
805
  constructor(opts) {
725
806
  super(opts);
807
+ this._onLineDataChangeEmitter = new Emitter2();
808
+ this.onLineDataChange = this._onLineDataChangeEmitter.event;
726
809
  this._uiState = {
727
810
  hasError: false,
728
811
  flowing: false,
729
812
  disabled: false,
730
- vertical: false,
731
813
  hideArrow: false,
732
814
  reverse: false,
815
+ shrink: 10,
816
+ curvature: 0.25,
733
817
  highlightColor: "",
734
818
  lockedColor: ""
735
819
  };
@@ -747,7 +831,8 @@ var _WorkflowLineEntity = class _WorkflowLineEntity extends Entity2 {
747
831
  to: opts.to,
748
832
  drawingTo: opts.drawingTo,
749
833
  fromPort: opts.fromPort,
750
- toPort: opts.toPort
834
+ toPort: opts.toPort,
835
+ data: opts.data
751
836
  });
752
837
  if (opts.drawingTo) {
753
838
  this.isDrawing = true;
@@ -760,6 +845,7 @@ var _WorkflowLineEntity = class _WorkflowLineEntity extends Entity2 {
760
845
  this.fromPort?.validate();
761
846
  this.toPort?.validate();
762
847
  });
848
+ this.toDispose.push(this._onLineDataChangeEmitter);
763
849
  }
764
850
  /**
765
851
  * 转成线条 id
@@ -802,9 +888,13 @@ var _WorkflowLineEntity = class _WorkflowLineEntity extends Entity2 {
802
888
  * 更新线条扩展数据
803
889
  * @param data
804
890
  */
805
- set lineData(data) {
806
- this._lineData = data;
807
- this.fireChange();
891
+ set lineData(newValue) {
892
+ const oldValue = this._lineData;
893
+ if (!isEqual2(oldValue, newValue)) {
894
+ this._lineData = newValue;
895
+ this._onLineDataChangeEmitter.fire({ oldValue, newValue });
896
+ this.fireChange();
897
+ }
808
898
  }
809
899
  /**
810
900
  * 获取线条的前置节点
@@ -827,20 +917,17 @@ var _WorkflowLineEntity = class _WorkflowLineEntity extends Entity2 {
827
917
  }
828
918
  /**
829
919
  * 获取是否 testrun processing
830
- * @deprecated use `uiState.flowing` instead
920
+ * @deprecated use `flowing` instead
831
921
  */
832
922
  get processing() {
833
923
  return this._uiState.flowing;
834
924
  }
835
925
  /**
836
926
  * 设置 testrun processing 状态
837
- * @deprecated use `uiState.flowing` instead
927
+ * @deprecated use `flowing` instead
838
928
  */
839
929
  set processing(status) {
840
- if (this._uiState.flowing !== status) {
841
- this._uiState.flowing = status;
842
- this.fireChange();
843
- }
930
+ this.flowing = status;
844
931
  }
845
932
  // 获取连线是否为错误态
846
933
  get hasError() {
@@ -870,7 +957,6 @@ var _WorkflowLineEntity = class _WorkflowLineEntity extends Entity2 {
870
957
  const { node, portID } = toPort;
871
958
  this._to = node;
872
959
  this.info.drawingTo = void 0;
873
- this.info.isDefaultLine = false;
874
960
  this.info.to = node.id;
875
961
  this.info.toPort = portID;
876
962
  } else {
@@ -895,7 +981,6 @@ var _WorkflowLineEntity = class _WorkflowLineEntity extends Entity2 {
895
981
  }
896
982
  if (!oldDrawingTo || pos.x !== oldDrawingTo.x || pos.y !== oldDrawingTo.y) {
897
983
  this.info.to = void 0;
898
- this.info.isDefaultLine = false;
899
984
  this.info.drawingTo = pos;
900
985
  this.fireChange();
901
986
  }
@@ -961,13 +1046,25 @@ var _WorkflowLineEntity = class _WorkflowLineEntity extends Entity2 {
961
1046
  get flowing() {
962
1047
  return this.linesManager.isFlowingLine(this, this.uiState.flowing);
963
1048
  }
1049
+ set flowing(flowing) {
1050
+ if (this._uiState.flowing !== flowing) {
1051
+ this._uiState.flowing = flowing;
1052
+ this.fireChange();
1053
+ }
1054
+ }
964
1055
  /** 是否禁用 */
965
1056
  get disabled() {
966
1057
  return this.linesManager.isDisabledLine(this, this.uiState.disabled);
967
1058
  }
968
1059
  /** 是否竖向 */
969
1060
  get vertical() {
970
- return this.linesManager.isVerticalLine(this, this.uiState.vertical);
1061
+ const fromLocation = this.fromPort.location;
1062
+ const toLocation = this.toPort?.location;
1063
+ if (toLocation) {
1064
+ return toLocation === "top";
1065
+ } else {
1066
+ return fromLocation === "bottom";
1067
+ }
971
1068
  }
972
1069
  /** 获取线条渲染器类型 */
973
1070
  get renderType() {
@@ -975,7 +1072,7 @@ var _WorkflowLineEntity = class _WorkflowLineEntity extends Entity2 {
975
1072
  }
976
1073
  /** 获取线条样式 */
977
1074
  get className() {
978
- return this.linesManager.setLineClassName(this) ?? "";
1075
+ return [this.linesManager.setLineClassName(this), this._uiState.className].filter((s) => !!s).join(" ");
979
1076
  }
980
1077
  get color() {
981
1078
  return this.linesManager.getLineColor(this);
@@ -989,6 +1086,7 @@ var _WorkflowLineEntity = class _WorkflowLineEntity extends Entity2 {
989
1086
  this.info = info;
990
1087
  this._from = this.document.getNode(info.from);
991
1088
  this._to = info.to ? this.document.getNode(info.to) : void 0;
1089
+ this._lineData = info.data;
992
1090
  this.fireChange();
993
1091
  }
994
1092
  }
@@ -1149,12 +1247,12 @@ WorkflowSelectService = __decorateClass([
1149
1247
 
1150
1248
  // src/service/workflow-hover-service.ts
1151
1249
  import { inject as inject2, injectable as injectable2 } from "inversify";
1152
- import { Emitter as Emitter2 } from "@flowgram.ai/utils";
1250
+ import { Emitter as Emitter3 } from "@flowgram.ai/utils";
1153
1251
  import { EntityManager } from "@flowgram.ai/core";
1154
1252
  var WorkflowHoverService = class {
1155
1253
  constructor() {
1156
- this.onHoveredChangeEmitter = new Emitter2();
1157
- this.onUpdateHoverPositionEmitter = new Emitter2();
1254
+ this.onHoveredChangeEmitter = new Emitter3();
1255
+ this.onUpdateHoverPositionEmitter = new Emitter3();
1158
1256
  this.onHoveredChange = this.onHoveredChangeEmitter.event;
1159
1257
  this.onUpdateHoverPosition = this.onUpdateHoverPositionEmitter.event;
1160
1258
  // 当前鼠标 hover 位置
@@ -1220,7 +1318,7 @@ import { inject as inject6, injectable as injectable6, postConstruct as postCons
1220
1318
  import {
1221
1319
  domUtils as domUtils2,
1222
1320
  PromiseDeferred,
1223
- Emitter as Emitter5,
1321
+ Emitter as Emitter6,
1224
1322
  DisposableCollection as DisposableCollection2,
1225
1323
  Rectangle as Rectangle8,
1226
1324
  delay as delay2
@@ -1241,7 +1339,7 @@ import {
1241
1339
  // src/workflow-lines-manager.ts
1242
1340
  import { last } from "lodash-es";
1243
1341
  import { inject as inject3, injectable as injectable3 } from "inversify";
1244
- import { DisposableCollection, Emitter as Emitter3 } from "@flowgram.ai/utils";
1342
+ import { DisposableCollection, Emitter as Emitter4 } from "@flowgram.ai/utils";
1245
1343
  import { FlowNodeRenderData as FlowNodeRenderData2, FlowNodeTransformData as FlowNodeTransformData3 } from "@flowgram.ai/document";
1246
1344
  import { EntityManager as EntityManager2, PlaygroundConfigEntity as PlaygroundConfigEntity2 } from "@flowgram.ai/core";
1247
1345
 
@@ -1325,8 +1423,8 @@ var WorkflowLinesManager = class {
1325
1423
  this.toDispose = new DisposableCollection();
1326
1424
  // 线条类型
1327
1425
  this._lineType = 0 /* BEZIER */;
1328
- this.onAvailableLinesChangeEmitter = new Emitter3();
1329
- this.onForceUpdateEmitter = new Emitter3();
1426
+ this.onAvailableLinesChangeEmitter = new Emitter4();
1427
+ this.onForceUpdateEmitter = new Emitter4();
1330
1428
  /**
1331
1429
  * 有效的线条被添加或者删除时候触发,未连上的线条不算
1332
1430
  */
@@ -1397,6 +1495,9 @@ var WorkflowLinesManager = class {
1397
1495
  WorkflowLineEntity.portInfoToLineId(portInfo)
1398
1496
  );
1399
1497
  }
1498
+ getLineById(id) {
1499
+ return this.entityManager.getEntityById(id);
1500
+ }
1400
1501
  replaceLine(oldPortInfo, newPortInfo) {
1401
1502
  const oldLine = this.getLine(oldPortInfo);
1402
1503
  if (oldLine) {
@@ -1405,7 +1506,7 @@ var WorkflowLinesManager = class {
1405
1506
  return this.createLine(newPortInfo);
1406
1507
  }
1407
1508
  createLine(options) {
1408
- const { from, to, drawingTo, fromPort, toPort } = options;
1509
+ const { from, to, drawingTo, fromPort, toPort, data } = options;
1409
1510
  const available = Boolean(from && to);
1410
1511
  const key = options.key || WorkflowLineEntity.portInfoToLineId(options);
1411
1512
  let line = this.entityManager.getEntityById(key);
@@ -1428,7 +1529,8 @@ var WorkflowLinesManager = class {
1428
1529
  fromPort,
1429
1530
  toPort,
1430
1531
  to,
1431
- drawingTo
1532
+ drawingTo,
1533
+ data
1432
1534
  });
1433
1535
  this.registerData(line);
1434
1536
  fromNode.addLine(line);
@@ -1449,6 +1551,14 @@ var WorkflowLinesManager = class {
1449
1551
  });
1450
1552
  }
1451
1553
  });
1554
+ line.onLineDataChange(({ oldValue }) => {
1555
+ this.onAvailableLinesChangeEmitter.fire({
1556
+ type: "LINE_DATA_CHANGE" /* LINE_DATA_CHANGE */,
1557
+ toJSON: () => line.toJSON(),
1558
+ oldValue,
1559
+ entity: line
1560
+ });
1561
+ });
1452
1562
  if (available) {
1453
1563
  this.onAvailableLinesChangeEmitter.fire({
1454
1564
  type: "ADD_LINE" /* ADD_LINE */,
@@ -1512,12 +1622,6 @@ var WorkflowLinesManager = class {
1512
1622
  }
1513
1623
  return defaultValue;
1514
1624
  }
1515
- isVerticalLine(line, defaultValue = false) {
1516
- if (this.options.isVerticalLine) {
1517
- return this.options.isVerticalLine(line);
1518
- }
1519
- return defaultValue;
1520
- }
1521
1625
  setLineRenderType(line) {
1522
1626
  if (this.options.setLineRenderType) {
1523
1627
  return this.options.setLineRenderType(line);
@@ -1561,6 +1665,14 @@ var WorkflowLinesManager = class {
1561
1665
  if (fromPort === toPort || fromPort.node === toPort.node || fromPort.portType !== "output" || toPort.portType !== "input" || toPort.disabled) {
1562
1666
  return false;
1563
1667
  }
1668
+ const fromCanAdd = fromPort.node.getNodeRegistry().canAddLine;
1669
+ const toCanAdd = toPort.node.getNodeRegistry().canAddLine;
1670
+ if (fromCanAdd && !fromCanAdd(fromPort, toPort, this, silent)) {
1671
+ return false;
1672
+ }
1673
+ if (toCanAdd && !toCanAdd(fromPort, toPort, this, silent)) {
1674
+ return false;
1675
+ }
1564
1676
  if (this.options.canAddLine) {
1565
1677
  return this.options.canAddLine(fromPort, toPort, this, silent);
1566
1678
  }
@@ -1664,7 +1776,7 @@ WorkflowLinesManager = __decorateClass([
1664
1776
  // src/workflow-document.ts
1665
1777
  import { customAlphabet } from "nanoid";
1666
1778
  import { inject as inject5, injectable as injectable5, optional, postConstruct } from "inversify";
1667
- import { Emitter as Emitter4 } from "@flowgram.ai/utils";
1779
+ import { Emitter as Emitter5 } from "@flowgram.ai/utils";
1668
1780
  import { NodeEngineContext } from "@flowgram.ai/form-core";
1669
1781
  import {
1670
1782
  FlowDocument,
@@ -1825,10 +1937,10 @@ var WorkflowDocumentProvider = Symbol("WorkflowDocumentProvider");
1825
1937
  var WorkflowDocument = class extends FlowDocument {
1826
1938
  constructor() {
1827
1939
  super(...arguments);
1828
- this._onContentChangeEmitter = new Emitter4();
1829
- this.onLoadedEmitter = new Emitter4();
1940
+ this._onContentChangeEmitter = new Emitter5();
1941
+ this.onLoadedEmitter = new Emitter5();
1830
1942
  this.onContentChange = this._onContentChangeEmitter.event;
1831
- this._onReloadEmitter = new Emitter4();
1943
+ this._onReloadEmitter = new Emitter5();
1832
1944
  this.onReload = this._onReloadEmitter.event;
1833
1945
  /**
1834
1946
  * 数据加载完成
@@ -1840,6 +1952,11 @@ var WorkflowDocument = class extends FlowDocument {
1840
1952
  get loading() {
1841
1953
  return this._loading;
1842
1954
  }
1955
+ /**
1956
+ * use `ctx.tools.fitView()` instead
1957
+ * @deprecated
1958
+ * @param easing
1959
+ */
1843
1960
  async fitView(easing) {
1844
1961
  return fitView(this, this.playgroundConfig, easing).then(() => {
1845
1962
  this.linesManager.forceUpdate();
@@ -2147,10 +2264,13 @@ var WorkflowDocument = class extends FlowDocument {
2147
2264
  from: line.from.id,
2148
2265
  to: line.to.id
2149
2266
  }));
2150
- const startNodeId = allNode.find((node) => node.isStart).id;
2151
- const endNodeId = allNode.find((node) => node.isNodeEnd).id;
2267
+ const startNodeId = allNode.find((node) => node.isStart)?.id;
2268
+ const endNodeId = allNode.find((node) => node.isNodeEnd)?.id;
2152
2269
  const nodeInContainer = allNode.filter((node) => node.parent?.getNodeMeta().isContainer).map((node) => node.id);
2153
- const associatedCache = /* @__PURE__ */ new Set([endNodeId, ...nodeInContainer]);
2270
+ const associatedCache = new Set(nodeInContainer);
2271
+ if (endNodeId) {
2272
+ associatedCache.add(endNodeId);
2273
+ }
2154
2274
  const bfs = (nodeId) => {
2155
2275
  if (associatedCache.has(nodeId)) {
2156
2276
  return;
@@ -2164,7 +2284,9 @@ var WorkflowDocument = class extends FlowDocument {
2164
2284
  }, []);
2165
2285
  nextNodes.forEach(bfs);
2166
2286
  };
2167
- bfs(startNodeId);
2287
+ if (startNodeId) {
2288
+ bfs(startNodeId);
2289
+ }
2168
2290
  const associatedNodes = allNode.filter((node) => associatedCache.has(node.id));
2169
2291
  return associatedNodes;
2170
2292
  }
@@ -2286,6 +2408,11 @@ var WorkflowDocument = class extends FlowDocument {
2286
2408
  * 导出数据
2287
2409
  */
2288
2410
  toJSON() {
2411
+ if (this.disposed) {
2412
+ throw new Error(
2413
+ "The WorkflowDocument has been disposed and it is no longer possible to call toJSON."
2414
+ );
2415
+ }
2289
2416
  const rootJSON = this.toNodeJSON(this.root);
2290
2417
  const json = {
2291
2418
  nodes: rootJSON.blocks ?? [],
@@ -2366,7 +2493,8 @@ var WorkflowDocument = class extends FlowDocument {
2366
2493
  from: json.sourceNodeID,
2367
2494
  fromPort: json.sourcePortID,
2368
2495
  to: json.targetNodeID,
2369
- toPort: json.targetPortID
2496
+ toPort: json.targetPortID,
2497
+ data: json.data
2370
2498
  };
2371
2499
  if (!parentId) {
2372
2500
  return this.linesManager.createLine(lineInfo);
@@ -2431,10 +2559,10 @@ function checkDragSuccess(time, e, originLine) {
2431
2559
  }
2432
2560
  var WorkflowDragService = class {
2433
2561
  constructor() {
2434
- this._onDragLineEventEmitter = new Emitter5();
2562
+ this._onDragLineEventEmitter = new Emitter6();
2435
2563
  this.onDragLineEventChange = this._onDragLineEventEmitter.event;
2436
2564
  this.isDragging = false;
2437
- this._nodesDragEmitter = new Emitter5();
2565
+ this._nodesDragEmitter = new Emitter6();
2438
2566
  this.onNodesDrag = this._nodesDragEmitter.event;
2439
2567
  this._toDispose = new DisposableCollection2();
2440
2568
  this._droppableTransforms = [];
@@ -2833,10 +2961,16 @@ var WorkflowDragService = class {
2833
2961
  originLine.highlightColor = this.linesManager.lineColor.hidden;
2834
2962
  }
2835
2963
  dragSuccess = true;
2964
+ const pos = config.getPosFromMouseEvent(event);
2836
2965
  line = this.linesManager.createLine({
2837
2966
  from: fromPort.node.id,
2838
2967
  fromPort: fromPort.portID,
2839
- drawingTo: config.getPosFromMouseEvent(event)
2968
+ data: originLine?.lineData,
2969
+ drawingTo: {
2970
+ x: pos.x,
2971
+ y: pos.y,
2972
+ location: fromPort.location === "right" ? "left" : "top"
2973
+ }
2840
2974
  });
2841
2975
  if (!line) {
2842
2976
  return;
@@ -2871,9 +3005,17 @@ var WorkflowDragService = class {
2871
3005
  lineErrorReset = hasError;
2872
3006
  }
2873
3007
  if (line.toPort) {
2874
- line.drawingTo = { x: line.toPort.point.x, y: line.toPort.point.y };
3008
+ line.drawingTo = {
3009
+ x: line.toPort.point.x,
3010
+ y: line.toPort.point.y,
3011
+ location: line.toPort.location
3012
+ };
2875
3013
  } else {
2876
- line.drawingTo = { x: dragPos.x, y: dragPos.y };
3014
+ line.drawingTo = {
3015
+ x: dragPos.x,
3016
+ y: dragPos.y,
3017
+ location: line.fromPort.location === "right" ? "left" : "top"
3018
+ };
2877
3019
  }
2878
3020
  originLine?.validate();
2879
3021
  line.validate();
@@ -2917,7 +3059,8 @@ var WorkflowDragService = class {
2917
3059
  from: fromPort.node.id,
2918
3060
  fromPort: fromPort.portID,
2919
3061
  to: toPort.node.id,
2920
- toPort: toPort.portID
3062
+ toPort: toPort.portID,
3063
+ data: originLine?.lineData
2921
3064
  } : void 0;
2922
3065
  const isReset = originLine && toPort;
2923
3066
  if (isReset && !this.linesManager.canReset(
@@ -3030,7 +3173,7 @@ WorkflowDragService = __decorateClass([
3030
3173
  import { inject as inject7, injectable as injectable7, postConstruct as postConstruct3 } from "inversify";
3031
3174
  import { PlaygroundConfigEntity as PlaygroundConfigEntity6 } from "@flowgram.ai/core";
3032
3175
  import { EntityManager as EntityManager3 } from "@flowgram.ai/core";
3033
- import { DisposableCollection as DisposableCollection3, Emitter as Emitter6 } from "@flowgram.ai/utils";
3176
+ import { DisposableCollection as DisposableCollection3, Emitter as Emitter7 } from "@flowgram.ai/utils";
3034
3177
 
3035
3178
  // src/utils/layout-to-positions.ts
3036
3179
  import { FlowNodeTransformData as FlowNodeTransformData7 } from "@flowgram.ai/document";
@@ -3075,7 +3218,7 @@ var layoutToPositions = async (nodes, nodePositionMap) => {
3075
3218
  // src/service/workflow-reset-layout-service.ts
3076
3219
  var WorkflowResetLayoutService = class {
3077
3220
  constructor() {
3078
- this._resetLayoutEmitter = new Emitter6();
3221
+ this._resetLayoutEmitter = new Emitter7();
3079
3222
  /**
3080
3223
  * reset layout事件
3081
3224
  */
@@ -3134,13 +3277,13 @@ WorkflowResetLayoutService = __decorateClass([
3134
3277
 
3135
3278
  // src/service/workflow-operation-base-service.ts
3136
3279
  import { inject as inject8 } from "inversify";
3137
- import { Emitter as Emitter7 } from "@flowgram.ai/utils";
3280
+ import { Emitter as Emitter8 } from "@flowgram.ai/utils";
3138
3281
  import { FlowOperationBaseServiceImpl } from "@flowgram.ai/document";
3139
3282
  import { TransformData as TransformData10 } from "@flowgram.ai/core";
3140
3283
  var WorkflowOperationBaseServiceImpl = class extends FlowOperationBaseServiceImpl {
3141
3284
  constructor() {
3142
3285
  super(...arguments);
3143
- this.onNodePostionUpdateEmitter = new Emitter7();
3286
+ this.onNodePostionUpdateEmitter = new Emitter8();
3144
3287
  this.onNodePostionUpdate = this.onNodePostionUpdateEmitter.event;
3145
3288
  }
3146
3289
  updateNodePosition(nodeOrId, position) {
@@ -3187,6 +3330,7 @@ function usePlaygroundReadonlyState(listenChange) {
3187
3330
  function checkTargetDraggable(el) {
3188
3331
  return el && el.tagName !== "INPUT" && el.tagName !== "TEXTAREA" && !el.closest(".flow-canvas-not-draggable");
3189
3332
  }
3333
+ var isFirefox = navigator?.userAgent?.includes?.("Firefox");
3190
3334
  function useNodeRender(nodeFromProps) {
3191
3335
  const node = nodeFromProps || useContext(PlaygroundEntityContext);
3192
3336
  const renderData = node.getData(FlowNodeRenderData3);
@@ -3250,7 +3394,6 @@ function useNodeRender(nodeFromProps) {
3250
3394
  );
3251
3395
  const deleteNode = useCallback(() => node.dispose(), [node]);
3252
3396
  useListenEvents(portsData.onDataChange);
3253
- const isFirefox = navigator?.userAgent?.includes?.("Firefox");
3254
3397
  const onFocus = useCallback(() => {
3255
3398
  if (isFirefox) {
3256
3399
  nodeRef.current?.setAttribute("draggable", "false");