@flowgram.ai/free-layout-core 0.1.0-alpha.4 → 0.1.0-alpha.6

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 (42) hide show
  1. package/dist/esm/{chunk-DE4324TR.js → chunk-IYUZVBAO.js} +1 -1
  2. package/dist/esm/chunk-IYUZVBAO.js.map +1 -0
  3. package/dist/esm/chunk-LJH3TSLZ.js +7 -0
  4. package/dist/esm/chunk-LJH3TSLZ.js.map +1 -0
  5. package/dist/esm/chunk-TQLT57GW.js +1 -0
  6. package/dist/esm/chunk-TQLT57GW.js.map +1 -0
  7. package/dist/esm/index.js +165 -62
  8. package/dist/esm/index.js.map +1 -1
  9. package/dist/esm/typings/index.js +10 -5
  10. package/dist/esm/typings/workflow-drag.js +2 -0
  11. package/dist/esm/typings/workflow-drag.js.map +1 -0
  12. package/dist/esm/typings/workflow-operation.js +8 -0
  13. package/dist/esm/typings/workflow-operation.js.map +1 -0
  14. package/dist/index.d.mts +121 -7
  15. package/dist/index.d.ts +121 -7
  16. package/dist/index.js +211 -107
  17. package/dist/index.js.map +1 -1
  18. package/dist/typings/index.d.mts +2 -1
  19. package/dist/typings/index.d.ts +2 -1
  20. package/dist/typings/index.js +7 -2
  21. package/dist/typings/index.js.map +1 -1
  22. package/dist/typings/workflow-drag.d.mts +8 -0
  23. package/dist/typings/workflow-drag.d.ts +8 -0
  24. package/dist/typings/workflow-drag.js +19 -0
  25. package/dist/typings/workflow-drag.js.map +1 -0
  26. package/dist/typings/workflow-json.d.mts +1 -1
  27. package/dist/typings/workflow-json.d.ts +1 -1
  28. package/dist/typings/workflow-line.d.mts +1 -1
  29. package/dist/typings/workflow-line.d.ts +1 -1
  30. package/dist/typings/workflow-node.d.mts +1 -1
  31. package/dist/typings/workflow-node.d.ts +1 -1
  32. package/dist/typings/workflow-node.js.map +1 -1
  33. package/dist/typings/workflow-operation.d.mts +24 -0
  34. package/dist/typings/workflow-operation.d.ts +24 -0
  35. package/dist/typings/workflow-operation.js +31 -0
  36. package/dist/typings/workflow-operation.js.map +1 -0
  37. package/dist/typings/workflow-registry.d.mts +1 -1
  38. package/dist/typings/workflow-registry.d.ts +1 -1
  39. package/dist/{workflow-line-entity-BJQBRDgJ.d.mts → workflow-line-entity-BCAgoA18.d.mts} +95 -170
  40. package/dist/{workflow-line-entity-CEitdjhk.d.ts → workflow-line-entity-DIyrK9yz.d.ts} +95 -170
  41. package/package.json +9 -9
  42. package/dist/esm/chunk-DE4324TR.js.map +0 -1
