@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/esm/index.js CHANGED
@@ -43,8 +43,7 @@ import {
43
43
  useEntities,
44
44
  useEntityFromContext as useEntityFromContext3,
45
45
  useEntityDataFromContext,
46
- useRefresh as useRefresh2,
47
- usePlaygroundLatest
46
+ useRefresh as useRefresh2
48
47
  } from "@flowgram.ai/core";
49
48
 
50
49
  // src/hooks/use-node-render.tsx
@@ -777,16 +776,8 @@ var WorkflowLineRenderData = class extends EntityData3 {
777
776
  * WARNING: 这个方法,必须在 requestAnimationFrame / useLayoutEffect 中调用,否则会引起浏览器强制重排
778
777
  */
779
778
  updatePosition() {
780
- this.data.position.from = this.entity.from.getData(WorkflowNodePortsData).getOutputPoint(this.entity.info.fromPort);
781
- if (this.entity.info.drawingTo) {
782
- this.data.position.to = this.entity.info.drawingTo;
783
- } else {
784
- this.data.position.to = this.entity.to?.getData(WorkflowNodePortsData)?.getInputPoint(this.entity.info.toPort) ?? {
785
- x: this.data.position.from.x,
786
- y: this.data.position.from.y,
787
- location: this.data.position.from.location === "right" ? "left" : "top"
788
- };
789
- }
779
+ this.data.position.from = this.entity.drawingFrom || this.entity.fromPort.point;
780
+ this.data.position.to = this.entity.drawingTo || this.entity.toPort.point;
790
781
  this.data.version = [
791
782
  this.lineType,
792
783
  this.data.position.from.x,
@@ -851,10 +842,11 @@ var _WorkflowLineEntity = class _WorkflowLineEntity extends Entity2 {
851
842
  to: opts.to,
852
843
  drawingTo: opts.drawingTo,
853
844
  fromPort: opts.fromPort,
845
+ drawingFrom: opts.drawingFrom,
854
846
  toPort: opts.toPort,
855
847
  data: opts.data
856
848
  });
857
- if (opts.drawingTo) {
849
+ if (opts.drawingTo || opts.drawingFrom) {
858
850
  this.isDrawing = true;
859
851
  }
860
852
  this.onEntityChange(() => {
@@ -989,6 +981,30 @@ var _WorkflowLineEntity = class _WorkflowLineEntity extends Entity2 {
989
981
  }
990
982
  this.fireChange();
991
983
  }
984
+ setFromPort(fromPort) {
985
+ if (!this.isDrawing) {
986
+ throw new Error("[setFromPort] only support drawing line.");
987
+ }
988
+ if (this.fromPort === fromPort) {
989
+ return;
990
+ }
991
+ const prePort = this.fromPort;
992
+ if (fromPort && fromPort.portType === "output" && this.linesManager.canAddLine(fromPort, this.toPort, true)) {
993
+ const { node, portID } = fromPort;
994
+ this._from = node;
995
+ this.info.drawingFrom = void 0;
996
+ this.info.from = node.id;
997
+ this.info.fromPort = portID;
998
+ } else {
999
+ this._from = void 0;
1000
+ this.info.from = void 0;
1001
+ this.info.fromPort = "";
1002
+ }
1003
+ if (prePort) {
1004
+ prePort.validate();
1005
+ }
1006
+ this.fireChange();
1007
+ }
992
1008
  /**
993
1009
  * 设置线条画线时的目标位置
994
1010
  */
@@ -1005,6 +1021,22 @@ var _WorkflowLineEntity = class _WorkflowLineEntity extends Entity2 {
1005
1021
  this.fireChange();
1006
1022
  }
1007
1023
  }
1024
+ set drawingFrom(pos) {
1025
+ const oldDrawingFrom = this.info.drawingFrom;
1026
+ if (!pos) {
1027
+ this.info.drawingFrom = void 0;
1028
+ this.fireChange();
1029
+ return;
1030
+ }
1031
+ if (!oldDrawingFrom || pos.x !== oldDrawingFrom.x || pos.y !== oldDrawingFrom.y) {
1032
+ this.info.from = void 0;
1033
+ this.info.drawingFrom = pos;
1034
+ this.fireChange();
1035
+ }
1036
+ }
1037
+ get drawingFrom() {
1038
+ return this.info.drawingFrom;
1039
+ }
1008
1040
  /**
1009
1041
  * 获取线条正在画线的位置
1010
1042
  */
@@ -1043,13 +1075,16 @@ var _WorkflowLineEntity = class _WorkflowLineEntity extends Entity2 {
1043
1075
  return this.getData(WorkflowLineRenderData).calcDistance(pos);
1044
1076
  }
1045
1077
  get fromPort() {
1046
- return this.from.getData(WorkflowNodePortsData).getPortEntityByKey("output", this.info.fromPort);
1078
+ if (!this.from) {
1079
+ return void 0;
1080
+ }
1081
+ return this.from.ports.getPortEntityByKey("output", this.info.fromPort);
1047
1082
  }
1048
1083
  get toPort() {
1049
1084
  if (!this.to) {
1050
1085
  return void 0;
1051
1086
  }
1052
- return this.to.getData(WorkflowNodePortsData).getPortEntityByKey("input", this.info.toPort);
1087
+ return this.to.ports.getPortEntityByKey("input", this.info.toPort);
1053
1088
  }
1054
1089
  /**
1055
1090
  * 获取线条真实的输入输出节点坐标
@@ -1083,7 +1118,7 @@ var _WorkflowLineEntity = class _WorkflowLineEntity extends Entity2 {
1083
1118
  * @deprecated
1084
1119
  */
1085
1120
  get vertical() {
1086
- const fromLocation = this.fromPort.location;
1121
+ const fromLocation = this.fromPort?.location;
1087
1122
  const toLocation = this.toPort?.location;
1088
1123
  if (toLocation) {
1089
1124
  return toLocation === "top";
@@ -1109,7 +1144,7 @@ var _WorkflowLineEntity = class _WorkflowLineEntity extends Entity2 {
1109
1144
  initInfo(info) {
1110
1145
  if (!isEqual2(info, this.info)) {
1111
1146
  this.info = info;
1112
- this._from = this.document.getNode(info.from);
1147
+ this._from = info.from ? this.document.getNode(info.from) : void 0;
1113
1148
  this._to = info.to ? this.document.getNode(info.to) : void 0;
1114
1149
  this._lineData = info.data;
1115
1150
  this.fireChange();
@@ -1143,7 +1178,7 @@ var _WorkflowLineEntity = class _WorkflowLineEntity extends Entity2 {
1143
1178
  this._node = domUtils.createDivWithClass("gedit-flow-activity-line");
1144
1179
  this._node.dataset.testid = "sdk.workflow.canvas.line";
1145
1180
  this._node.dataset.lineId = this.id;
1146
- this._node.dataset.fromNodeId = this.from.id;
1181
+ this._node.dataset.fromNodeId = this.from?.id ?? "";
1147
1182
  this._node.dataset.fromPortId = this.fromPort?.id ?? "";
1148
1183
  this._node.dataset.toNodeId = this.to?.id ?? "";
1149
1184
  this._node.dataset.toPortId = this.toPort?.id ?? "";
@@ -1325,10 +1360,17 @@ var WorkflowHoverService = class {
1325
1360
  }
1326
1361
  /**
1327
1362
  * 获取被 hover 的节点或线条
1363
+ * @deprecated use 'someHovered' instead
1328
1364
  */
1329
1365
  get hoveredNode() {
1330
1366
  return this.entityManager.getEntityById(this.hoveredKey);
1331
1367
  }
1368
+ /**
1369
+ * 获取被 hover 的节点或线条
1370
+ */
1371
+ get someHovered() {
1372
+ return this.entityManager.getEntityById(this.hoveredKey);
1373
+ }
1332
1374
  };
1333
1375
  __decorateClass([
1334
1376
  inject2(EntityManager)
@@ -1346,7 +1388,8 @@ import {
1346
1388
  Emitter as Emitter6,
1347
1389
  DisposableCollection as DisposableCollection2,
1348
1390
  Rectangle as Rectangle8,
1349
- delay as delay2
1391
+ delay as delay2,
1392
+ Point
1350
1393
  } from "@flowgram.ai/utils";
1351
1394
  import {
1352
1395
  FlowNodeTransformData as FlowNodeTransformData6,
@@ -1510,6 +1553,9 @@ var WorkflowLinesManager = class {
1510
1553
  getAllLines() {
1511
1554
  return this.entityManager.getEntities(WorkflowLineEntity);
1512
1555
  }
1556
+ getAllAvailableLines() {
1557
+ return this.getAllLines().filter((l) => !l.isDrawing && !l.isHidden);
1558
+ }
1513
1559
  hasLine(portInfo) {
1514
1560
  return !!this.entityManager.getEntityById(
1515
1561
  WorkflowLineEntity.portInfoToLineId(portInfo)
@@ -1531,7 +1577,7 @@ var WorkflowLinesManager = class {
1531
1577
  return this.createLine(newPortInfo);
1532
1578
  }
1533
1579
  createLine(options) {
1534
- const { from, to, drawingTo, fromPort, toPort, data } = options;
1580
+ const { from, to, drawingTo, fromPort, drawingFrom, toPort, data } = options;
1535
1581
  const available = Boolean(from && to);
1536
1582
  const key = options.key || WorkflowLineEntity.portInfoToLineId(options);
1537
1583
  let line = this.entityManager.getEntityById(key);
@@ -1540,12 +1586,12 @@ var WorkflowLinesManager = class {
1540
1586
  line.validate();
1541
1587
  return line;
1542
1588
  }
1543
- const fromNode = this.entityManager.getEntityById(from)?.getData(WorkflowNodeLinesData);
1589
+ const fromNode = from ? this.entityManager.getEntityById(from).getData(WorkflowNodeLinesData) : void 0;
1544
1590
  const toNode = to ? this.entityManager.getEntityById(to).getData(WorkflowNodeLinesData) : void 0;
1545
- if (!fromNode) {
1591
+ if (!fromNode && !toNode) {
1546
1592
  return;
1547
1593
  }
1548
- this.isDrawing = Boolean(drawingTo);
1594
+ this.isDrawing = Boolean(drawingTo || drawingFrom);
1549
1595
  line = this.entityManager.createEntity(WorkflowLineEntity, {
1550
1596
  id: key,
1551
1597
  document: this.document,
@@ -1555,16 +1601,15 @@ var WorkflowLinesManager = class {
1555
1601
  toPort,
1556
1602
  to,
1557
1603
  drawingTo,
1604
+ drawingFrom,
1558
1605
  data
1559
1606
  });
1560
1607
  this.registerData(line);
1561
- fromNode.addLine(line);
1608
+ fromNode?.addLine(line);
1562
1609
  toNode?.addLine(line);
1563
1610
  line.onDispose(() => {
1564
- if (drawingTo) {
1565
- this.isDrawing = false;
1566
- }
1567
- fromNode.removeLine(line);
1611
+ this.isDrawing = false;
1612
+ fromNode?.removeLine(line);
1568
1613
  toNode?.removeLine(line);
1569
1614
  });
1570
1615
  line.onDispose(() => {
@@ -1687,7 +1732,7 @@ var WorkflowLinesManager = class {
1687
1732
  return this.lineColor.default;
1688
1733
  }
1689
1734
  canAddLine(fromPort, toPort, silent) {
1690
- if (fromPort === toPort || fromPort.node === toPort.node || fromPort.portType !== "output" || toPort.portType !== "input" || toPort.disabled) {
1735
+ if (fromPort === toPort || fromPort.node === toPort.node || fromPort.portType !== "output" || toPort.portType !== "input" || fromPort.disabled || toPort.disabled) {
1691
1736
  return false;
1692
1737
  }
1693
1738
  const fromCanAdd = fromPort.node.getNodeRegistry().canAddLine;
@@ -1715,8 +1760,8 @@ var WorkflowLinesManager = class {
1715
1760
  }
1716
1761
  return true;
1717
1762
  }
1718
- canReset(fromPort, oldToPort, newToPort) {
1719
- if (this.options && this.options.canResetLine && !this.options.canResetLine(fromPort, oldToPort, newToPort, this)) {
1763
+ canReset(oldLine, newLineInfo) {
1764
+ if (this.options && this.options.canResetLine && !this.options.canResetLine(oldLine, newLineInfo, this)) {
1720
1765
  return false;
1721
1766
  }
1722
1767
  return true;
@@ -1725,9 +1770,14 @@ var WorkflowLinesManager = class {
1725
1770
  * 根据鼠标位置找到 port
1726
1771
  * @param pos
1727
1772
  */
1728
- getPortFromMousePos(pos) {
1773
+ getPortFromMousePos(pos, portType) {
1729
1774
  const allNodes = this.getSortedNodes().reverse();
1730
- const allPorts = allNodes.map((node) => node.getData(WorkflowNodePortsData).allPorts).flat();
1775
+ const allPorts = allNodes.map((node) => {
1776
+ if (!portType) {
1777
+ return node.ports.allPorts;
1778
+ }
1779
+ return portType === "input" ? node.ports.inputPorts : node.ports.outputPorts;
1780
+ }).flat();
1731
1781
  const targetPort = allPorts.find((port) => port.isHovered(pos.x, pos.y));
1732
1782
  if (targetPort) {
1733
1783
  const containNodes = this.getContainNodesFromMousePos(pos);
@@ -2182,8 +2232,11 @@ var WorkflowDocument = class extends FlowDocument {
2182
2232
  originParent,
2183
2233
  meta
2184
2234
  });
2235
+ this.options.preNodeCreate?.(node);
2185
2236
  const datas = dataRegistries ? this.nodeDataRegistries.concat(...dataRegistries) : this.nodeDataRegistries;
2186
2237
  node.addInitializeData(datas);
2238
+ node.ports = node.getData(WorkflowNodePortsData);
2239
+ node.lines = node.getData(WorkflowNodeLinesData);
2187
2240
  node.onDispose(() => this.onNodeDisposeEmitter.fire({ node }));
2188
2241
  this.options.fromNodeJSON?.(node, data, true);
2189
2242
  isNew = true;
@@ -2634,10 +2687,6 @@ var WorkflowDragService = class {
2634
2687
  return Promise.resolve(false);
2635
2688
  }
2636
2689
  this.isDragging = true;
2637
- const sameParent = this.childrenOfContainer(selectedNodes);
2638
- if (sameParent && sameParent.flowNodeType !== FlowNodeBaseType3.ROOT) {
2639
- selectedNodes = [sameParent];
2640
- }
2641
2690
  let startPosition = this.getNodesPosition(selectedNodes);
2642
2691
  let startPositions = selectedNodes.map((node) => {
2643
2692
  const transform = node.getData(TransformData8);
@@ -2699,6 +2748,7 @@ var WorkflowDragService = class {
2699
2748
  triggerEvent,
2700
2749
  dragger
2701
2750
  });
2751
+ this.resetContainerInternalPosition(selectedNodes);
2702
2752
  }
2703
2753
  });
2704
2754
  const { clientX, clientY } = MouseTouchEvent.getEventCoord(triggerEvent);
@@ -2739,7 +2789,7 @@ var WorkflowDragService = class {
2739
2789
  const targetNode = event.currentTarget;
2740
2790
  domNode = cloneNode ? cloneNode(e) : targetNode.cloneNode(true);
2741
2791
  const bounds = targetNode.getBoundingClientRect();
2742
- startPos = { x: bounds.left, y: bounds.top };
2792
+ startPos = { x: bounds.left + window.scrollX, y: bounds.top + window.scrollY };
2743
2793
  domUtils2.setStyle(domNode, {
2744
2794
  zIndex: 1e3,
2745
2795
  position: "absolute",
@@ -2947,18 +2997,30 @@ var WorkflowDragService = class {
2947
2997
  line.highlightColor = color;
2948
2998
  this.hoverService.clearHovered();
2949
2999
  }
2950
- handleDragOnNode(toNode, fromPort, line, toPort, originLine) {
2951
- if (toPort && (originLine?.toPort === toPort || toPort.portType === "input" && this.linesManager.canAddLine(fromPort, toPort, true))) {
2952
- this.hoverService.updateHoveredKey(toPort.id);
2953
- line.setToPort(toPort);
3000
+ checkDraggingPort(isDrawingTo, line, draggingNode, draggingPort, originLine) {
3001
+ let successDrawing = false;
3002
+ if (isDrawingTo) {
3003
+ successDrawing = !!(draggingPort && // 同一条线条则不用在判断 canAddLine
3004
+ (originLine?.toPort === draggingPort || draggingPort.portType === "input" && this.linesManager.canAddLine(line.fromPort, draggingPort, true)));
3005
+ } else {
3006
+ successDrawing = !!(draggingPort && // 同一条线条则不用在判断 canAddLine
3007
+ (originLine?.fromPort === draggingPort || draggingPort.portType === "output" && this.linesManager.canAddLine(draggingPort, line.toPort, true)));
3008
+ }
3009
+ if (successDrawing) {
3010
+ this.hoverService.updateHoveredKey(draggingPort.id);
3011
+ if (isDrawingTo) {
3012
+ line.setToPort(draggingPort);
3013
+ } else {
3014
+ line.setFromPort(draggingPort);
3015
+ }
2954
3016
  this._onDragLineEventEmitter.fire({
2955
3017
  type: "onDrag",
2956
- onDragNodeId: toNode.id
3018
+ onDragNodeId: draggingNode.id
2957
3019
  });
2958
3020
  return {
2959
3021
  hasError: false
2960
3022
  };
2961
- } else if (this.isContainer(toNode)) {
3023
+ } else if (this.isContainer(draggingNode)) {
2962
3024
  return {
2963
3025
  hasError: false
2964
3026
  };
@@ -2969,12 +3031,48 @@ var WorkflowDragService = class {
2969
3031
  };
2970
3032
  }
2971
3033
  }
3034
+ /**
3035
+ * 容器内子节点总体位置重置为0
3036
+ */
3037
+ resetContainerInternalPosition(nodes) {
3038
+ const container = this.childrenOfContainer(nodes);
3039
+ if (!container) {
3040
+ return;
3041
+ }
3042
+ const bounds = Rectangle8.enlarge(
3043
+ container.blocks.map((node) => {
3044
+ const x = node.transform.position.x - node.transform.bounds.width / 2;
3045
+ const y = node.transform.position.y;
3046
+ const width = node.transform.bounds.width;
3047
+ const height = node.transform.bounds.height;
3048
+ return new Rectangle8(x, y, width, height);
3049
+ })
3050
+ );
3051
+ const containerTransform = container.getData(TransformData8);
3052
+ containerTransform.update({
3053
+ position: {
3054
+ x: containerTransform.position.x + bounds.x,
3055
+ y: containerTransform.position.y + bounds.y
3056
+ }
3057
+ });
3058
+ this.document.layout.updateAffectedTransform(container);
3059
+ container.blocks.forEach((node) => {
3060
+ const transform = node.getData(TransformData8);
3061
+ transform.update({
3062
+ position: {
3063
+ x: transform.position.x - bounds.x,
3064
+ y: transform.position.y - bounds.y
3065
+ }
3066
+ });
3067
+ this.document.layout.updateAffectedTransform(node);
3068
+ });
3069
+ }
2972
3070
  childrenOfContainer(nodes) {
2973
3071
  if (nodes.length === 0) {
2974
3072
  return;
2975
3073
  }
2976
3074
  const sourceContainer = nodes[0]?.parent;
2977
- if (!sourceContainer || sourceContainer.collapsedChildren.length !== nodes.length) {
3075
+ if (!sourceContainer || sourceContainer.flowNodeType === FlowNodeBaseType3.ROOT) {
2978
3076
  return;
2979
3077
  }
2980
3078
  const valid = nodes.every((node) => node?.parent === sourceContainer);
@@ -2988,16 +3086,18 @@ var WorkflowDragService = class {
2988
3086
  * @param opts
2989
3087
  * @param event
2990
3088
  */
2991
- async startDrawingLine(fromPort, event, originLine) {
2992
- const isFromInActivePort = !originLine && fromPort.isErrorPort() && fromPort.disabled;
2993
- if (originLine?.disabled || isFromInActivePort || this.playgroundConfig.readonly || this.playgroundConfig.disabled) {
3089
+ async startDrawingLine(port, event, originLine) {
3090
+ const isDrawingTo = port.portType === "output";
3091
+ const isInActivePort = !originLine && port.isErrorPort() && port.disabled;
3092
+ if (originLine?.disabled || isInActivePort || this.playgroundConfig.readonly || this.playgroundConfig.disabled) {
2994
3093
  return { dragSuccess: false, newLine: void 0 };
2995
3094
  }
2996
3095
  this.selectService.clear();
2997
3096
  const config = this.playgroundConfig;
2998
3097
  const deferred = new PromiseDeferred();
2999
3098
  const preCursor = config.cursor;
3000
- let line, toPort, toNode, lineErrorReset = false;
3099
+ let line;
3100
+ let newLineInfo;
3001
3101
  const startTime = Date.now();
3002
3102
  let dragSuccess = false;
3003
3103
  const dragger = new PlaygroundDrag({
@@ -3008,16 +3108,29 @@ var WorkflowDragService = class {
3008
3108
  }
3009
3109
  dragSuccess = true;
3010
3110
  const pos = config.getPosFromMouseEvent(event);
3011
- line = this.linesManager.createLine({
3012
- from: fromPort.node.id,
3013
- fromPort: fromPort.portID,
3014
- data: originLine?.lineData,
3015
- drawingTo: {
3016
- x: pos.x,
3017
- y: pos.y,
3018
- location: fromPort.location === "right" ? "left" : "top"
3019
- }
3020
- });
3111
+ if (isDrawingTo) {
3112
+ line = this.linesManager.createLine({
3113
+ from: port.node.id,
3114
+ fromPort: port.portID,
3115
+ data: originLine?.lineData,
3116
+ drawingTo: {
3117
+ x: pos.x,
3118
+ y: pos.y,
3119
+ location: port.location === "right" ? "left" : "top"
3120
+ }
3121
+ });
3122
+ } else {
3123
+ line = this.linesManager.createLine({
3124
+ to: port.node.id,
3125
+ toPort: port.portID,
3126
+ data: originLine?.lineData,
3127
+ drawingFrom: {
3128
+ x: pos.x,
3129
+ y: pos.y,
3130
+ location: port.location === "left" ? "right" : "bottom"
3131
+ }
3132
+ });
3133
+ }
3021
3134
  if (!line) {
3022
3135
  return;
3023
3136
  }
@@ -3028,49 +3141,15 @@ var WorkflowDragService = class {
3028
3141
  if (!line) {
3029
3142
  return;
3030
3143
  }
3031
- lineErrorReset = false;
3032
3144
  const dragPos = config.getPosFromMouseEvent(e);
3033
- toNode = this.linesManager.getNodeFromMousePos(dragPos);
3034
- toPort = this.linesManager.getPortFromMousePos(dragPos);
3035
- if (!toPort) {
3036
- line.setToPort(void 0);
3037
- } else if (!this.linesManager.canAddLine(fromPort, toPort, true)) {
3038
- line.highlightColor = this.linesManager.lineColor.error;
3039
- lineErrorReset = true;
3040
- line.setToPort(void 0);
3041
- } else {
3042
- line.setToPort(toPort);
3043
- }
3044
- this._onDragLineEventEmitter.fire({
3045
- type: "onDrag"
3046
- });
3047
- this.setLineColor(line, originLine?.lockedColor || this.linesManager.lineColor.drawing);
3048
- if (toNode && this.canBuildContainerLine(toNode, dragPos)) {
3049
- toPort = this.getNearestPort(toNode, dragPos);
3050
- const { hasError } = this.handleDragOnNode(toNode, fromPort, line, toPort, originLine);
3051
- lineErrorReset = hasError;
3052
- }
3053
- if (line.toPort) {
3054
- line.drawingTo = {
3055
- x: line.toPort.point.x,
3056
- y: line.toPort.point.y,
3057
- location: line.toPort.location
3058
- };
3059
- } else {
3060
- line.drawingTo = {
3061
- x: dragPos.x,
3062
- y: dragPos.y,
3063
- location: reverseLocation(line.fromPort.location)
3064
- };
3065
- }
3066
- originLine?.validate();
3067
- line.validate();
3145
+ newLineInfo = this.updateDrawingLine(isDrawingTo, line, dragPos, originLine);
3068
3146
  },
3069
3147
  // eslint-disable-next-line complexity
3070
3148
  onDragEnd: async (e) => {
3071
3149
  const dragPos = config.getPosFromMouseEvent(e);
3072
3150
  const onDragLineEndCallbacks = Array.from(this._onDragLineEndCallbacks.values());
3073
3151
  config.updateCursor(preCursor);
3152
+ const { fromPort, toPort, hasError } = newLineInfo || {};
3074
3153
  await Promise.all(
3075
3154
  onDragLineEndCallbacks.map(
3076
3155
  (callback) => callback({
@@ -3095,36 +3174,32 @@ var WorkflowDragService = class {
3095
3174
  deferred.resolve({ dragSuccess });
3096
3175
  };
3097
3176
  if (dragSuccess) {
3098
- if (originLine && originLine.toPort === toPort) {
3177
+ if (originLine && originLine.toPort === toPort && originLine.fromPort === fromPort) {
3099
3178
  return end();
3100
3179
  }
3101
- if (toPort && toPort.portType !== "input") {
3180
+ if (toPort && toPort.portType !== "input" || fromPort && fromPort.portType !== "output") {
3102
3181
  return end();
3103
3182
  }
3104
- const newLineInfo = toPort ? {
3183
+ const newLinePortInfo = toPort && fromPort ? {
3105
3184
  from: fromPort.node.id,
3106
3185
  fromPort: fromPort.portID,
3107
3186
  to: toPort.node.id,
3108
3187
  toPort: toPort.portID,
3109
3188
  data: originLine?.lineData
3110
3189
  } : void 0;
3111
- const isReset = originLine && toPort;
3112
- if (isReset && !this.linesManager.canReset(
3113
- originLine.fromPort,
3114
- originLine.toPort,
3115
- toPort
3116
- )) {
3190
+ const isReset = originLine && newLinePortInfo;
3191
+ if (isReset && !this.linesManager.canReset(originLine, newLinePortInfo)) {
3117
3192
  return end();
3118
3193
  }
3119
- if (originLine && (!this.linesManager.canRemove(originLine, newLineInfo, false) || lineErrorReset)) {
3194
+ if (originLine && (!this.linesManager.canRemove(originLine, newLinePortInfo, false) || hasError)) {
3120
3195
  return end();
3121
3196
  } else {
3122
3197
  originLine?.dispose();
3123
3198
  }
3124
- if (!toPort || !this.linesManager.canAddLine(fromPort, toPort, false)) {
3199
+ if (!newLinePortInfo || !this.linesManager.canAddLine(fromPort, toPort, false)) {
3125
3200
  return end();
3126
3201
  }
3127
- const newLine = this.linesManager.createLine(newLineInfo);
3202
+ const newLine = this.linesManager.createLine(newLinePortInfo);
3128
3203
  if (!newLine) {
3129
3204
  end();
3130
3205
  }
@@ -3141,14 +3216,109 @@ var WorkflowDragService = class {
3141
3216
  await dragger.start(clientX, clientY, config);
3142
3217
  return deferred.promise;
3143
3218
  }
3219
+ updateDrawingLine(isDrawingTo, line, dragPos, originLine) {
3220
+ let hasError = false;
3221
+ const mouseNode = this.linesManager.getNodeFromMousePos(dragPos);
3222
+ let toNode;
3223
+ let toPort;
3224
+ let fromPort;
3225
+ let fromNode;
3226
+ if (isDrawingTo) {
3227
+ fromPort = line.fromPort;
3228
+ toNode = mouseNode;
3229
+ toPort = this.linesManager.getPortFromMousePos(dragPos, "input");
3230
+ if (toNode && this.canBuildContainerLine(toNode, dragPos)) {
3231
+ toPort = this.getNearestPort(toNode, dragPos, "input");
3232
+ hasError = this.checkDraggingPort(isDrawingTo, line, toNode, toPort, originLine).hasError;
3233
+ }
3234
+ if (!toPort) {
3235
+ line.setToPort(void 0);
3236
+ } else if (!this.linesManager.canAddLine(fromPort, toPort, true)) {
3237
+ hasError = true;
3238
+ line.setToPort(void 0);
3239
+ } else {
3240
+ line.setToPort(toPort);
3241
+ }
3242
+ if (line.toPort) {
3243
+ line.drawingTo = {
3244
+ x: line.toPort.point.x,
3245
+ y: line.toPort.point.y,
3246
+ location: line.toPort.location
3247
+ };
3248
+ } else {
3249
+ line.drawingTo = {
3250
+ x: dragPos.x,
3251
+ y: dragPos.y,
3252
+ location: reverseLocation(line.fromPort.location)
3253
+ };
3254
+ }
3255
+ } else {
3256
+ toPort = line.toPort;
3257
+ fromNode = mouseNode;
3258
+ fromPort = this.linesManager.getPortFromMousePos(dragPos, "output");
3259
+ if (fromNode && this.canBuildContainerLine(fromNode, dragPos)) {
3260
+ fromPort = this.getNearestPort(fromNode, dragPos, "output");
3261
+ hasError = this.checkDraggingPort(
3262
+ isDrawingTo,
3263
+ line,
3264
+ fromNode,
3265
+ fromPort,
3266
+ originLine
3267
+ ).hasError;
3268
+ }
3269
+ if (!fromPort) {
3270
+ line.setFromPort(void 0);
3271
+ } else if (!this.linesManager.canAddLine(fromPort, toPort, true)) {
3272
+ hasError = true;
3273
+ line.setFromPort(void 0);
3274
+ } else {
3275
+ line.setFromPort(fromPort);
3276
+ }
3277
+ if (line.fromPort) {
3278
+ line.drawingFrom = {
3279
+ x: line.fromPort.point.x,
3280
+ y: line.fromPort.point.y,
3281
+ location: line.fromPort.location
3282
+ };
3283
+ } else {
3284
+ line.drawingFrom = {
3285
+ x: dragPos.x,
3286
+ y: dragPos.y,
3287
+ location: reverseLocation(line.toPort.location)
3288
+ };
3289
+ }
3290
+ }
3291
+ this._onDragLineEventEmitter.fire({
3292
+ type: "onDrag"
3293
+ });
3294
+ if (hasError) {
3295
+ this.setLineColor(line, this.linesManager.lineColor.error);
3296
+ } else {
3297
+ this.setLineColor(line, originLine?.lockedColor || this.linesManager.lineColor.drawing);
3298
+ }
3299
+ originLine?.validate();
3300
+ line.validate();
3301
+ return {
3302
+ fromPort,
3303
+ toPort,
3304
+ hasError
3305
+ };
3306
+ }
3144
3307
  /**
3145
3308
  * 重新连接线条
3146
3309
  * @param line
3147
3310
  * @param e
3148
3311
  */
3149
3312
  async resetLine(line, e) {
3150
- const { fromPort } = line;
3151
- const { dragSuccess } = await this.startDrawingLine(fromPort, e, line);
3313
+ const { fromPort, toPort } = line;
3314
+ const mousePos = this.playgroundConfig.getPosFromMouseEvent(e);
3315
+ const distanceFrom = Point.getDistance(fromPort.point, mousePos);
3316
+ const distanceTo = Point.getDistance(toPort.point, mousePos);
3317
+ const { dragSuccess } = await this.startDrawingLine(
3318
+ distanceTo <= distanceFrom || !this.document.options.twoWayConnection ? fromPort : toPort,
3319
+ e,
3320
+ line
3321
+ );
3152
3322
  if (!dragSuccess) {
3153
3323
  this.selectService.select(line);
3154
3324
  }
@@ -3170,17 +3340,27 @@ var WorkflowDragService = class {
3170
3340
  return true;
3171
3341
  }
3172
3342
  const { padding, bounds } = node.transform;
3173
- const contentRect = new Rectangle8(bounds.x, bounds.y, padding.left * 2 / 3, bounds.height);
3174
- return contentRect.contains(mousePos.x, mousePos.y);
3343
+ const DEFAULT_DELTA = 10;
3344
+ const leftDelta = padding.left * 2 / 3 || DEFAULT_DELTA;
3345
+ const rightDelta = padding.right * 2 / 3 || DEFAULT_DELTA;
3346
+ const bottomDelta = padding.bottom * 2 / 3 || DEFAULT_DELTA;
3347
+ const topDelta = padding.top * 2 / 3 || DEFAULT_DELTA;
3348
+ const rectangles = [
3349
+ new Rectangle8(bounds.x, bounds.y, leftDelta, bounds.height),
3350
+ // left
3351
+ new Rectangle8(bounds.x, bounds.y, bounds.width, topDelta),
3352
+ // top
3353
+ new Rectangle8(bounds.x, bounds.y + bounds.height - bottomDelta, bounds.width, bottomDelta),
3354
+ // bottom
3355
+ new Rectangle8(bounds.x + bounds.width - rightDelta, bounds.y, rightDelta, bounds.height)
3356
+ // right
3357
+ ];
3358
+ return rectangles.some((rect) => rect.contains(mousePos.x, mousePos.y));
3175
3359
  }
3176
3360
  /** 获取最近的 port */
3177
- getNearestPort(node, mousePos) {
3178
- const portsData = node.getData(WorkflowNodePortsData);
3179
- const distanceSortedPorts = portsData.inputPorts.sort((a, b) => {
3180
- const aDistance = Math.abs(mousePos.y - a.point.y);
3181
- const bDistance = Math.abs(mousePos.y - b.point.y);
3182
- return aDistance - bDistance;
3183
- });
3361
+ getNearestPort(node, mousePos, portType = "input") {
3362
+ const portsData = node.ports;
3363
+ const distanceSortedPorts = (portType === "input" ? portsData.inputPorts : portsData.outputPorts).sort((a, b) => Point.getDistance(mousePos, a.point) - Point.getDistance(mousePos, b.point));
3184
3364
  return distanceSortedPorts[0];
3185
3365
  }
3186
3366
  };
@@ -3380,7 +3560,7 @@ var isFirefox = navigator?.userAgent?.includes?.("Firefox");
3380
3560
  function useNodeRender(nodeFromProps) {
3381
3561
  const node = nodeFromProps || useContext(PlaygroundEntityContext);
3382
3562
  const renderData = node.getData(FlowNodeRenderData3);
3383
- const portsData = node.getData(WorkflowNodePortsData);
3563
+ const portsData = node.ports;
3384
3564
  const readonly = usePlaygroundReadonlyState();
3385
3565
  const dragService = useService(WorkflowDragService);
3386
3566
  const selectionService = useService(WorkflowSelectService);
@@ -3608,11 +3788,35 @@ WorkflowDocumentContribution = __decorateClass([
3608
3788
 
3609
3789
  // src/utils/get-url-params.ts
3610
3790
  function getUrlParams() {
3611
- return location.search.replace(/^\?/, "").split("&").reduce((res, key) => {
3791
+ const paramsMap = /* @__PURE__ */ new Map();
3792
+ location.search.replace(/^\?/, "").split("&").forEach((key) => {
3793
+ if (!key) return;
3612
3794
  const [k, v] = key.split("=");
3613
- res[k] = v;
3614
- return res;
3615
- }, {});
3795
+ if (k) {
3796
+ const decodedKey = decodeURIComponent(k.trim());
3797
+ const decodedValue = v ? decodeURIComponent(v.trim()) : "";
3798
+ const dangerousProps = [
3799
+ "__proto__",
3800
+ "constructor",
3801
+ "prototype",
3802
+ "__defineGetter__",
3803
+ "__defineSetter__",
3804
+ "__lookupGetter__",
3805
+ "__lookupSetter__",
3806
+ "hasOwnProperty",
3807
+ "isPrototypeOf",
3808
+ "propertyIsEnumerable",
3809
+ "toString",
3810
+ "valueOf",
3811
+ "toLocaleString"
3812
+ ];
3813
+ if (dangerousProps.includes(decodedKey.toLowerCase())) {
3814
+ return;
3815
+ }
3816
+ paramsMap.set(decodedKey, decodedValue);
3817
+ }
3818
+ });
3819
+ return Object.fromEntries(paramsMap);
3616
3820
  }
3617
3821
 
3618
3822
  // src/workflow-document-container-module.ts
@@ -3687,7 +3891,6 @@ export {
3687
3891
  usePlayground2 as usePlayground,
3688
3892
  usePlaygroundContainer,
3689
3893
  usePlaygroundContext,
3690
- usePlaygroundLatest,
3691
3894
  usePlaygroundReadonlyState,
3692
3895
  useRefresh2 as useRefresh,
3693
3896
  useService3 as useService,