@flowgram.ai/free-layout-core 0.1.0-alpha.15 → 0.1.0-alpha.17

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/dist/index.js CHANGED
@@ -26,8 +26,8 @@ var __decorateClass = (decorators, target, key, kind) => {
26
26
  };
27
27
 
28
28
  // src/index.ts
29
- var src_exports = {};
30
- __export(src_exports, {
29
+ var index_exports = {};
30
+ __export(index_exports, {
31
31
  EditorCursorState: () => EditorCursorState,
32
32
  InteractiveType: () => InteractiveType,
33
33
  LINE_HOVER_DISTANCE: () => LINE_HOVER_DISTANCE,
@@ -79,13 +79,12 @@ __export(src_exports, {
79
79
  usePlayground: () => import_core25.usePlayground,
80
80
  usePlaygroundContainer: () => import_core25.usePlaygroundContainer,
81
81
  usePlaygroundContext: () => import_core25.usePlaygroundContext,
82
- usePlaygroundLatest: () => import_core25.usePlaygroundLatest,
83
82
  usePlaygroundReadonlyState: () => usePlaygroundReadonlyState,
84
83
  useRefresh: () => import_core25.useRefresh,
85
84
  useService: () => import_core25.useService,
86
85
  useWorkflowDocument: () => useWorkflowDocument
87
86
  });
88
- module.exports = __toCommonJS(src_exports);
87
+ module.exports = __toCommonJS(index_exports);
89
88
 
90
89
  // src/workflow-commands.ts
91
90
  var WorkflowCommands = /* @__PURE__ */ ((WorkflowCommands2) => {
@@ -819,16 +818,8 @@ var WorkflowLineRenderData = class extends import_core7.EntityData {
819
818
  * WARNING: 这个方法,必须在 requestAnimationFrame / useLayoutEffect 中调用,否则会引起浏览器强制重排
820
819
  */
821
820
  updatePosition() {
822
- this.data.position.from = this.entity.from.getData(WorkflowNodePortsData).getOutputPoint(this.entity.info.fromPort);
823
- if (this.entity.info.drawingTo) {
824
- this.data.position.to = this.entity.info.drawingTo;
825
- } else {
826
- this.data.position.to = this.entity.to?.getData(WorkflowNodePortsData)?.getInputPoint(this.entity.info.toPort) ?? {
827
- x: this.data.position.from.x,
828
- y: this.data.position.from.y,
829
- location: this.data.position.from.location === "right" ? "left" : "top"
830
- };
831
- }
821
+ this.data.position.from = this.entity.drawingFrom || this.entity.fromPort.point;
822
+ this.data.position.to = this.entity.drawingTo || this.entity.toPort.point;
832
823
  this.data.version = [
833
824
  this.lineType,
834
825
  this.data.position.from.x,
@@ -893,10 +884,11 @@ var _WorkflowLineEntity = class _WorkflowLineEntity extends import_core8.Entity
893
884
  to: opts.to,
894
885
  drawingTo: opts.drawingTo,
895
886
  fromPort: opts.fromPort,
887
+ drawingFrom: opts.drawingFrom,
896
888
  toPort: opts.toPort,
897
889
  data: opts.data
898
890
  });
899
- if (opts.drawingTo) {
891
+ if (opts.drawingTo || opts.drawingFrom) {
900
892
  this.isDrawing = true;
901
893
  }
902
894
  this.onEntityChange(() => {
@@ -1031,6 +1023,30 @@ var _WorkflowLineEntity = class _WorkflowLineEntity extends import_core8.Entity
1031
1023
  }
1032
1024
  this.fireChange();
1033
1025
  }
1026
+ setFromPort(fromPort) {
1027
+ if (!this.isDrawing) {
1028
+ throw new Error("[setFromPort] only support drawing line.");
1029
+ }
1030
+ if (this.fromPort === fromPort) {
1031
+ return;
1032
+ }
1033
+ const prePort = this.fromPort;
1034
+ if (fromPort && fromPort.portType === "output" && this.linesManager.canAddLine(fromPort, this.toPort, true)) {
1035
+ const { node, portID } = fromPort;
1036
+ this._from = node;
1037
+ this.info.drawingFrom = void 0;
1038
+ this.info.from = node.id;
1039
+ this.info.fromPort = portID;
1040
+ } else {
1041
+ this._from = void 0;
1042
+ this.info.from = void 0;
1043
+ this.info.fromPort = "";
1044
+ }
1045
+ if (prePort) {
1046
+ prePort.validate();
1047
+ }
1048
+ this.fireChange();
1049
+ }
1034
1050
  /**
1035
1051
  * 设置线条画线时的目标位置
1036
1052
  */
@@ -1047,6 +1063,22 @@ var _WorkflowLineEntity = class _WorkflowLineEntity extends import_core8.Entity
1047
1063
  this.fireChange();
1048
1064
  }
1049
1065
  }
1066
+ set drawingFrom(pos) {
1067
+ const oldDrawingFrom = this.info.drawingFrom;
1068
+ if (!pos) {
1069
+ this.info.drawingFrom = void 0;
1070
+ this.fireChange();
1071
+ return;
1072
+ }
1073
+ if (!oldDrawingFrom || pos.x !== oldDrawingFrom.x || pos.y !== oldDrawingFrom.y) {
1074
+ this.info.from = void 0;
1075
+ this.info.drawingFrom = pos;
1076
+ this.fireChange();
1077
+ }
1078
+ }
1079
+ get drawingFrom() {
1080
+ return this.info.drawingFrom;
1081
+ }
1050
1082
  /**
1051
1083
  * 获取线条正在画线的位置
1052
1084
  */
@@ -1085,13 +1117,16 @@ var _WorkflowLineEntity = class _WorkflowLineEntity extends import_core8.Entity
1085
1117
  return this.getData(WorkflowLineRenderData).calcDistance(pos);
1086
1118
  }
1087
1119
  get fromPort() {
1088
- return this.from.getData(WorkflowNodePortsData).getPortEntityByKey("output", this.info.fromPort);
1120
+ if (!this.from) {
1121
+ return void 0;
1122
+ }
1123
+ return this.from.ports.getPortEntityByKey("output", this.info.fromPort);
1089
1124
  }
1090
1125
  get toPort() {
1091
1126
  if (!this.to) {
1092
1127
  return void 0;
1093
1128
  }
1094
- return this.to.getData(WorkflowNodePortsData).getPortEntityByKey("input", this.info.toPort);
1129
+ return this.to.ports.getPortEntityByKey("input", this.info.toPort);
1095
1130
  }
1096
1131
  /**
1097
1132
  * 获取线条真实的输入输出节点坐标
@@ -1125,7 +1160,7 @@ var _WorkflowLineEntity = class _WorkflowLineEntity extends import_core8.Entity
1125
1160
  * @deprecated
1126
1161
  */
1127
1162
  get vertical() {
1128
- const fromLocation = this.fromPort.location;
1163
+ const fromLocation = this.fromPort?.location;
1129
1164
  const toLocation = this.toPort?.location;
1130
1165
  if (toLocation) {
1131
1166
  return toLocation === "top";
@@ -1151,7 +1186,7 @@ var _WorkflowLineEntity = class _WorkflowLineEntity extends import_core8.Entity
1151
1186
  initInfo(info) {
1152
1187
  if (!(0, import_lodash_es2.isEqual)(info, this.info)) {
1153
1188
  this.info = info;
1154
- this._from = this.document.getNode(info.from);
1189
+ this._from = info.from ? this.document.getNode(info.from) : void 0;
1155
1190
  this._to = info.to ? this.document.getNode(info.to) : void 0;
1156
1191
  this._lineData = info.data;
1157
1192
  this.fireChange();
@@ -1185,7 +1220,7 @@ var _WorkflowLineEntity = class _WorkflowLineEntity extends import_core8.Entity
1185
1220
  this._node = import_utils8.domUtils.createDivWithClass("gedit-flow-activity-line");
1186
1221
  this._node.dataset.testid = "sdk.workflow.canvas.line";
1187
1222
  this._node.dataset.lineId = this.id;
1188
- this._node.dataset.fromNodeId = this.from.id;
1223
+ this._node.dataset.fromNodeId = this.from?.id ?? "";
1189
1224
  this._node.dataset.fromPortId = this.fromPort?.id ?? "";
1190
1225
  this._node.dataset.toNodeId = this.to?.id ?? "";
1191
1226
  this._node.dataset.toPortId = this.toPort?.id ?? "";
@@ -1367,10 +1402,17 @@ var WorkflowHoverService = class {
1367
1402
  }
1368
1403
  /**
1369
1404
  * 获取被 hover 的节点或线条
1405
+ * @deprecated use 'someHovered' instead
1370
1406
  */
1371
1407
  get hoveredNode() {
1372
1408
  return this.entityManager.getEntityById(this.hoveredKey);
1373
1409
  }
1410
+ /**
1411
+ * 获取被 hover 的节点或线条
1412
+ */
1413
+ get someHovered() {
1414
+ return this.entityManager.getEntityById(this.hoveredKey);
1415
+ }
1374
1416
  };
1375
1417
  __decorateClass([
1376
1418
  (0, import_inversify2.inject)(import_core10.EntityManager)
@@ -1575,6 +1617,9 @@ var WorkflowLinesManager = class {
1575
1617
  getAllLines() {
1576
1618
  return this.entityManager.getEntities(WorkflowLineEntity);
1577
1619
  }
1620
+ getAllAvailableLines() {
1621
+ return this.getAllLines().filter((l) => !l.isDrawing && !l.isHidden);
1622
+ }
1578
1623
  hasLine(portInfo) {
1579
1624
  return !!this.entityManager.getEntityById(
1580
1625
  WorkflowLineEntity.portInfoToLineId(portInfo)
@@ -1596,7 +1641,7 @@ var WorkflowLinesManager = class {
1596
1641
  return this.createLine(newPortInfo);
1597
1642
  }
1598
1643
  createLine(options) {
1599
- const { from, to, drawingTo, fromPort, toPort, data } = options;
1644
+ const { from, to, drawingTo, fromPort, drawingFrom, toPort, data } = options;
1600
1645
  const available = Boolean(from && to);
1601
1646
  const key = options.key || WorkflowLineEntity.portInfoToLineId(options);
1602
1647
  let line = this.entityManager.getEntityById(key);
@@ -1605,12 +1650,12 @@ var WorkflowLinesManager = class {
1605
1650
  line.validate();
1606
1651
  return line;
1607
1652
  }
1608
- const fromNode = this.entityManager.getEntityById(from)?.getData(WorkflowNodeLinesData);
1653
+ const fromNode = from ? this.entityManager.getEntityById(from).getData(WorkflowNodeLinesData) : void 0;
1609
1654
  const toNode = to ? this.entityManager.getEntityById(to).getData(WorkflowNodeLinesData) : void 0;
1610
- if (!fromNode) {
1655
+ if (!fromNode && !toNode) {
1611
1656
  return;
1612
1657
  }
1613
- this.isDrawing = Boolean(drawingTo);
1658
+ this.isDrawing = Boolean(drawingTo || drawingFrom);
1614
1659
  line = this.entityManager.createEntity(WorkflowLineEntity, {
1615
1660
  id: key,
1616
1661
  document: this.document,
@@ -1620,16 +1665,15 @@ var WorkflowLinesManager = class {
1620
1665
  toPort,
1621
1666
  to,
1622
1667
  drawingTo,
1668
+ drawingFrom,
1623
1669
  data
1624
1670
  });
1625
1671
  this.registerData(line);
1626
- fromNode.addLine(line);
1672
+ fromNode?.addLine(line);
1627
1673
  toNode?.addLine(line);
1628
1674
  line.onDispose(() => {
1629
- if (drawingTo) {
1630
- this.isDrawing = false;
1631
- }
1632
- fromNode.removeLine(line);
1675
+ this.isDrawing = false;
1676
+ fromNode?.removeLine(line);
1633
1677
  toNode?.removeLine(line);
1634
1678
  });
1635
1679
  line.onDispose(() => {
@@ -1752,7 +1796,7 @@ var WorkflowLinesManager = class {
1752
1796
  return this.lineColor.default;
1753
1797
  }
1754
1798
  canAddLine(fromPort, toPort, silent) {
1755
- if (fromPort === toPort || fromPort.node === toPort.node || fromPort.portType !== "output" || toPort.portType !== "input" || toPort.disabled) {
1799
+ if (fromPort === toPort || fromPort.node === toPort.node || fromPort.portType !== "output" || toPort.portType !== "input" || fromPort.disabled || toPort.disabled) {
1756
1800
  return false;
1757
1801
  }
1758
1802
  const fromCanAdd = fromPort.node.getNodeRegistry().canAddLine;
@@ -1780,8 +1824,8 @@ var WorkflowLinesManager = class {
1780
1824
  }
1781
1825
  return true;
1782
1826
  }
1783
- canReset(fromPort, oldToPort, newToPort) {
1784
- if (this.options && this.options.canResetLine && !this.options.canResetLine(fromPort, oldToPort, newToPort, this)) {
1827
+ canReset(oldLine, newLineInfo) {
1828
+ if (this.options && this.options.canResetLine && !this.options.canResetLine(oldLine, newLineInfo, this)) {
1785
1829
  return false;
1786
1830
  }
1787
1831
  return true;
@@ -1790,9 +1834,14 @@ var WorkflowLinesManager = class {
1790
1834
  * 根据鼠标位置找到 port
1791
1835
  * @param pos
1792
1836
  */
1793
- getPortFromMousePos(pos) {
1837
+ getPortFromMousePos(pos, portType) {
1794
1838
  const allNodes = this.getSortedNodes().reverse();
1795
- const allPorts = allNodes.map((node) => node.getData(WorkflowNodePortsData).allPorts).flat();
1839
+ const allPorts = allNodes.map((node) => {
1840
+ if (!portType) {
1841
+ return node.ports.allPorts;
1842
+ }
1843
+ return portType === "input" ? node.ports.inputPorts : node.ports.outputPorts;
1844
+ }).flat();
1796
1845
  const targetPort = allPorts.find((port) => port.isHovered(pos.x, pos.y));
1797
1846
  if (targetPort) {
1798
1847
  const containNodes = this.getContainNodesFromMousePos(pos);
@@ -2231,8 +2280,11 @@ var WorkflowDocument = class extends import_document8.FlowDocument {
2231
2280
  originParent,
2232
2281
  meta
2233
2282
  });
2283
+ this.options.preNodeCreate?.(node);
2234
2284
  const datas = dataRegistries ? this.nodeDataRegistries.concat(...dataRegistries) : this.nodeDataRegistries;
2235
2285
  node.addInitializeData(datas);
2286
+ node.ports = node.getData(WorkflowNodePortsData);
2287
+ node.lines = node.getData(WorkflowNodeLinesData);
2236
2288
  node.onDispose(() => this.onNodeDisposeEmitter.fire({ node }));
2237
2289
  this.options.fromNodeJSON?.(node, data, true);
2238
2290
  isNew = true;
@@ -2683,10 +2735,6 @@ var WorkflowDragService = class {
2683
2735
  return Promise.resolve(false);
2684
2736
  }
2685
2737
  this.isDragging = true;
2686
- const sameParent = this.childrenOfContainer(selectedNodes);
2687
- if (sameParent && sameParent.flowNodeType !== import_document10.FlowNodeBaseType.ROOT) {
2688
- selectedNodes = [sameParent];
2689
- }
2690
2738
  let startPosition = this.getNodesPosition(selectedNodes);
2691
2739
  let startPositions = selectedNodes.map((node) => {
2692
2740
  const transform = node.getData(import_core15.TransformData);
@@ -2748,6 +2796,7 @@ var WorkflowDragService = class {
2748
2796
  triggerEvent,
2749
2797
  dragger
2750
2798
  });
2799
+ this.resetContainerInternalPosition(selectedNodes);
2751
2800
  }
2752
2801
  });
2753
2802
  const { clientX, clientY } = import_core15.MouseTouchEvent.getEventCoord(triggerEvent);
@@ -2788,7 +2837,7 @@ var WorkflowDragService = class {
2788
2837
  const targetNode = event.currentTarget;
2789
2838
  domNode = cloneNode ? cloneNode(e) : targetNode.cloneNode(true);
2790
2839
  const bounds = targetNode.getBoundingClientRect();
2791
- startPos = { x: bounds.left, y: bounds.top };
2840
+ startPos = { x: bounds.left + window.scrollX, y: bounds.top + window.scrollY };
2792
2841
  import_utils16.domUtils.setStyle(domNode, {
2793
2842
  zIndex: 1e3,
2794
2843
  position: "absolute",
@@ -2996,18 +3045,30 @@ var WorkflowDragService = class {
2996
3045
  line.highlightColor = color;
2997
3046
  this.hoverService.clearHovered();
2998
3047
  }
2999
- handleDragOnNode(toNode, fromPort, line, toPort, originLine) {
3000
- if (toPort && (originLine?.toPort === toPort || toPort.portType === "input" && this.linesManager.canAddLine(fromPort, toPort, true))) {
3001
- this.hoverService.updateHoveredKey(toPort.id);
3002
- line.setToPort(toPort);
3048
+ checkDraggingPort(isDrawingTo, line, draggingNode, draggingPort, originLine) {
3049
+ let successDrawing = false;
3050
+ if (isDrawingTo) {
3051
+ successDrawing = !!(draggingPort && // 同一条线条则不用在判断 canAddLine
3052
+ (originLine?.toPort === draggingPort || draggingPort.portType === "input" && this.linesManager.canAddLine(line.fromPort, draggingPort, true)));
3053
+ } else {
3054
+ successDrawing = !!(draggingPort && // 同一条线条则不用在判断 canAddLine
3055
+ (originLine?.fromPort === draggingPort || draggingPort.portType === "output" && this.linesManager.canAddLine(draggingPort, line.toPort, true)));
3056
+ }
3057
+ if (successDrawing) {
3058
+ this.hoverService.updateHoveredKey(draggingPort.id);
3059
+ if (isDrawingTo) {
3060
+ line.setToPort(draggingPort);
3061
+ } else {
3062
+ line.setFromPort(draggingPort);
3063
+ }
3003
3064
  this._onDragLineEventEmitter.fire({
3004
3065
  type: "onDrag",
3005
- onDragNodeId: toNode.id
3066
+ onDragNodeId: draggingNode.id
3006
3067
  });
3007
3068
  return {
3008
3069
  hasError: false
3009
3070
  };
3010
- } else if (this.isContainer(toNode)) {
3071
+ } else if (this.isContainer(draggingNode)) {
3011
3072
  return {
3012
3073
  hasError: false
3013
3074
  };
@@ -3018,12 +3079,48 @@ var WorkflowDragService = class {
3018
3079
  };
3019
3080
  }
3020
3081
  }
3082
+ /**
3083
+ * 容器内子节点总体位置重置为0
3084
+ */
3085
+ resetContainerInternalPosition(nodes) {
3086
+ const container = this.childrenOfContainer(nodes);
3087
+ if (!container) {
3088
+ return;
3089
+ }
3090
+ const bounds = import_utils16.Rectangle.enlarge(
3091
+ container.blocks.map((node) => {
3092
+ const x = node.transform.position.x - node.transform.bounds.width / 2;
3093
+ const y = node.transform.position.y;
3094
+ const width = node.transform.bounds.width;
3095
+ const height = node.transform.bounds.height;
3096
+ return new import_utils16.Rectangle(x, y, width, height);
3097
+ })
3098
+ );
3099
+ const containerTransform = container.getData(import_core15.TransformData);
3100
+ containerTransform.update({
3101
+ position: {
3102
+ x: containerTransform.position.x + bounds.x,
3103
+ y: containerTransform.position.y + bounds.y
3104
+ }
3105
+ });
3106
+ this.document.layout.updateAffectedTransform(container);
3107
+ container.blocks.forEach((node) => {
3108
+ const transform = node.getData(import_core15.TransformData);
3109
+ transform.update({
3110
+ position: {
3111
+ x: transform.position.x - bounds.x,
3112
+ y: transform.position.y - bounds.y
3113
+ }
3114
+ });
3115
+ this.document.layout.updateAffectedTransform(node);
3116
+ });
3117
+ }
3021
3118
  childrenOfContainer(nodes) {
3022
3119
  if (nodes.length === 0) {
3023
3120
  return;
3024
3121
  }
3025
3122
  const sourceContainer = nodes[0]?.parent;
3026
- if (!sourceContainer || sourceContainer.collapsedChildren.length !== nodes.length) {
3123
+ if (!sourceContainer || sourceContainer.flowNodeType === import_document10.FlowNodeBaseType.ROOT) {
3027
3124
  return;
3028
3125
  }
3029
3126
  const valid = nodes.every((node) => node?.parent === sourceContainer);
@@ -3037,16 +3134,18 @@ var WorkflowDragService = class {
3037
3134
  * @param opts
3038
3135
  * @param event
3039
3136
  */
3040
- async startDrawingLine(fromPort, event, originLine) {
3041
- const isFromInActivePort = !originLine && fromPort.isErrorPort() && fromPort.disabled;
3042
- if (originLine?.disabled || isFromInActivePort || this.playgroundConfig.readonly || this.playgroundConfig.disabled) {
3137
+ async startDrawingLine(port, event, originLine) {
3138
+ const isDrawingTo = port.portType === "output";
3139
+ const isInActivePort = !originLine && port.isErrorPort() && port.disabled;
3140
+ if (originLine?.disabled || isInActivePort || this.playgroundConfig.readonly || this.playgroundConfig.disabled) {
3043
3141
  return { dragSuccess: false, newLine: void 0 };
3044
3142
  }
3045
3143
  this.selectService.clear();
3046
3144
  const config = this.playgroundConfig;
3047
3145
  const deferred = new import_utils16.PromiseDeferred();
3048
3146
  const preCursor = config.cursor;
3049
- let line, toPort, toNode, lineErrorReset = false;
3147
+ let line;
3148
+ let newLineInfo;
3050
3149
  const startTime = Date.now();
3051
3150
  let dragSuccess = false;
3052
3151
  const dragger = new import_core15.PlaygroundDrag({
@@ -3057,16 +3156,29 @@ var WorkflowDragService = class {
3057
3156
  }
3058
3157
  dragSuccess = true;
3059
3158
  const pos = config.getPosFromMouseEvent(event);
3060
- line = this.linesManager.createLine({
3061
- from: fromPort.node.id,
3062
- fromPort: fromPort.portID,
3063
- data: originLine?.lineData,
3064
- drawingTo: {
3065
- x: pos.x,
3066
- y: pos.y,
3067
- location: fromPort.location === "right" ? "left" : "top"
3068
- }
3069
- });
3159
+ if (isDrawingTo) {
3160
+ line = this.linesManager.createLine({
3161
+ from: port.node.id,
3162
+ fromPort: port.portID,
3163
+ data: originLine?.lineData,
3164
+ drawingTo: {
3165
+ x: pos.x,
3166
+ y: pos.y,
3167
+ location: port.location === "right" ? "left" : "top"
3168
+ }
3169
+ });
3170
+ } else {
3171
+ line = this.linesManager.createLine({
3172
+ to: port.node.id,
3173
+ toPort: port.portID,
3174
+ data: originLine?.lineData,
3175
+ drawingFrom: {
3176
+ x: pos.x,
3177
+ y: pos.y,
3178
+ location: port.location === "left" ? "right" : "bottom"
3179
+ }
3180
+ });
3181
+ }
3070
3182
  if (!line) {
3071
3183
  return;
3072
3184
  }
@@ -3077,49 +3189,15 @@ var WorkflowDragService = class {
3077
3189
  if (!line) {
3078
3190
  return;
3079
3191
  }
3080
- lineErrorReset = false;
3081
3192
  const dragPos = config.getPosFromMouseEvent(e);
3082
- toNode = this.linesManager.getNodeFromMousePos(dragPos);
3083
- toPort = this.linesManager.getPortFromMousePos(dragPos);
3084
- if (!toPort) {
3085
- line.setToPort(void 0);
3086
- } else if (!this.linesManager.canAddLine(fromPort, toPort, true)) {
3087
- line.highlightColor = this.linesManager.lineColor.error;
3088
- lineErrorReset = true;
3089
- line.setToPort(void 0);
3090
- } else {
3091
- line.setToPort(toPort);
3092
- }
3093
- this._onDragLineEventEmitter.fire({
3094
- type: "onDrag"
3095
- });
3096
- this.setLineColor(line, originLine?.lockedColor || this.linesManager.lineColor.drawing);
3097
- if (toNode && this.canBuildContainerLine(toNode, dragPos)) {
3098
- toPort = this.getNearestPort(toNode, dragPos);
3099
- const { hasError } = this.handleDragOnNode(toNode, fromPort, line, toPort, originLine);
3100
- lineErrorReset = hasError;
3101
- }
3102
- if (line.toPort) {
3103
- line.drawingTo = {
3104
- x: line.toPort.point.x,
3105
- y: line.toPort.point.y,
3106
- location: line.toPort.location
3107
- };
3108
- } else {
3109
- line.drawingTo = {
3110
- x: dragPos.x,
3111
- y: dragPos.y,
3112
- location: reverseLocation(line.fromPort.location)
3113
- };
3114
- }
3115
- originLine?.validate();
3116
- line.validate();
3193
+ newLineInfo = this.updateDrawingLine(isDrawingTo, line, dragPos, originLine);
3117
3194
  },
3118
3195
  // eslint-disable-next-line complexity
3119
3196
  onDragEnd: async (e) => {
3120
3197
  const dragPos = config.getPosFromMouseEvent(e);
3121
3198
  const onDragLineEndCallbacks = Array.from(this._onDragLineEndCallbacks.values());
3122
3199
  config.updateCursor(preCursor);
3200
+ const { fromPort, toPort, hasError } = newLineInfo || {};
3123
3201
  await Promise.all(
3124
3202
  onDragLineEndCallbacks.map(
3125
3203
  (callback) => callback({
@@ -3144,36 +3222,32 @@ var WorkflowDragService = class {
3144
3222
  deferred.resolve({ dragSuccess });
3145
3223
  };
3146
3224
  if (dragSuccess) {
3147
- if (originLine && originLine.toPort === toPort) {
3225
+ if (originLine && originLine.toPort === toPort && originLine.fromPort === fromPort) {
3148
3226
  return end();
3149
3227
  }
3150
- if (toPort && toPort.portType !== "input") {
3228
+ if (toPort && toPort.portType !== "input" || fromPort && fromPort.portType !== "output") {
3151
3229
  return end();
3152
3230
  }
3153
- const newLineInfo = toPort ? {
3231
+ const newLinePortInfo = toPort && fromPort ? {
3154
3232
  from: fromPort.node.id,
3155
3233
  fromPort: fromPort.portID,
3156
3234
  to: toPort.node.id,
3157
3235
  toPort: toPort.portID,
3158
3236
  data: originLine?.lineData
3159
3237
  } : void 0;
3160
- const isReset = originLine && toPort;
3161
- if (isReset && !this.linesManager.canReset(
3162
- originLine.fromPort,
3163
- originLine.toPort,
3164
- toPort
3165
- )) {
3238
+ const isReset = originLine && newLinePortInfo;
3239
+ if (isReset && !this.linesManager.canReset(originLine, newLinePortInfo)) {
3166
3240
  return end();
3167
3241
  }
3168
- if (originLine && (!this.linesManager.canRemove(originLine, newLineInfo, false) || lineErrorReset)) {
3242
+ if (originLine && (!this.linesManager.canRemove(originLine, newLinePortInfo, false) || hasError)) {
3169
3243
  return end();
3170
3244
  } else {
3171
3245
  originLine?.dispose();
3172
3246
  }
3173
- if (!toPort || !this.linesManager.canAddLine(fromPort, toPort, false)) {
3247
+ if (!newLinePortInfo || !this.linesManager.canAddLine(fromPort, toPort, false)) {
3174
3248
  return end();
3175
3249
  }
3176
- const newLine = this.linesManager.createLine(newLineInfo);
3250
+ const newLine = this.linesManager.createLine(newLinePortInfo);
3177
3251
  if (!newLine) {
3178
3252
  end();
3179
3253
  }
@@ -3190,14 +3264,109 @@ var WorkflowDragService = class {
3190
3264
  await dragger.start(clientX, clientY, config);
3191
3265
  return deferred.promise;
3192
3266
  }
3267
+ updateDrawingLine(isDrawingTo, line, dragPos, originLine) {
3268
+ let hasError = false;
3269
+ const mouseNode = this.linesManager.getNodeFromMousePos(dragPos);
3270
+ let toNode;
3271
+ let toPort;
3272
+ let fromPort;
3273
+ let fromNode;
3274
+ if (isDrawingTo) {
3275
+ fromPort = line.fromPort;
3276
+ toNode = mouseNode;
3277
+ toPort = this.linesManager.getPortFromMousePos(dragPos, "input");
3278
+ if (toNode && this.canBuildContainerLine(toNode, dragPos)) {
3279
+ toPort = this.getNearestPort(toNode, dragPos, "input");
3280
+ hasError = this.checkDraggingPort(isDrawingTo, line, toNode, toPort, originLine).hasError;
3281
+ }
3282
+ if (!toPort) {
3283
+ line.setToPort(void 0);
3284
+ } else if (!this.linesManager.canAddLine(fromPort, toPort, true)) {
3285
+ hasError = true;
3286
+ line.setToPort(void 0);
3287
+ } else {
3288
+ line.setToPort(toPort);
3289
+ }
3290
+ if (line.toPort) {
3291
+ line.drawingTo = {
3292
+ x: line.toPort.point.x,
3293
+ y: line.toPort.point.y,
3294
+ location: line.toPort.location
3295
+ };
3296
+ } else {
3297
+ line.drawingTo = {
3298
+ x: dragPos.x,
3299
+ y: dragPos.y,
3300
+ location: reverseLocation(line.fromPort.location)
3301
+ };
3302
+ }
3303
+ } else {
3304
+ toPort = line.toPort;
3305
+ fromNode = mouseNode;
3306
+ fromPort = this.linesManager.getPortFromMousePos(dragPos, "output");
3307
+ if (fromNode && this.canBuildContainerLine(fromNode, dragPos)) {
3308
+ fromPort = this.getNearestPort(fromNode, dragPos, "output");
3309
+ hasError = this.checkDraggingPort(
3310
+ isDrawingTo,
3311
+ line,
3312
+ fromNode,
3313
+ fromPort,
3314
+ originLine
3315
+ ).hasError;
3316
+ }
3317
+ if (!fromPort) {
3318
+ line.setFromPort(void 0);
3319
+ } else if (!this.linesManager.canAddLine(fromPort, toPort, true)) {
3320
+ hasError = true;
3321
+ line.setFromPort(void 0);
3322
+ } else {
3323
+ line.setFromPort(fromPort);
3324
+ }
3325
+ if (line.fromPort) {
3326
+ line.drawingFrom = {
3327
+ x: line.fromPort.point.x,
3328
+ y: line.fromPort.point.y,
3329
+ location: line.fromPort.location
3330
+ };
3331
+ } else {
3332
+ line.drawingFrom = {
3333
+ x: dragPos.x,
3334
+ y: dragPos.y,
3335
+ location: reverseLocation(line.toPort.location)
3336
+ };
3337
+ }
3338
+ }
3339
+ this._onDragLineEventEmitter.fire({
3340
+ type: "onDrag"
3341
+ });
3342
+ if (hasError) {
3343
+ this.setLineColor(line, this.linesManager.lineColor.error);
3344
+ } else {
3345
+ this.setLineColor(line, originLine?.lockedColor || this.linesManager.lineColor.drawing);
3346
+ }
3347
+ originLine?.validate();
3348
+ line.validate();
3349
+ return {
3350
+ fromPort,
3351
+ toPort,
3352
+ hasError
3353
+ };
3354
+ }
3193
3355
  /**
3194
3356
  * 重新连接线条
3195
3357
  * @param line
3196
3358
  * @param e
3197
3359
  */
3198
3360
  async resetLine(line, e) {
3199
- const { fromPort } = line;
3200
- const { dragSuccess } = await this.startDrawingLine(fromPort, e, line);
3361
+ const { fromPort, toPort } = line;
3362
+ const mousePos = this.playgroundConfig.getPosFromMouseEvent(e);
3363
+ const distanceFrom = import_utils16.Point.getDistance(fromPort.point, mousePos);
3364
+ const distanceTo = import_utils16.Point.getDistance(toPort.point, mousePos);
3365
+ const { dragSuccess } = await this.startDrawingLine(
3366
+ distanceTo <= distanceFrom || !this.document.options.twoWayConnection ? fromPort : toPort,
3367
+ e,
3368
+ line
3369
+ );
3201
3370
  if (!dragSuccess) {
3202
3371
  this.selectService.select(line);
3203
3372
  }
@@ -3219,17 +3388,27 @@ var WorkflowDragService = class {
3219
3388
  return true;
3220
3389
  }
3221
3390
  const { padding, bounds } = node.transform;
3222
- const contentRect = new import_utils16.Rectangle(bounds.x, bounds.y, padding.left * 2 / 3, bounds.height);
3223
- return contentRect.contains(mousePos.x, mousePos.y);
3391
+ const DEFAULT_DELTA = 10;
3392
+ const leftDelta = padding.left * 2 / 3 || DEFAULT_DELTA;
3393
+ const rightDelta = padding.right * 2 / 3 || DEFAULT_DELTA;
3394
+ const bottomDelta = padding.bottom * 2 / 3 || DEFAULT_DELTA;
3395
+ const topDelta = padding.top * 2 / 3 || DEFAULT_DELTA;
3396
+ const rectangles = [
3397
+ new import_utils16.Rectangle(bounds.x, bounds.y, leftDelta, bounds.height),
3398
+ // left
3399
+ new import_utils16.Rectangle(bounds.x, bounds.y, bounds.width, topDelta),
3400
+ // top
3401
+ new import_utils16.Rectangle(bounds.x, bounds.y + bounds.height - bottomDelta, bounds.width, bottomDelta),
3402
+ // bottom
3403
+ new import_utils16.Rectangle(bounds.x + bounds.width - rightDelta, bounds.y, rightDelta, bounds.height)
3404
+ // right
3405
+ ];
3406
+ return rectangles.some((rect) => rect.contains(mousePos.x, mousePos.y));
3224
3407
  }
3225
3408
  /** 获取最近的 port */
3226
- getNearestPort(node, mousePos) {
3227
- const portsData = node.getData(WorkflowNodePortsData);
3228
- const distanceSortedPorts = portsData.inputPorts.sort((a, b) => {
3229
- const aDistance = Math.abs(mousePos.y - a.point.y);
3230
- const bDistance = Math.abs(mousePos.y - b.point.y);
3231
- return aDistance - bDistance;
3232
- });
3409
+ getNearestPort(node, mousePos, portType = "input") {
3410
+ const portsData = node.ports;
3411
+ const distanceSortedPorts = (portType === "input" ? portsData.inputPorts : portsData.outputPorts).sort((a, b) => import_utils16.Point.getDistance(mousePos, a.point) - import_utils16.Point.getDistance(mousePos, b.point));
3233
3412
  return distanceSortedPorts[0];
3234
3413
  }
3235
3414
  };
@@ -3429,7 +3608,7 @@ var isFirefox = navigator?.userAgent?.includes?.("Firefox");
3429
3608
  function useNodeRender(nodeFromProps) {
3430
3609
  const node = nodeFromProps || (0, import_react2.useContext)(import_core21.PlaygroundEntityContext);
3431
3610
  const renderData = node.getData(import_document13.FlowNodeRenderData);
3432
- const portsData = node.getData(WorkflowNodePortsData);
3611
+ const portsData = node.ports;
3433
3612
  const readonly = usePlaygroundReadonlyState();
3434
3613
  const dragService = (0, import_core21.useService)(WorkflowDragService);
3435
3614
  const selectionService = (0, import_core21.useService)(WorkflowSelectService);
@@ -3654,11 +3833,35 @@ WorkflowDocumentContribution = __decorateClass([
3654
3833
 
3655
3834
  // src/utils/get-url-params.ts
3656
3835
  function getUrlParams() {
3657
- return location.search.replace(/^\?/, "").split("&").reduce((res, key) => {
3836
+ const paramsMap = /* @__PURE__ */ new Map();
3837
+ location.search.replace(/^\?/, "").split("&").forEach((key) => {
3838
+ if (!key) return;
3658
3839
  const [k, v] = key.split("=");
3659
- res[k] = v;
3660
- return res;
3661
- }, {});
3840
+ if (k) {
3841
+ const decodedKey = decodeURIComponent(k.trim());
3842
+ const decodedValue = v ? decodeURIComponent(v.trim()) : "";
3843
+ const dangerousProps = [
3844
+ "__proto__",
3845
+ "constructor",
3846
+ "prototype",
3847
+ "__defineGetter__",
3848
+ "__defineSetter__",
3849
+ "__lookupGetter__",
3850
+ "__lookupSetter__",
3851
+ "hasOwnProperty",
3852
+ "isPrototypeOf",
3853
+ "propertyIsEnumerable",
3854
+ "toString",
3855
+ "valueOf",
3856
+ "toLocaleString"
3857
+ ];
3858
+ if (dangerousProps.includes(decodedKey.toLowerCase())) {
3859
+ return;
3860
+ }
3861
+ paramsMap.set(decodedKey, decodedValue);
3862
+ }
3863
+ });
3864
+ return Object.fromEntries(paramsMap);
3662
3865
  }
3663
3866
 
3664
3867
  // src/workflow-document-container-module.ts
@@ -3734,7 +3937,6 @@ var WorkflowDocumentContainerModule = new import_inversify10.ContainerModule(
3734
3937
  usePlayground,
3735
3938
  usePlaygroundContainer,
3736
3939
  usePlaygroundContext,
3737
- usePlaygroundLatest,
3738
3940
  usePlaygroundReadonlyState,
3739
3941
  useRefresh,
3740
3942
  useService,