package/dist/index.js CHANGED
@@ -52,6 +52,8 @@ __export(src_exports, {
52
52
  WorkflowNodeEntity: () => WorkflowNodeEntity,
53
53
  WorkflowNodeLinesData: () => WorkflowNodeLinesData,
54
54
  WorkflowNodePortsData: () => WorkflowNodePortsData,
55
+ WorkflowOperationBaseService: () => WorkflowOperationBaseService,
56
+ WorkflowOperationBaseServiceImpl: () => WorkflowOperationBaseServiceImpl,
55
57
  WorkflowPortEntity: () => WorkflowPortEntity,
56
58
  WorkflowResetLayoutService: () => WorkflowResetLayoutService,
57
59
  WorkflowSelectService: () => WorkflowSelectService,
@@ -65,21 +67,21 @@ __export(src_exports, {
65
67
  getAntiOverlapPosition: () => getAntiOverlapPosition,
66
68
  getPortEntityId: () => getPortEntityId,
67
69
  nanoid: () => nanoid,
68
- useConfigEntity: () => import_core24.useConfigEntity,
70
+ useConfigEntity: () => import_core25.useConfigEntity,
69
71
  useCurrentDomNode: () => useCurrentDomNode,
70
72
  useCurrentEntity: () => useCurrentEntity,
71
- useEntities: () => import_core24.useEntities,
72
- useEntityDataFromContext: () => import_core24.useEntityDataFromContext,
73
- useEntityFromContext: () => import_core24.useEntityFromContext,
74
- useListenEvents: () => import_core24.useListenEvents,
73
+ useEntities: () => import_core25.useEntities,
74
+ useEntityDataFromContext: () => import_core25.useEntityDataFromContext,
75
+ useEntityFromContext: () => import_core25.useEntityFromContext,
76
+ useListenEvents: () => import_core25.useListenEvents,
75
77
  useNodeRender: () => useNodeRender,
76
- usePlayground: () => import_core24.usePlayground,
77
- usePlaygroundContainer: () => import_core24.usePlaygroundContainer,
78
- usePlaygroundContext: () => import_core24.usePlaygroundContext,
79
- usePlaygroundLatest: () => import_core24.usePlaygroundLatest,
78
+ usePlayground: () => import_core25.usePlayground,
79
+ usePlaygroundContainer: () => import_core25.usePlaygroundContainer,
80
+ usePlaygroundContext: () => import_core25.usePlaygroundContext,
81
+ usePlaygroundLatest: () => import_core25.usePlaygroundLatest,
80
82
  usePlaygroundReadonlyState: () => usePlaygroundReadonlyState,
81
- useRefresh: () => import_core24.useRefresh,
82
- useService: () => import_core24.useService,
83
+ useRefresh: () => import_core25.useRefresh,
84
+ useService: () => import_core25.useService,
83
85
  useWorkflowDocument: () => useWorkflowDocument
84
86
  });
85
87
  module.exports = __toCommonJS(src_exports);
@@ -97,14 +99,14 @@ var WorkflowCommands = /* @__PURE__ */ ((WorkflowCommands2) => {
97
99
  })(WorkflowCommands || {});
98
100
 
99
101
  // src/hooks/index.ts
100
- var import_core24 = require("@flowgram.ai/core");
102
+ var import_core25 = require("@flowgram.ai/core");
101
103
 
102
104
  // src/hooks/use-node-render.tsx
103
105
  var import_react2 = require("react");
104
106
  var import_reactive = require("@flowgram.ai/reactive");
105
107
  var import_node = require("@flowgram.ai/node");
106
- var import_document10 = require("@flowgram.ai/document");
107
- var import_core20 = require("@flowgram.ai/core");
108
+ var import_document12 = require("@flowgram.ai/document");
109
+ var import_core21 = require("@flowgram.ai/core");
108
110
 
109
111
  // src/service/workflow-select-service.ts
110
112
  var import_inversify = require("inversify");
@@ -178,11 +180,12 @@ var import_core8 = require("@flowgram.ai/core");
178
180
 
179
181
  // src/entity-datas/workflow-node-ports-data.ts
180
182
  var import_lodash_es = require("lodash-es");
181
- var import_document2 = require("@flowgram.ai/document");
183
+ var import_document3 = require("@flowgram.ai/document");
182
184
  var import_core5 = require("@flowgram.ai/core");
183
185
 
184
186
  // src/entities/workflow-port-entity.ts
185
187
  var import_utils5 = require("@flowgram.ai/utils");
188
+ var import_document2 = require("@flowgram.ai/document");
186
189
  var import_core4 = require("@flowgram.ai/core");
187
190
  var PORT_SIZE = 24;
188
191
  var WorkflowPortEntity = class extends import_core4.Entity {
@@ -230,7 +233,7 @@ var WorkflowPortEntity = class extends import_core4.Entity {
230
233
  }
231
234
  get point() {
232
235
  const { targetElement } = this;
233
- const { bounds } = this.node.getData(import_core4.TransformData);
236
+ const { bounds } = this.node.getData(import_document2.FlowNodeTransformData);
234
237
  if (targetElement) {
235
238
  const pos = domReactToBounds(targetElement.getBoundingClientRect()).center;
236
239
  return this.entityManager.getEntity(import_core4.PlaygroundConfigEntity).getPosFromMouseEvent({
@@ -259,7 +262,7 @@ var WorkflowPortEntity = class extends import_core4.Entity {
259
262
  */
260
263
  get relativePosition() {
261
264
  const { point } = this;
262
- const { bounds } = this.node.getData(import_core4.TransformData);
265
+ const { bounds } = this.node.getData(import_document2.FlowNodeTransformData);
263
266
  return {
264
267
  x: point.x - bounds.x,
265
268
  y: point.y - bounds.y
@@ -290,10 +293,17 @@ var WorkflowPortEntity = class extends import_core4.Entity {
290
293
  }
291
294
  /**
292
295
  * 当前点位上连接的线条
296
+ * @deprecated use `availableLines` instead
293
297
  */
294
298
  get lines() {
295
299
  return this.allLines.filter((line) => !line.isDrawing);
296
300
  }
301
+ /**
302
+ * 当前有效的线条,不包含正在画的线条和隐藏的线条(这个出现在线条重连会先把原来的线条隐藏)
303
+ */
304
+ get availableLines() {
305
+ return this.allLines.filter((line) => !line.isDrawing && !line.isHidden);
306
+ }
297
307
  /**
298
308
  * 当前点位上连接的线条(包含 isDrawing === true 的线条)
299
309
  */
@@ -362,7 +372,7 @@ var WorkflowNodePortsData = class extends import_core5.EntityData {
362
372
  * 动态计算点位,通过 dom 的 data-port-key
363
373
  */
364
374
  updateDynamicPorts() {
365
- const domNode = this.entity.getData(import_document2.FlowNodeRenderData).node;
375
+ const domNode = this.entity.getData(import_document3.FlowNodeRenderData).node;
366
376
  const elements = domNode.querySelectorAll("[data-port-id]");
367
377
  const staticPorts = this._staticPorts;
368
378
  const dynamicPorts = [];
@@ -1139,20 +1149,20 @@ WorkflowHoverService = __decorateClass([
1139
1149
  var import_nanoid3 = require("nanoid");
1140
1150
  var import_inversify6 = require("inversify");
1141
1151
  var import_utils16 = require("@flowgram.ai/utils");
1142
- var import_document7 = require("@flowgram.ai/document");
1143
1152
  var import_document8 = require("@flowgram.ai/document");
1153
+ var import_document9 = require("@flowgram.ai/document");
1144
1154
  var import_core15 = require("@flowgram.ai/core");
1145
1155
 
1146
1156
  // src/workflow-lines-manager.ts
1147
1157
  var import_lodash_es3 = require("lodash-es");
1148
1158
  var import_inversify3 = require("inversify");
1149
1159
  var import_utils12 = require("@flowgram.ai/utils");
1150
- var import_document4 = require("@flowgram.ai/document");
1160
+ var import_document5 = require("@flowgram.ai/document");
1151
1161
  var import_core12 = require("@flowgram.ai/core");
1152
1162
 
1153
1163
  // src/workflow-document-option.ts
1154
1164
  var import_form_core2 = require("@flowgram.ai/form-core");
1155
- var import_document3 = require("@flowgram.ai/document");
1165
+ var import_document4 = require("@flowgram.ai/document");
1156
1166
  var import_core11 = require("@flowgram.ai/core");
1157
1167
 
1158
1168
  // src/utils/flow-node-form-data.ts
@@ -1185,6 +1195,9 @@ var LineColors = /* @__PURE__ */ ((LineColors2) => {
1185
1195
  return LineColors2;
1186
1196
  })(LineColors || {});
1187
1197
 
1198
+ // src/typings/workflow-operation.ts
1199
+ var WorkflowOperationBaseService = Symbol("WorkflowOperationBaseService");
1200
+
1188
1201
  // src/typings/index.ts
1189
1202
  var URLParams = Symbol("");
1190
1203
 
@@ -1235,7 +1248,7 @@ var WorkflowDocumentOptionsDefault = {
1235
1248
  const nodeMeta = node.getNodeMeta();
1236
1249
  const subCanvas = nodeMeta.subCanvas?.(node);
1237
1250
  if (subCanvas?.isCanvas === false) {
1238
- const canvasNodeTransform = subCanvas.canvasNode.getData(import_document3.FlowNodeTransformData);
1251
+ const canvasNodeTransform = subCanvas.canvasNode.getData(import_document4.FlowNodeTransformData);
1239
1252
  const { x, y } = canvasNodeTransform.transform.position;
1240
1253
  metaData.canvasPosition = { x, y };
1241
1254
  }
@@ -1533,12 +1546,12 @@ var WorkflowLinesManager = class {
1533
1546
  * @param pos - 鼠标位置
1534
1547
  */
1535
1548
  getNodeFromMousePos(pos) {
1536
- const allNodes = this.document.getAllNodes();
1549
+ const allNodes = this.document.getAllNodes().sort((a, b) => this.getNodeIndex(a) - this.getNodeIndex(b));
1537
1550
  const containNodes = [];
1538
1551
  const { selection } = this.selectService;
1539
1552
  const zoom = this.entityManager.getEntity(import_core12.PlaygroundConfigEntity)?.config?.zoom || 1;
1540
1553
  allNodes.forEach((node) => {
1541
- const { bounds } = node.getData(import_document4.FlowNodeTransformData);
1554
+ const { bounds } = node.getData(import_document5.FlowNodeTransformData);
1542
1555
  if (bounds.clone().pad(4 / zoom).contains(pos.x, pos.y)) {
1543
1556
  containNodes.push(node);
1544
1557
  }
@@ -1560,6 +1573,10 @@ var WorkflowLinesManager = class {
1560
1573
  registerData(line) {
1561
1574
  line.addData(WorkflowLineRenderData);
1562
1575
  }
1576
+ getNodeIndex(node) {
1577
+ const nodeRenderData = node.getData(import_document5.FlowNodeRenderData);
1578
+ return nodeRenderData.stackIndex;
1579
+ }
1563
1580
  };
1564
1581
  __decorateClass([
1565
1582
  (0, import_inversify3.inject)(WorkflowHoverService)
@@ -1582,12 +1599,12 @@ var import_nanoid2 = require("nanoid");
1582
1599
  var import_inversify5 = require("inversify");
1583
1600
  var import_utils14 = require("@flowgram.ai/utils");
1584
1601
  var import_form_core3 = require("@flowgram.ai/form-core");
1585
- var import_document6 = require("@flowgram.ai/document");
1602
+ var import_document7 = require("@flowgram.ai/document");
1586
1603
  var import_core14 = require("@flowgram.ai/core");
1587
1604
 
1588
1605
  // src/layout/free-layout.ts
1589
1606
  var import_inversify4 = require("inversify");
1590
- var import_document5 = require("@flowgram.ai/document");
1607
+ var import_document6 = require("@flowgram.ai/document");
1591
1608
  var import_core13 = require("@flowgram.ai/core");
1592
1609
  var import_utils13 = require("@flowgram.ai/utils");
1593
1610
  var FREE_LAYOUT_KEY = "free-layout";
@@ -1602,12 +1619,12 @@ var FreeLayout = class {
1602
1619
  * 更新布局
1603
1620
  */
1604
1621
  update() {
1605
- if (this.document.root.getData(import_document5.FlowNodeTransformData)?.localDirty) {
1622
+ if (this.document.root.getData(import_document6.FlowNodeTransformData)?.localDirty) {
1606
1623
  this.document.root.clearMemoGlobal();
1607
1624
  }
1608
1625
  }
1609
1626
  syncTransform(node) {
1610
- const transform = node.getData(import_document5.FlowNodeTransformData);
1627
+ const transform = node.getData(import_document6.FlowNodeTransformData);
1611
1628
  if (!transform.localDirty) {
1612
1629
  return;
1613
1630
  }
@@ -1621,7 +1638,7 @@ var FreeLayout = class {
1621
1638
  }
1622
1639
  node.parent.clearMemoGlobal();
1623
1640
  node.parent.clearMemoLocal();
1624
- const parentTransform = node.parent.getData(import_document5.FlowNodeTransformData);
1641
+ const parentTransform = node.parent.getData(import_document6.FlowNodeTransformData);
1625
1642
  parentTransform.transform.fireChange();
1626
1643
  }
1627
1644
  /**
@@ -1630,7 +1647,7 @@ var FreeLayout = class {
1630
1647
  */
1631
1648
  getPadding(node) {
1632
1649
  const { padding } = node.getNodeMeta();
1633
- const transform = node.getData(import_document5.FlowNodeTransformData);
1650
+ const transform = node.getData(import_document6.FlowNodeTransformData);
1634
1651
  if (padding) {
1635
1652
  return typeof padding === "function" ? padding(transform) : padding;
1636
1653
  }
@@ -1674,7 +1691,7 @@ __decorateClass([
1674
1691
  (0, import_inversify4.inject)(import_core13.PlaygroundConfigEntity)
1675
1692
  ], FreeLayout.prototype, "playgroundConfig", 2);
1676
1693
  __decorateClass([
1677
- (0, import_inversify4.inject)(import_document5.FlowDocumentProvider)
1694
+ (0, import_inversify4.inject)(import_document6.FlowDocumentProvider)
1678
1695
  ], FreeLayout.prototype, "documentProvider", 2);
1679
1696
  FreeLayout = __decorateClass([
1680
1697
  (0, import_inversify4.injectable)()
@@ -1683,7 +1700,7 @@ FreeLayout = __decorateClass([
1683
1700
  // src/workflow-document.ts
1684
1701
  var nanoid2 = (0, import_nanoid2.customAlphabet)("1234567890", 5);
1685
1702
  var WorkflowDocumentProvider = Symbol("WorkflowDocumentProvider");
1686
- var WorkflowDocument = class extends import_document6.FlowDocument {
1703
+ var WorkflowDocument = class extends import_document7.FlowDocument {
1687
1704
  constructor() {
1688
1705
  super(...arguments);
1689
1706
  this._onContentChangeEmitter = new import_utils14.Emitter();
@@ -1776,7 +1793,7 @@ var WorkflowDocument = class extends import_document6.FlowDocument {
1776
1793
  const { formMeta } = registry;
1777
1794
  const meta = node.getNodeMeta();
1778
1795
  const formData = getFlowNodeFormData(node);
1779
- const transform = node.getData(import_document6.FlowNodeTransformData);
1796
+ const transform = node.getData(import_document7.FlowNodeTransformData);
1780
1797
  const freeLayout = this.layout;
1781
1798
  transform.onDataChange(() => {
1782
1799
  freeLayout.syncTransform(node);
@@ -1824,10 +1841,10 @@ var WorkflowDocument = class extends import_document6.FlowDocument {
1824
1841
  );
1825
1842
  node.toDispose.push(
1826
1843
  import_utils14.Disposable.create(() => {
1827
- if (!node.parent || node.parent.flowNodeType === import_document6.FlowNodeBaseType.ROOT) {
1844
+ if (!node.parent || node.parent.flowNodeType === import_document7.FlowNodeBaseType.ROOT) {
1828
1845
  return;
1829
1846
  }
1830
- const parentTransform = node.parent.getData(import_document6.FlowNodeTransformData);
1847
+ const parentTransform = node.parent.getData(import_document7.FlowNodeTransformData);
1831
1848
  setTimeout(() => {
1832
1849
  parentTransform.fireChange();
1833
1850
  }, 0);
@@ -1908,10 +1925,10 @@ var WorkflowDocument = class extends import_document6.FlowDocument {
1908
1925
  );
1909
1926
  }
1910
1927
  getAllNodes() {
1911
- return this.entityManager.getEntities(WorkflowNodeEntity).filter((n) => n.id !== import_document6.FlowNodeBaseType.ROOT);
1928
+ return this.entityManager.getEntities(WorkflowNodeEntity).filter((n) => n.id !== import_document7.FlowNodeBaseType.ROOT);
1912
1929
  }
1913
1930
  getAllPorts() {
1914
- return this.entityManager.getEntities(WorkflowPortEntity).filter((p) => p.node.id !== import_document6.FlowNodeBaseType.ROOT);
1931
+ return this.entityManager.getEntities(WorkflowPortEntity).filter((p) => p.node.id !== import_document7.FlowNodeBaseType.ROOT);
1915
1932
  }
1916
1933
  /**
1917
1934
  * 获取画布中的非游离节点
@@ -1928,8 +1945,8 @@ var WorkflowDocument = class extends import_document6.FlowDocument {
1928
1945
  }));
1929
1946
  const startNodeId = allNode.find((node) => node.isStart).id;
1930
1947
  const endNodeId = allNode.find((node) => node.isNodeEnd).id;
1931
- const nodeInSubCanvas = allNode.filter((node) => node.parent?.flowNodeType === import_document6.FlowNodeBaseType.SUB_CANVAS).map((node) => node.id);
1932
- const associatedCache = /* @__PURE__ */ new Set([endNodeId, ...nodeInSubCanvas]);
1948
+ const nodeInContainer = allNode.filter((node) => node.parent?.getNodeMeta().isContainer).map((node) => node.id);
1949
+ const associatedCache = /* @__PURE__ */ new Set([endNodeId, ...nodeInContainer]);
1933
1950
  const bfs = (nodeId) => {
1934
1951
  if (associatedCache.has(nodeId)) {
1935
1952
  return;
@@ -2099,8 +2116,8 @@ var WorkflowDocument = class extends import_document6.FlowDocument {
2099
2116
  const flattenEdgeJSONs = [...rootEdges];
2100
2117
  const rootBlockIDs = rootNodes.map((node) => node.id);
2101
2118
  const rootEdgeIDs = rootEdges.map((edge) => this.getEdgeID(edge));
2102
- nodeBlocks.set(import_document6.FlowNodeBaseType.ROOT, rootBlockIDs);
2103
- nodeEdges.set(import_document6.FlowNodeBaseType.ROOT, rootEdgeIDs);
2119
+ nodeBlocks.set(import_document7.FlowNodeBaseType.ROOT, rootBlockIDs);
2120
+ nodeEdges.set(import_document7.FlowNodeBaseType.ROOT, rootEdgeIDs);
2104
2121
  rootNodes.forEach((nodeJSON) => {
2105
2122
  const { blocks, edges } = nodeJSON;
2106
2123
  if (blocks) {
@@ -2143,8 +2160,8 @@ var WorkflowDocument = class extends import_document6.FlowDocument {
2143
2160
  };
2144
2161
  const nodeMap = /* @__PURE__ */ new Map();
2145
2162
  const edgeMap = /* @__PURE__ */ new Map();
2146
- const rootBlockSet = new Set(nodeBlocks.get(import_document6.FlowNodeBaseType.ROOT) ?? []);
2147
- const rootEdgeSet = new Set(nodeEdges.get(import_document6.FlowNodeBaseType.ROOT) ?? []);
2163
+ const rootBlockSet = new Set(nodeBlocks.get(import_document7.FlowNodeBaseType.ROOT) ?? []);
2164
+ const rootEdgeSet = new Set(nodeEdges.get(import_document7.FlowNodeBaseType.ROOT) ?? []);
2148
2165
  flattenJSON.nodes.forEach((nodeJSON) => {
2149
2166
  nodeMap.set(nodeJSON.id, nodeJSON);
2150
2167
  });
@@ -2204,7 +2221,7 @@ var WorkflowDocument = class extends import_document6.FlowDocument {
2204
2221
  }
2205
2222
  toLineJSON(line) {
2206
2223
  const lineJSON = line.toJSON();
2207
- if (!line.to || !line.info.to || !line.toPort) {
2224
+ if (!line.from || !line.info.from || !line.fromPort || !line.to || !line.info.to || !line.toPort) {
2208
2225
  return;
2209
2226
  }
2210
2227
  const fromSubCanvas = this.getNodeSubCanvas(line.from);
@@ -2322,18 +2339,19 @@ var WorkflowDragService = class {
2322
2339
  }
2323
2340
  /**
2324
2341
  * 拖拽选中节点
2325
- * @param event
2342
+ * @param triggerEvent
2326
2343
  */
2327
- startDragSelectedNodes(event) {
2344
+ startDragSelectedNodes(triggerEvent) {
2328
2345
  let { selectedNodes } = this.selectService;
2329
- if (selectedNodes.length === 0 || this.playgroundConfig.readonly || this.playgroundConfig.disabled) {
2346
+ if (selectedNodes.length === 0 || this.playgroundConfig.readonly || this.playgroundConfig.disabled || this.isDragging) {
2330
2347
  return Promise.resolve(false);
2331
2348
  }
2349
+ this.isDragging = true;
2332
2350
  const sameParent = this.childrenOfContainer(selectedNodes);
2333
- if (sameParent && sameParent.flowNodeType !== import_document8.FlowNodeBaseType.ROOT) {
2351
+ if (sameParent && sameParent.flowNodeType !== import_document9.FlowNodeBaseType.ROOT) {
2334
2352
  selectedNodes = [sameParent];
2335
2353
  }
2336
- const { altKey } = event;
2354
+ const { altKey } = triggerEvent;
2337
2355
  let startPosition = this.getNodesPosition(selectedNodes);
2338
2356
  let startPositions = selectedNodes.map((node) => {
2339
2357
  const transform = node.getData(import_core15.TransformData);
@@ -2342,11 +2360,19 @@ var WorkflowDragService = class {
2342
2360
  let dragSuccess = false;
2343
2361
  const startTime = Date.now();
2344
2362
  const dragger = new import_core15.PlaygroundDrag({
2345
- onDragStart: () => {
2346
- this.isDragging = true;
2363
+ onDragStart: (dragEvent) => {
2364
+ this._nodesDragEmitter.fire({
2365
+ type: "onDragStart",
2366
+ nodes: selectedNodes,
2367
+ startPositions,
2368
+ altKey,
2369
+ dragEvent,
2370
+ triggerEvent,
2371
+ dragger
2372
+ });
2347
2373
  },
2348
- onDrag: (e) => {
2349
- if (!dragSuccess && checkDragSuccess(Date.now() - startTime, e)) {
2374
+ onDrag: (dragEvent) => {
2375
+ if (!dragSuccess && checkDragSuccess(Date.now() - startTime, dragEvent)) {
2350
2376
  dragSuccess = true;
2351
2377
  if (altKey) {
2352
2378
  const tryCopyNodes = selectedNodes;
@@ -2369,10 +2395,11 @@ var WorkflowDragService = class {
2369
2395
  }
2370
2396
  }
2371
2397
  const offset = this.getDragPosOffset({
2372
- event: e,
2398
+ event: dragEvent,
2373
2399
  selectedNodes,
2374
2400
  startPosition
2375
2401
  });
2402
+ const positions = [];
2376
2403
  selectedNodes.forEach((node, index) => {
2377
2404
  const transform = node.getData(import_core15.TransformData);
2378
2405
  const nodeStartPosition = startPositions[index];
@@ -2382,26 +2409,40 @@ var WorkflowDragService = class {
2382
2409
  };
2383
2410
  if (node.collapsedChildren?.length > 0) {
2384
2411
  node.collapsedChildren.forEach((childNode) => {
2385
- const childNodeTransformData = childNode.getData(import_document7.FlowNodeTransformData);
2412
+ const childNodeTransformData = childNode.getData(import_document8.FlowNodeTransformData);
2386
2413
  childNodeTransformData.fireChange();
2387
2414
  });
2388
2415
  }
2389
2416
  transform.update({
2390
2417
  position: newPosition
2391
2418
  });
2419
+ positions.push(newPosition);
2420
+ });
2421
+ this._nodesDragEmitter.fire({
2422
+ type: "onDragging",
2423
+ nodes: selectedNodes,
2424
+ startPositions,
2425
+ positions,
2426
+ altKey,
2427
+ dragEvent,
2428
+ triggerEvent,
2429
+ dragger
2392
2430
  });
2393
2431
  },
2394
- onDragEnd: () => {
2432
+ onDragEnd: (dragEvent) => {
2395
2433
  this.isDragging = false;
2396
2434
  this._nodesDragEmitter.fire({
2397
2435
  type: "onDragEnd",
2398
2436
  nodes: selectedNodes,
2399
2437
  startPositions,
2400
- altKey
2438
+ altKey,
2439
+ dragEvent,
2440
+ triggerEvent,
2441
+ dragger
2401
2442
  });
2402
2443
  }
2403
2444
  });
2404
- return dragger.start(event.clientX, event.clientY, this.playgroundConfig).then(() => dragSuccess);
2445
+ return dragger.start(triggerEvent.clientX, triggerEvent.clientY, this.playgroundConfig)?.then(() => dragSuccess);
2405
2446
  }
2406
2447
  /**
2407
2448
  * 通过拖入卡片添加
@@ -2473,7 +2514,11 @@ var WorkflowDragService = class {
2473
2514
  },
2474
2515
  onDragEnd: async (e) => {
2475
2516
  const dropNode = this._dropNode;
2476
- const dragNode = await this.dropCard(type, e, data, dropNode);
2517
+ const { allowDrop } = this.canDropToNode({
2518
+ dragNodeType: type,
2519
+ dropNode
2520
+ });
2521
+ const dragNode = allowDrop ? await this.dropCard(type, e, data, dropNode) : void 0;
2477
2522
  this.clearDrop();
2478
2523
  if (dragNode) {
2479
2524
  domNode.remove();
@@ -2499,7 +2544,7 @@ var WorkflowDragService = class {
2499
2544
  if (!mousePos) {
2500
2545
  return { x: 0, y: 0 };
2501
2546
  }
2502
- if (!subNodeType || !containerNode || containerNode.flowNodeType === import_document8.FlowNodeBaseType.ROOT) {
2547
+ if (!subNodeType || !containerNode || containerNode.flowNodeType === import_document9.FlowNodeBaseType.ROOT) {
2503
2548
  return mousePos;
2504
2549
  }
2505
2550
  const isParentEmpty = !containerNode.children || containerNode.children.length === 0;
@@ -2526,6 +2571,22 @@ var WorkflowDragService = class {
2526
2571
  dispose: () => this.posAdjusters.delete(adjuster)
2527
2572
  };
2528
2573
  }
2574
+ /**
2575
+ * 判断是否可以放置节点
2576
+ */
2577
+ canDropToNode(params) {
2578
+ const { dragNodeType, dropNode } = params;
2579
+ if (!dragNodeType) {
2580
+ return {
2581
+ allowDrop: false,
2582
+ message: "Please select a node to drop"
2583
+ };
2584
+ }
2585
+ return {
2586
+ allowDrop: true,
2587
+ dropNode
2588
+ };
2589
+ }
2529
2590
  /**
2530
2591
  * 获取拖拽偏移
2531
2592
  */
@@ -2556,23 +2617,24 @@ var WorkflowDragService = class {
2556
2617
  return offset;
2557
2618
  }
2558
2619
  updateDroppableTransforms() {
2559
- this._droppableTransforms = this.document.getRenderDatas(import_document7.FlowNodeTransformData, false).filter((transform) => {
2620
+ this._droppableTransforms = this.document.getRenderDatas(import_document8.FlowNodeTransformData, false).filter((transform) => {
2560
2621
  const { entity } = transform;
2561
2622
  if (entity.originParent) {
2562
2623
  return this.nodeSelectable(entity) && this.nodeSelectable(entity.originParent);
2563
2624
  }
2564
2625
  return this.nodeSelectable(entity);
2565
- }).filter((transform) => {
2566
- const { entity } = transform;
2567
- return entity.flowNodeType === import_document8.FlowNodeBaseType.SUB_CANVAS;
2568
- });
2626
+ }).filter((transform) => this.isContainer(transform.entity));
2627
+ }
2628
+ /** 是否容器节点 */
2629
+ isContainer(node) {
2630
+ return node?.getNodeMeta().isContainer ?? false;
2569
2631
  }
2570
2632
  /**
2571
2633
  * 获取节点整体位置
2572
2634
  */
2573
2635
  getNodesPosition(nodes) {
2574
2636
  const selectedBounds = import_utils16.Rectangle.enlarge(
2575
- nodes.map((n) => n.getData(import_document7.FlowNodeTransformData).bounds)
2637
+ nodes.map((n) => n.getData(import_document8.FlowNodeTransformData).bounds)
2576
2638
  );
2577
2639
  const position = {
2578
2640
  x: selectedBounds.x,
@@ -2622,7 +2684,7 @@ var WorkflowDragService = class {
2622
2684
  return {
2623
2685
  hasError: false
2624
2686
  };
2625
- } else if (toNode.flowNodeType === import_document8.FlowNodeBaseType.SUB_CANVAS) {
2687
+ } else if (this.isContainer(toNode)) {
2626
2688
  return {
2627
2689
  hasError: false
2628
2690
  };
@@ -2657,6 +2719,7 @@ var WorkflowDragService = class {
2657
2719
  if (originLine?.disabled || isFromInActivePort || this.playgroundConfig.readonly || this.playgroundConfig.disabled) {
2658
2720
  return { dragSuccess: false, newLine: void 0 };
2659
2721
  }
2722
+ this.selectService.clear();
2660
2723
  const config = this.playgroundConfig;
2661
2724
  const deferred = new import_utils16.PromiseDeferred();
2662
2725
  const preCursor = config.cursor;
@@ -2702,9 +2765,12 @@ var WorkflowDragService = class {
2702
2765
  type: "onDrag"
2703
2766
  });
2704
2767
  this.setLineColor(line, this.linesManager.lineColor.drawing);
2705
- if (toNode && toNode.flowNodeType !== import_document8.FlowNodeBaseType.SUB_CANVAS) {
2768
+ if (toNode && !this.isContainer(toNode)) {
2706
2769
  const portsData = toNode.getData(WorkflowNodePortsData);
2707
- toPort = portsData.inputPorts[0];
2770
+ const { inputPorts } = portsData;
2771
+ if (inputPorts.length === 1) {
2772
+ toPort = inputPorts[0];
2773
+ }
2708
2774
  const { hasError } = this.handleDragOnNode(toNode, fromPort, line, toPort, originLine);
2709
2775
  lineErrorReset = hasError;
2710
2776
  }
@@ -2831,7 +2897,7 @@ __decorateClass([
2831
2897
  (0, import_inversify6.inject)(WorkflowSelectService)
2832
2898
  ], WorkflowDragService.prototype, "selectService", 2);
2833
2899
  __decorateClass([
2834
- (0, import_inversify6.inject)(import_document7.FlowOperationBaseService)
2900
+ (0, import_inversify6.inject)(import_document8.FlowOperationBaseService)
2835
2901
  ], WorkflowDragService.prototype, "operationService", 2);
2836
2902
  __decorateClass([
2837
2903
  (0, import_inversify6.inject)(WorkflowDocumentOptions)
@@ -2850,13 +2916,13 @@ var import_core18 = require("@flowgram.ai/core");
2850
2916
  var import_utils17 = require("@flowgram.ai/utils");
2851
2917
 
2852
2918
  // src/utils/layout-to-positions.ts
2853
- var import_document9 = require("@flowgram.ai/document");
2919
+ var import_document10 = require("@flowgram.ai/document");
2854
2920
  var import_core16 = require("@flowgram.ai/core");
2855
2921
  var layoutToPositions = async (nodes, nodePositionMap) => {
2856
2922
  const newNodePositionMap = {};
2857
2923
  nodes.forEach((node) => {
2858
2924
  const transform = node.getData(import_core16.TransformData);
2859
- const nodeTransform = node.getData(import_document9.FlowNodeTransformData);
2925
+ const nodeTransform = node.getData(import_document10.FlowNodeTransformData);
2860
2926
  newNodePositionMap[node.id] = {
2861
2927
  x: transform.position.x,
2862
2928
  y: transform.position.y + nodeTransform.bounds.height / 2
@@ -2874,7 +2940,7 @@ var layoutToPositions = async (nodes, nodePositionMap) => {
2874
2940
  const deltaY = (nodePositionMap[node.id].y - transform.bounds.height / 2 - transform.position.y) * v.d / 100;
2875
2941
  if (node.collapsedChildren?.length > 0) {
2876
2942
  node.collapsedChildren.forEach((childNode) => {
2877
- const childNodeTransformData = childNode.getData(import_document9.FlowNodeTransformData);
2943
+ const childNodeTransformData = childNode.getData(import_document10.FlowNodeTransformData);
2878
2944
  childNodeTransformData.fireChange();
2879
2945
  });
2880
2946
  }
@@ -2953,12 +3019,47 @@ WorkflowResetLayoutService = __decorateClass([
2953
3019
  (0, import_inversify7.injectable)()
2954
3020
  ], WorkflowResetLayoutService);
2955
3021
 
3022
+ // src/service/workflow-operation-base-service.ts
3023
+ var import_inversify8 = require("inversify");
3024
+ var import_utils19 = require("@flowgram.ai/utils");
3025
+ var import_document11 = require("@flowgram.ai/document");
3026
+ var import_core19 = require("@flowgram.ai/core");
3027
+ var WorkflowOperationBaseServiceImpl = class extends import_document11.FlowOperationBaseServiceImpl {
3028
+ constructor() {
3029
+ super(...arguments);
3030
+ this.onNodePostionUpdateEmitter = new import_utils19.Emitter();
3031
+ this.onNodePostionUpdate = this.onNodePostionUpdateEmitter.event;
3032
+ }
3033
+ updateNodePosition(nodeOrId, position) {
3034
+ const node = this.toNodeEntity(nodeOrId);
3035
+ if (!node) {
3036
+ return;
3037
+ }
3038
+ const transformData = node.getData(import_core19.TransformData);
3039
+ const oldPosition = {
3040
+ x: transformData.position.x,
3041
+ y: transformData.position.y
3042
+ };
3043
+ transformData.update({
3044
+ position
3045
+ });
3046
+ this.onNodePostionUpdateEmitter.fire({
3047
+ node,
3048
+ oldPosition,
3049
+ newPosition: position
3050
+ });
3051
+ }
3052
+ };
3053
+ __decorateClass([
3054
+ (0, import_inversify8.inject)(WorkflowDocument)
3055
+ ], WorkflowOperationBaseServiceImpl.prototype, "document", 2);
3056
+
2956
3057
  // src/hooks/use-playground-readonly-state.ts
2957
3058
  var import_react = require("react");
2958
- var import_core19 = require("@flowgram.ai/core");
3059
+ var import_core20 = require("@flowgram.ai/core");
2959
3060
  function usePlaygroundReadonlyState(listenChange) {
2960
- const playground = (0, import_core19.usePlayground)();
2961
- const refresh = (0, import_core19.useRefresh)();
3061
+ const playground = (0, import_core20.usePlayground)();
3062
+ const refresh = (0, import_core20.useRefresh)();
2962
3063
  (0, import_react.useEffect)(() => {
2963
3064
  let dispose = void 0;
2964
3065
  if (listenChange) {
@@ -2974,12 +3075,12 @@ function checkTargetDraggable(el) {
2974
3075
  return el && el.tagName !== "INPUT" && el.tagName !== "TEXTAREA" && !el.closest(".flow-canvas-not-draggable");
2975
3076
  }
2976
3077
  function useNodeRender(nodeFromProps) {
2977
- const node = nodeFromProps || (0, import_react2.useContext)(import_core20.PlaygroundEntityContext);
2978
- const renderData = node.getData(import_document10.FlowNodeRenderData);
3078
+ const node = nodeFromProps || (0, import_react2.useContext)(import_core21.PlaygroundEntityContext);
3079
+ const renderData = node.getData(import_document12.FlowNodeRenderData);
2979
3080
  const portsData = node.getData(WorkflowNodePortsData);
2980
3081
  const readonly = usePlaygroundReadonlyState();
2981
- const dragService = (0, import_core20.useService)(WorkflowDragService);
2982
- const selectionService = (0, import_core20.useService)(WorkflowSelectService);
3082
+ const dragService = (0, import_core21.useService)(WorkflowDragService);
3083
+ const selectionService = (0, import_core21.useService)(WorkflowSelectService);
2983
3084
  const isDragging = (0, import_react2.useRef)(false);
2984
3085
  const nodeRef = (0, import_react2.useRef)(null);
2985
3086
  const [linkingNodeId, setLinkingNodeId] = (0, import_react2.useState)("");
@@ -3005,7 +3106,7 @@ function useNodeRender(nodeFromProps) {
3005
3106
  return;
3006
3107
  }
3007
3108
  isDragging.current = true;
3008
- dragService.startDragSelectedNodes(e).finally(
3109
+ dragService.startDragSelectedNodes(e)?.finally(
3009
3110
  () => setTimeout(() => {
3010
3111
  isDragging.current = false;
3011
3112
  })
@@ -3018,7 +3119,7 @@ function useNodeRender(nodeFromProps) {
3018
3119
  if (isDragging.current) {
3019
3120
  return;
3020
3121
  }
3021
- if (e.metaKey || e.shiftKey || e.ctrlKey) {
3122
+ if (e.shiftKey) {
3022
3123
  selectionService.toggleSelect(node);
3023
3124
  } else {
3024
3125
  selectionService.selectNode(node);
@@ -3030,7 +3131,7 @@ function useNodeRender(nodeFromProps) {
3030
3131
  [node]
3031
3132
  );
3032
3133
  const deleteNode = (0, import_react2.useCallback)(() => node.dispose(), [node]);
3033
- (0, import_core20.useListenEvents)(portsData.onDataChange);
3134
+ (0, import_core21.useListenEvents)(portsData.onDataChange);
3034
3135
  const isFirefox = navigator?.userAgent?.includes?.("Firefox");
3035
3136
  const onFocus = (0, import_react2.useCallback)(() => {
3036
3137
  if (isFirefox) {
@@ -3087,24 +3188,24 @@ function useNodeRender(nodeFromProps) {
3087
3188
  }
3088
3189
 
3089
3190
  // src/hooks/use-current-dom-node.ts
3090
- var import_document11 = require("@flowgram.ai/document");
3091
- var import_core21 = require("@flowgram.ai/core");
3191
+ var import_document13 = require("@flowgram.ai/document");
3192
+ var import_core22 = require("@flowgram.ai/core");
3092
3193
  function useCurrentDomNode() {
3093
- const entity = (0, import_core21.useEntityFromContext)();
3094
- const renderData = entity.getData(import_document11.FlowNodeRenderData);
3194
+ const entity = (0, import_core22.useEntityFromContext)();
3195
+ const renderData = entity.getData(import_document13.FlowNodeRenderData);
3095
3196
  return renderData.node;
3096
3197
  }
3097
3198
 
3098
3199
  // src/hooks/use-current-entity.ts
3099
- var import_core22 = require("@flowgram.ai/core");
3200
+ var import_core23 = require("@flowgram.ai/core");
3100
3201
  function useCurrentEntity() {
3101
- return (0, import_core22.useEntityFromContext)();
3202
+ return (0, import_core23.useEntityFromContext)();
3102
3203
  }
3103
3204
 
3104
3205
  // src/hooks/use-workflow-document.ts
3105
- var import_core23 = require("@flowgram.ai/core");
3206
+ var import_core24 = require("@flowgram.ai/core");
3106
3207
  function useWorkflowDocument() {
3107
- return (0, import_core23.useService)(WorkflowDocument);
3208
+ return (0, import_core24.useService)(WorkflowDocument);
3108
3209
  }
3109
3210
 
3110
3211
  // src/constants.ts
@@ -3120,18 +3221,18 @@ var InteractiveType = /* @__PURE__ */ ((InteractiveType2) => {
3120
3221
  })(InteractiveType || {});
3121
3222
 
3122
3223
  // src/workflow-document-container-module.ts
3123
- var import_inversify9 = require("inversify");
3124
- var import_document13 = require("@flowgram.ai/document");
3125
- var import_utils19 = require("@flowgram.ai/utils");
3224
+ var import_inversify10 = require("inversify");
3225
+ var import_utils20 = require("@flowgram.ai/utils");
3226
+ var import_document15 = require("@flowgram.ai/document");
3126
3227
 
3127
3228
  // src/workflow-document-contribution.ts
3128
- var import_inversify8 = require("inversify");
3129
- var import_document12 = require("@flowgram.ai/document");
3229
+ var import_inversify9 = require("inversify");
3230
+ var import_document14 = require("@flowgram.ai/document");
3130
3231
  var WorkflowDocumentContribution = class {
3131
3232
  registerDocument(document2) {
3132
3233
  document2.registerNodeDatas(
3133
- import_document12.FlowNodeTransformData,
3134
- import_document12.FlowNodeRenderData,
3234
+ import_document14.FlowNodeTransformData,
3235
+ import_document14.FlowNodeRenderData,
3135
3236
  WorkflowNodePortsData,
3136
3237
  WorkflowNodeLinesData
3137
3238
  );
@@ -3139,10 +3240,10 @@ var WorkflowDocumentContribution = class {
3139
3240
  }
3140
3241
  };
3141
3242
  __decorateClass([
3142
- (0, import_inversify8.inject)(FreeLayout)
3243
+ (0, import_inversify9.inject)(FreeLayout)
3143
3244
  ], WorkflowDocumentContribution.prototype, "freeLayout", 2);
3144
3245
  WorkflowDocumentContribution = __decorateClass([
3145
- (0, import_inversify8.injectable)()
3246
+ (0, import_inversify9.injectable)()
3146
3247
  ], WorkflowDocumentContribution);
3147
3248
 
3148
3249
  // src/utils/get-url-params.ts
@@ -3155,7 +3256,7 @@ function getUrlParams() {
3155
3256
  }
3156
3257
 
3157
3258
  // src/workflow-document-container-module.ts
3158
- var WorkflowDocumentContainerModule = new import_inversify9.ContainerModule(
3259
+ var WorkflowDocumentContainerModule = new import_inversify10.ContainerModule(
3159
3260
  (bind, unbind, isBound, rebind) => {
3160
3261
  bind(WorkflowDocument).toSelf().inSingletonScope();
3161
3262
  bind(WorkflowLinesManager).toSelf().inSingletonScope();
@@ -3164,18 +3265,19 @@ var WorkflowDocumentContainerModule = new import_inversify9.ContainerModule(
3164
3265
  bind(WorkflowSelectService).toSelf().inSingletonScope();
3165
3266
  bind(WorkflowHoverService).toSelf().inSingletonScope();
3166
3267
  bind(WorkflowResetLayoutService).toSelf().inSingletonScope();
3268
+ bind(WorkflowOperationBaseService).to(WorkflowOperationBaseServiceImpl).inSingletonScope();
3167
3269
  bind(URLParams).toDynamicValue(() => getUrlParams()).inSingletonScope();
3168
- (0, import_utils19.bindContributions)(bind, WorkflowDocumentContribution, [import_document13.FlowDocumentContribution]);
3270
+ (0, import_utils20.bindContributions)(bind, WorkflowDocumentContribution, [import_document15.FlowDocumentContribution]);
3169
3271
  bind(WorkflowDocumentOptions).toConstantValue({
3170
3272
  ...WorkflowDocumentOptionsDefault
3171
3273
  });
3172
- rebind(import_document13.FlowDocument).toService(WorkflowDocument);
3274
+ rebind(import_document15.FlowDocument).toService(WorkflowDocument);
3173
3275
  bind(WorkflowDocumentProvider).toDynamicValue((ctx) => () => ctx.container.get(WorkflowDocument)).inSingletonScope();
3174
3276
  }
3175
3277
  );
3176
3278
 
3177
3279
  // src/utils/simple-line.ts
3178
- var import_utils20 = require("@flowgram.ai/utils");
3280
+ var import_utils21 = require("@flowgram.ai/utils");
3179
3281
  var LINE_PADDING = 12;
3180
3282
  var WorkflowSimpleLineContribution = class {
3181
3283
  constructor(entity) {
@@ -3189,11 +3291,11 @@ var WorkflowSimpleLineContribution = class {
3189
3291
  return Number.MAX_SAFE_INTEGER;
3190
3292
  }
3191
3293
  const [start, end] = this.data.points;
3192
- return import_utils20.Point.getDistance(pos, this.projectPointOnLine(pos, start, end));
3294
+ return import_utils21.Point.getDistance(pos, this.projectPointOnLine(pos, start, end));
3193
3295
  }
3194
3296
  get bounds() {
3195
3297
  if (!this.data) {
3196
- return new import_utils20.Rectangle();
3298
+ return new import_utils21.Rectangle();
3197
3299
  }
3198
3300
  return this.data.bbox;
3199
3301
  }
@@ -3218,7 +3320,7 @@ var WorkflowSimpleLineContribution = class {
3218
3320
  y: toPos.y + targetOffset.y
3219
3321
  }
3220
3322
  ];
3221
- const bbox = import_utils20.Rectangle.createRectangleWithTwoPoints(points[0], points[1]);
3323
+ const bbox = import_utils21.Rectangle.createRectangleWithTwoPoints(points[0], points[1]);
3222
3324
  const adjustedPoints = points.map((p) => ({
3223
3325
  x: p.x - bbox.x + LINE_PADDING,
3224
3326
  y: p.y - bbox.y + LINE_PADDING
@@ -3274,6 +3376,8 @@ WorkflowSimpleLineContribution.type = "WorkflowSimpleLineContribution";
3274
3376
  WorkflowNodeEntity,
3275
3377
  WorkflowNodeLinesData,
3276
3378
  WorkflowNodePortsData,
3379
+ WorkflowOperationBaseService,
3380
+ WorkflowOperationBaseServiceImpl,
3277
3381
  WorkflowPortEntity,
3278
3382
  WorkflowResetLayoutService,
3279
3383
  WorkflowSelectService,