@flowgram.ai/free-layout-core 0.1.13 → 0.1.14

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 +156 -60
  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 +202 -105
  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-CF97dniV.d.mts} +90 -170
  40. package/dist/{workflow-line-entity-CEitdjhk.d.ts → workflow-line-entity-niuFXSbE.d.ts} +90 -170
  41. package/package.json +9 -9
  42. package/dist/esm/chunk-DE4324TR.js.map +0 -1
@@ -4,4 +4,4 @@ var URLParams = Symbol("");
4
4
  export {
5
5
  URLParams
6
6
  };
7
- //# sourceMappingURL=chunk-DE4324TR.js.map
7
+ //# sourceMappingURL=chunk-IYUZVBAO.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/typings/index.ts"],"sourcesContent":["export * from './workflow-json';\nexport * from './workflow-edge';\nexport * from './workflow-node';\nexport * from './workflow-registry';\nexport * from './workflow-line';\nexport * from './workflow-sub-canvas';\nexport * from './workflow-operation';\nexport * from './workflow-drag';\n\nexport const URLParams = Symbol('');\n\nexport interface URLParams {\n [key: string]: string;\n}\n"],"mappings":";AASO,IAAM,YAAY,OAAO,EAAE;","names":[]}
@@ -0,0 +1,7 @@
1
+ // src/typings/workflow-operation.ts
2
+ var WorkflowOperationBaseService = Symbol("WorkflowOperationBaseService");
3
+
4
+ export {
5
+ WorkflowOperationBaseService
6
+ };
7
+ //# sourceMappingURL=chunk-LJH3TSLZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/typings/workflow-operation.ts"],"sourcesContent":["import { IPoint, Event } from '@flowgram.ai/utils';\nimport {\n FlowNodeEntity,\n FlowNodeEntityOrId,\n FlowOperationBaseService,\n} from '@flowgram.ai/document';\n\nexport interface NodePostionUpdateEvent {\n node: FlowNodeEntity;\n oldPosition: IPoint;\n newPosition: IPoint;\n}\n\nexport interface WorkflowOperationBaseService extends FlowOperationBaseService {\n /**\n * 节点位置更新事件\n */\n readonly onNodePostionUpdate: Event<NodePostionUpdateEvent>;\n /**\n * 更新节点位置\n * @param nodeOrId\n * @param position\n * @returns\n */\n updateNodePosition(nodeOrId: FlowNodeEntityOrId, position: IPoint): void;\n}\n\nexport const WorkflowOperationBaseService = Symbol('WorkflowOperationBaseService');\n"],"mappings":";AA2BO,IAAM,+BAA+B,OAAO,8BAA8B;","names":[]}
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=chunk-TQLT57GW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/dist/esm/index.js CHANGED
@@ -1,6 +1,9 @@
1
1
  import {
2
2
  URLParams
3
- } from "./chunk-DE4324TR.js";
3
+ } from "./chunk-IYUZVBAO.js";
4
+ import "./chunk-KNYZRMIO.js";
5
+ import "./chunk-NU6G5HF4.js";
6
+ import "./chunk-TQLT57GW.js";
4
7
  import "./chunk-CGOMTQ3G.js";
5
8
  import {
6
9
  WorkflowContentChangeType
@@ -9,12 +12,13 @@ import {
9
12
  LineColors,
10
13
  LineType
11
14
  } from "./chunk-PT4ZVDZZ.js";
15
+ import "./chunk-DDJTYHXN.js";
16
+ import {
17
+ WorkflowOperationBaseService
18
+ } from "./chunk-LJH3TSLZ.js";
12
19
  import {
13
20
  __decorateClass
14
21
  } from "./chunk-EUXUH3YW.js";
15
- import "./chunk-DDJTYHXN.js";
16
- import "./chunk-KNYZRMIO.js";
17
- import "./chunk-NU6G5HF4.js";
18
22
 
19
23
  // src/workflow-commands.ts
20
24
  var WorkflowCommands = /* @__PURE__ */ ((WorkflowCommands2) => {
@@ -47,7 +51,7 @@ import {
47
51
  import { useCallback, useEffect as useEffect2, useRef, useState, useContext, useMemo } from "react";
48
52
  import { useObserve } from "@flowgram.ai/reactive";
49
53
  import { getNodeForm } from "@flowgram.ai/node";
50
- import { FlowNodeRenderData as FlowNodeRenderData2 } from "@flowgram.ai/document";
54
+ import { FlowNodeRenderData as FlowNodeRenderData3 } from "@flowgram.ai/document";
51
55
  import { PlaygroundEntityContext, useListenEvents, useService } from "@flowgram.ai/core";
52
56
 
53
57
  // src/service/workflow-select-service.ts
@@ -131,6 +135,7 @@ import { EntityData, SizeData } from "@flowgram.ai/core";
131
135
 
132
136
  // src/entities/workflow-port-entity.ts
133
137
  import { Rectangle as Rectangle3, Emitter } from "@flowgram.ai/utils";
138
+ import { FlowNodeTransformData } from "@flowgram.ai/document";
134
139
  import {
135
140
  Entity,
136
141
  PlaygroundConfigEntity,
@@ -182,7 +187,7 @@ var WorkflowPortEntity = class extends Entity {
182
187
  }
183
188
  get point() {
184
189
  const { targetElement } = this;
185
- const { bounds } = this.node.getData(TransformData3);
190
+ const { bounds } = this.node.getData(FlowNodeTransformData);
186
191
  if (targetElement) {
187
192
  const pos = domReactToBounds(targetElement.getBoundingClientRect()).center;
188
193
  return this.entityManager.getEntity(PlaygroundConfigEntity).getPosFromMouseEvent({
@@ -211,7 +216,7 @@ var WorkflowPortEntity = class extends Entity {
211
216
  */
212
217
  get relativePosition() {
213
218
  const { point } = this;
214
- const { bounds } = this.node.getData(TransformData3);
219
+ const { bounds } = this.node.getData(FlowNodeTransformData);
215
220
  return {
216
221
  x: point.x - bounds.x,
217
222
  y: point.y - bounds.y
@@ -1099,7 +1104,7 @@ import {
1099
1104
  delay as delay2
1100
1105
  } from "@flowgram.ai/utils";
1101
1106
  import {
1102
- FlowNodeTransformData as FlowNodeTransformData5,
1107
+ FlowNodeTransformData as FlowNodeTransformData6,
1103
1108
  FlowOperationBaseService
1104
1109
  } from "@flowgram.ai/document";
1105
1110
  import { FlowNodeBaseType as FlowNodeBaseType2 } from "@flowgram.ai/document";
@@ -1114,12 +1119,12 @@ import {
1114
1119
  import { last } from "lodash-es";
1115
1120
  import { inject as inject3, injectable as injectable3 } from "inversify";
1116
1121
  import { Disposable as Disposable2, DisposableCollection, Emitter as Emitter3 } from "@flowgram.ai/utils";
1117
- import { FlowNodeTransformData as FlowNodeTransformData2 } from "@flowgram.ai/document";
1122
+ import { FlowNodeRenderData as FlowNodeRenderData2, FlowNodeTransformData as FlowNodeTransformData3 } from "@flowgram.ai/document";
1118
1123
  import { EntityManager as EntityManager2, PlaygroundConfigEntity as PlaygroundConfigEntity2, TransformData as TransformData6 } from "@flowgram.ai/core";
1119
1124
 
1120
1125
  // src/workflow-document-option.ts
1121
1126
  import { FlowNodeErrorData } from "@flowgram.ai/form-core";
1122
- import { FlowNodeTransformData } from "@flowgram.ai/document";
1127
+ import { FlowNodeTransformData as FlowNodeTransformData2 } from "@flowgram.ai/document";
1123
1128
  import { TransformData as TransformData5 } from "@flowgram.ai/core";
1124
1129
 
1125
1130
  // src/utils/flow-node-form-data.ts
@@ -1170,7 +1175,7 @@ var WorkflowDocumentOptionsDefault = {
1170
1175
  const nodeMeta = node.getNodeMeta();
1171
1176
  const subCanvas = nodeMeta.subCanvas?.(node);
1172
1177
  if (subCanvas?.isCanvas === false) {
1173
- const canvasNodeTransform = subCanvas.canvasNode.getData(FlowNodeTransformData);
1178
+ const canvasNodeTransform = subCanvas.canvasNode.getData(FlowNodeTransformData2);
1174
1179
  const { x, y } = canvasNodeTransform.transform.position;
1175
1180
  metaData.canvasPosition = { x, y };
1176
1181
  }
@@ -1468,12 +1473,12 @@ var WorkflowLinesManager = class {
1468
1473
  * @param pos - 鼠标位置
1469
1474
  */
1470
1475
  getNodeFromMousePos(pos) {
1471
- const allNodes = this.document.getAllNodes();
1476
+ const allNodes = this.document.getAllNodes().sort((a, b) => this.getNodeIndex(a) - this.getNodeIndex(b));
1472
1477
  const containNodes = [];
1473
1478
  const { selection } = this.selectService;
1474
1479
  const zoom = this.entityManager.getEntity(PlaygroundConfigEntity2)?.config?.zoom || 1;
1475
1480
  allNodes.forEach((node) => {
1476
- const { bounds } = node.getData(FlowNodeTransformData2);
1481
+ const { bounds } = node.getData(FlowNodeTransformData3);
1477
1482
  if (bounds.clone().pad(4 / zoom).contains(pos.x, pos.y)) {
1478
1483
  containNodes.push(node);
1479
1484
  }
@@ -1495,6 +1500,10 @@ var WorkflowLinesManager = class {
1495
1500
  registerData(line) {
1496
1501
  line.addData(WorkflowLineRenderData);
1497
1502
  }
1503
+ getNodeIndex(node) {
1504
+ const nodeRenderData = node.getData(FlowNodeRenderData2);
1505
+ return nodeRenderData.stackIndex;
1506
+ }
1498
1507
  };
1499
1508
  __decorateClass([
1500
1509
  inject3(WorkflowHoverService)
@@ -1517,7 +1526,7 @@ import { customAlphabet } from "nanoid";
1517
1526
  import { inject as inject5, injectable as injectable5, optional, postConstruct } from "inversify";
1518
1527
  import { Disposable as Disposable3, Emitter as Emitter4 } from "@flowgram.ai/utils";
1519
1528
  import { NodeEngineContext } from "@flowgram.ai/form-core";
1520
- import { FlowDocument, FlowNodeBaseType, FlowNodeTransformData as FlowNodeTransformData4 } from "@flowgram.ai/document";
1529
+ import { FlowDocument, FlowNodeBaseType, FlowNodeTransformData as FlowNodeTransformData5 } from "@flowgram.ai/document";
1521
1530
  import {
1522
1531
  injectPlaygroundContext,
1523
1532
  PlaygroundConfigEntity as PlaygroundConfigEntity4,
@@ -1529,7 +1538,7 @@ import {
1529
1538
  import { inject as inject4, injectable as injectable4 } from "inversify";
1530
1539
  import {
1531
1540
  FlowDocumentProvider,
1532
- FlowNodeTransformData as FlowNodeTransformData3
1541
+ FlowNodeTransformData as FlowNodeTransformData4
1533
1542
  } from "@flowgram.ai/document";
1534
1543
  import { PlaygroundConfigEntity as PlaygroundConfigEntity3, TransformData as TransformData7 } from "@flowgram.ai/core";
1535
1544
  import {
@@ -1549,12 +1558,12 @@ var FreeLayout = class {
1549
1558
  * 更新布局
1550
1559
  */
1551
1560
  update() {
1552
- if (this.document.root.getData(FlowNodeTransformData3)?.localDirty) {
1561
+ if (this.document.root.getData(FlowNodeTransformData4)?.localDirty) {
1553
1562
  this.document.root.clearMemoGlobal();
1554
1563
  }
1555
1564
  }
1556
1565
  syncTransform(node) {
1557
- const transform = node.getData(FlowNodeTransformData3);
1566
+ const transform = node.getData(FlowNodeTransformData4);
1558
1567
  if (!transform.localDirty) {
1559
1568
  return;
1560
1569
  }
@@ -1568,7 +1577,7 @@ var FreeLayout = class {
1568
1577
  }
1569
1578
  node.parent.clearMemoGlobal();
1570
1579
  node.parent.clearMemoLocal();
1571
- const parentTransform = node.parent.getData(FlowNodeTransformData3);
1580
+ const parentTransform = node.parent.getData(FlowNodeTransformData4);
1572
1581
  parentTransform.transform.fireChange();
1573
1582
  }
1574
1583
  /**
@@ -1577,7 +1586,7 @@ var FreeLayout = class {
1577
1586
  */
1578
1587
  getPadding(node) {
1579
1588
  const { padding } = node.getNodeMeta();
1580
- const transform = node.getData(FlowNodeTransformData3);
1589
+ const transform = node.getData(FlowNodeTransformData4);
1581
1590
  if (padding) {
1582
1591
  return typeof padding === "function" ? padding(transform) : padding;
1583
1592
  }
@@ -1723,7 +1732,7 @@ var WorkflowDocument = class extends FlowDocument {
1723
1732
  const { formMeta } = registry;
1724
1733
  const meta = node.getNodeMeta();
1725
1734
  const formData = getFlowNodeFormData(node);
1726
- const transform = node.getData(FlowNodeTransformData4);
1735
+ const transform = node.getData(FlowNodeTransformData5);
1727
1736
  const freeLayout = this.layout;
1728
1737
  transform.onDataChange(() => {
1729
1738
  freeLayout.syncTransform(node);
@@ -1774,7 +1783,7 @@ var WorkflowDocument = class extends FlowDocument {
1774
1783
  if (!node.parent || node.parent.flowNodeType === FlowNodeBaseType.ROOT) {
1775
1784
  return;
1776
1785
  }
1777
- const parentTransform = node.parent.getData(FlowNodeTransformData4);
1786
+ const parentTransform = node.parent.getData(FlowNodeTransformData5);
1778
1787
  setTimeout(() => {
1779
1788
  parentTransform.fireChange();
1780
1789
  }, 0);
@@ -1875,8 +1884,8 @@ var WorkflowDocument = class extends FlowDocument {
1875
1884
  }));
1876
1885
  const startNodeId = allNode.find((node) => node.isStart).id;
1877
1886
  const endNodeId = allNode.find((node) => node.isNodeEnd).id;
1878
- const nodeInSubCanvas = allNode.filter((node) => node.parent?.flowNodeType === FlowNodeBaseType.SUB_CANVAS).map((node) => node.id);
1879
- const associatedCache = /* @__PURE__ */ new Set([endNodeId, ...nodeInSubCanvas]);
1887
+ const nodeInContainer = allNode.filter((node) => node.parent?.getNodeMeta().isContainer).map((node) => node.id);
1888
+ const associatedCache = /* @__PURE__ */ new Set([endNodeId, ...nodeInContainer]);
1880
1889
  const bfs = (nodeId) => {
1881
1890
  if (associatedCache.has(nodeId)) {
1882
1891
  return;
@@ -2151,7 +2160,7 @@ var WorkflowDocument = class extends FlowDocument {
2151
2160
  }
2152
2161
  toLineJSON(line) {
2153
2162
  const lineJSON = line.toJSON();
2154
- if (!line.to || !line.info.to || !line.toPort) {
2163
+ if (!line.from || !line.info.from || !line.fromPort || !line.to || !line.info.to || !line.toPort) {
2155
2164
  return;
2156
2165
  }
2157
2166
  const fromSubCanvas = this.getNodeSubCanvas(line.from);
@@ -2269,18 +2278,19 @@ var WorkflowDragService = class {
2269
2278
  }
2270
2279
  /**
2271
2280
  * 拖拽选中节点
2272
- * @param event
2281
+ * @param triggerEvent
2273
2282
  */
2274
- startDragSelectedNodes(event) {
2283
+ startDragSelectedNodes(triggerEvent) {
2275
2284
  let { selectedNodes } = this.selectService;
2276
- if (selectedNodes.length === 0 || this.playgroundConfig.readonly || this.playgroundConfig.disabled) {
2285
+ if (selectedNodes.length === 0 || this.playgroundConfig.readonly || this.playgroundConfig.disabled || this.isDragging) {
2277
2286
  return Promise.resolve(false);
2278
2287
  }
2288
+ this.isDragging = true;
2279
2289
  const sameParent = this.childrenOfContainer(selectedNodes);
2280
2290
  if (sameParent && sameParent.flowNodeType !== FlowNodeBaseType2.ROOT) {
2281
2291
  selectedNodes = [sameParent];
2282
2292
  }
2283
- const { altKey } = event;
2293
+ const { altKey } = triggerEvent;
2284
2294
  let startPosition = this.getNodesPosition(selectedNodes);
2285
2295
  let startPositions = selectedNodes.map((node) => {
2286
2296
  const transform = node.getData(TransformData9);
@@ -2289,11 +2299,19 @@ var WorkflowDragService = class {
2289
2299
  let dragSuccess = false;
2290
2300
  const startTime = Date.now();
2291
2301
  const dragger = new PlaygroundDrag({
2292
- onDragStart: () => {
2293
- this.isDragging = true;
2302
+ onDragStart: (dragEvent) => {
2303
+ this._nodesDragEmitter.fire({
2304
+ type: "onDragStart",
2305
+ nodes: selectedNodes,
2306
+ startPositions,
2307
+ altKey,
2308
+ dragEvent,
2309
+ triggerEvent,
2310
+ dragger
2311
+ });
2294
2312
  },
2295
- onDrag: (e) => {
2296
- if (!dragSuccess && checkDragSuccess(Date.now() - startTime, e)) {
2313
+ onDrag: (dragEvent) => {
2314
+ if (!dragSuccess && checkDragSuccess(Date.now() - startTime, dragEvent)) {
2297
2315
  dragSuccess = true;
2298
2316
  if (altKey) {
2299
2317
  const tryCopyNodes = selectedNodes;
@@ -2316,10 +2334,11 @@ var WorkflowDragService = class {
2316
2334
  }
2317
2335
  }
2318
2336
  const offset = this.getDragPosOffset({
2319
- event: e,
2337
+ event: dragEvent,
2320
2338
  selectedNodes,
2321
2339
  startPosition
2322
2340
  });
2341
+ const positions = [];
2323
2342
  selectedNodes.forEach((node, index) => {
2324
2343
  const transform = node.getData(TransformData9);
2325
2344
  const nodeStartPosition = startPositions[index];
@@ -2329,26 +2348,40 @@ var WorkflowDragService = class {
2329
2348
  };
2330
2349
  if (node.collapsedChildren?.length > 0) {
2331
2350
  node.collapsedChildren.forEach((childNode) => {
2332
- const childNodeTransformData = childNode.getData(FlowNodeTransformData5);
2351
+ const childNodeTransformData = childNode.getData(FlowNodeTransformData6);
2333
2352
  childNodeTransformData.fireChange();
2334
2353
  });
2335
2354
  }
2336
2355
  transform.update({
2337
2356
  position: newPosition
2338
2357
  });
2358
+ positions.push(newPosition);
2359
+ });
2360
+ this._nodesDragEmitter.fire({
2361
+ type: "onDragging",
2362
+ nodes: selectedNodes,
2363
+ startPositions,
2364
+ positions,
2365
+ altKey,
2366
+ dragEvent,
2367
+ triggerEvent,
2368
+ dragger
2339
2369
  });
2340
2370
  },
2341
- onDragEnd: () => {
2371
+ onDragEnd: (dragEvent) => {
2342
2372
  this.isDragging = false;
2343
2373
  this._nodesDragEmitter.fire({
2344
2374
  type: "onDragEnd",
2345
2375
  nodes: selectedNodes,
2346
2376
  startPositions,
2347
- altKey
2377
+ altKey,
2378
+ dragEvent,
2379
+ triggerEvent,
2380
+ dragger
2348
2381
  });
2349
2382
  }
2350
2383
  });
2351
- return dragger.start(event.clientX, event.clientY, this.playgroundConfig).then(() => dragSuccess);
2384
+ return dragger.start(triggerEvent.clientX, triggerEvent.clientY, this.playgroundConfig)?.then(() => dragSuccess);
2352
2385
  }
2353
2386
  /**
2354
2387
  * 通过拖入卡片添加
@@ -2420,6 +2453,13 @@ var WorkflowDragService = class {
2420
2453
  },
2421
2454
  onDragEnd: async (e) => {
2422
2455
  const dropNode = this._dropNode;
2456
+ const { allowDrop } = this.canDropToNode({
2457
+ dragNodeType: type,
2458
+ dropNode
2459
+ });
2460
+ if (!allowDrop) {
2461
+ return this.clearDrop();
2462
+ }
2423
2463
  const dragNode = await this.dropCard(type, e, data, dropNode);
2424
2464
  this.clearDrop();
2425
2465
  if (dragNode) {
@@ -2473,6 +2513,22 @@ var WorkflowDragService = class {
2473
2513
  dispose: () => this.posAdjusters.delete(adjuster)
2474
2514
  };
2475
2515
  }
2516
+ /**
2517
+ * 判断是否可以放置节点
2518
+ */
2519
+ canDropToNode(params) {
2520
+ const { dragNodeType, dropNode } = params;
2521
+ if (!dragNodeType) {
2522
+ return {
2523
+ allowDrop: false,
2524
+ message: "Please select a node to drop"
2525
+ };
2526
+ }
2527
+ return {
2528
+ allowDrop: true,
2529
+ dropNode
2530
+ };
2531
+ }
2476
2532
  /**
2477
2533
  * 获取拖拽偏移
2478
2534
  */
@@ -2503,23 +2559,24 @@ var WorkflowDragService = class {
2503
2559
  return offset;
2504
2560
  }
2505
2561
  updateDroppableTransforms() {
2506
- this._droppableTransforms = this.document.getRenderDatas(FlowNodeTransformData5, false).filter((transform) => {
2562
+ this._droppableTransforms = this.document.getRenderDatas(FlowNodeTransformData6, false).filter((transform) => {
2507
2563
  const { entity } = transform;
2508
2564
  if (entity.originParent) {
2509
2565
  return this.nodeSelectable(entity) && this.nodeSelectable(entity.originParent);
2510
2566
  }
2511
2567
  return this.nodeSelectable(entity);
2512
- }).filter((transform) => {
2513
- const { entity } = transform;
2514
- return entity.flowNodeType === FlowNodeBaseType2.SUB_CANVAS;
2515
- });
2568
+ }).filter((transform) => this.isContainer(transform.entity));
2569
+ }
2570
+ /** 是否容器节点 */
2571
+ isContainer(node) {
2572
+ return node?.getNodeMeta().isContainer ?? false;
2516
2573
  }
2517
2574
  /**
2518
2575
  * 获取节点整体位置
2519
2576
  */
2520
2577
  getNodesPosition(nodes) {
2521
2578
  const selectedBounds = Rectangle8.enlarge(
2522
- nodes.map((n) => n.getData(FlowNodeTransformData5).bounds)
2579
+ nodes.map((n) => n.getData(FlowNodeTransformData6).bounds)
2523
2580
  );
2524
2581
  const position = {
2525
2582
  x: selectedBounds.x,
@@ -2569,7 +2626,7 @@ var WorkflowDragService = class {
2569
2626
  return {
2570
2627
  hasError: false
2571
2628
  };
2572
- } else if (toNode.flowNodeType === FlowNodeBaseType2.SUB_CANVAS) {
2629
+ } else if (this.isContainer(toNode)) {
2573
2630
  return {
2574
2631
  hasError: false
2575
2632
  };
@@ -2604,6 +2661,7 @@ var WorkflowDragService = class {
2604
2661
  if (originLine?.disabled || isFromInActivePort || this.playgroundConfig.readonly || this.playgroundConfig.disabled) {
2605
2662
  return { dragSuccess: false, newLine: void 0 };
2606
2663
  }
2664
+ this.selectService.clear();
2607
2665
  const config = this.playgroundConfig;
2608
2666
  const deferred = new PromiseDeferred();
2609
2667
  const preCursor = config.cursor;
@@ -2649,7 +2707,7 @@ var WorkflowDragService = class {
2649
2707
  type: "onDrag"
2650
2708
  });
2651
2709
  this.setLineColor(line, this.linesManager.lineColor.drawing);
2652
- if (toNode && toNode.flowNodeType !== FlowNodeBaseType2.SUB_CANVAS) {
2710
+ if (toNode && !this.isContainer(toNode)) {
2653
2711
  const portsData = toNode.getData(WorkflowNodePortsData);
2654
2712
  toPort = portsData.inputPorts[0];
2655
2713
  const { hasError } = this.handleDragOnNode(toNode, fromPort, line, toPort, originLine);
@@ -2797,13 +2855,13 @@ import { EntityManager as EntityManager3 } from "@flowgram.ai/core";
2797
2855
  import { DisposableCollection as DisposableCollection3, Emitter as Emitter6 } from "@flowgram.ai/utils";
2798
2856
 
2799
2857
  // src/utils/layout-to-positions.ts
2800
- import { FlowNodeTransformData as FlowNodeTransformData6 } from "@flowgram.ai/document";
2858
+ import { FlowNodeTransformData as FlowNodeTransformData7 } from "@flowgram.ai/document";
2801
2859
  import { TransformData as TransformData10, startTween } from "@flowgram.ai/core";
2802
2860
  var layoutToPositions = async (nodes, nodePositionMap) => {
2803
2861
  const newNodePositionMap = {};
2804
2862
  nodes.forEach((node) => {
2805
2863
  const transform = node.getData(TransformData10);
2806
- const nodeTransform = node.getData(FlowNodeTransformData6);
2864
+ const nodeTransform = node.getData(FlowNodeTransformData7);
2807
2865
  newNodePositionMap[node.id] = {
2808
2866
  x: transform.position.x,
2809
2867
  y: transform.position.y + nodeTransform.bounds.height / 2
@@ -2821,7 +2879,7 @@ var layoutToPositions = async (nodes, nodePositionMap) => {
2821
2879
  const deltaY = (nodePositionMap[node.id].y - transform.bounds.height / 2 - transform.position.y) * v.d / 100;
2822
2880
  if (node.collapsedChildren?.length > 0) {
2823
2881
  node.collapsedChildren.forEach((childNode) => {
2824
- const childNodeTransformData = childNode.getData(FlowNodeTransformData6);
2882
+ const childNodeTransformData = childNode.getData(FlowNodeTransformData7);
2825
2883
  childNodeTransformData.fireChange();
2826
2884
  });
2827
2885
  }
@@ -2900,6 +2958,41 @@ WorkflowResetLayoutService = __decorateClass([
2900
2958
  injectable7()
2901
2959
  ], WorkflowResetLayoutService);
2902
2960
 
2961
+ // src/service/workflow-operation-base-service.ts
2962
+ import { inject as inject8 } from "inversify";
2963
+ import { Emitter as Emitter7 } from "@flowgram.ai/utils";
2964
+ import { FlowOperationBaseServiceImpl } from "@flowgram.ai/document";
2965
+ import { TransformData as TransformData11 } from "@flowgram.ai/core";
2966
+ var WorkflowOperationBaseServiceImpl = class extends FlowOperationBaseServiceImpl {
2967
+ constructor() {
2968
+ super(...arguments);
2969
+ this.onNodePostionUpdateEmitter = new Emitter7();
2970
+ this.onNodePostionUpdate = this.onNodePostionUpdateEmitter.event;
2971
+ }
2972
+ updateNodePosition(nodeOrId, position) {
2973
+ const node = this.toNodeEntity(nodeOrId);
2974
+ if (!node) {
2975
+ return;
2976
+ }
2977
+ const transformData = node.getData(TransformData11);
2978
+ const oldPosition = {
2979
+ x: transformData.position.x,
2980
+ y: transformData.position.y
2981
+ };
2982
+ transformData.update({
2983
+ position
2984
+ });
2985
+ this.onNodePostionUpdateEmitter.fire({
2986
+ node,
2987
+ oldPosition,
2988
+ newPosition: position
2989
+ });
2990
+ }
2991
+ };
2992
+ __decorateClass([
2993
+ inject8(WorkflowDocument)
2994
+ ], WorkflowOperationBaseServiceImpl.prototype, "document", 2);
2995
+
2903
2996
  // src/hooks/use-playground-readonly-state.ts
2904
2997
  import { useEffect } from "react";
2905
2998
  import { usePlayground, useRefresh } from "@flowgram.ai/core";
@@ -2922,7 +3015,7 @@ function checkTargetDraggable(el) {
2922
3015
  }
2923
3016
  function useNodeRender(nodeFromProps) {
2924
3017
  const node = nodeFromProps || useContext(PlaygroundEntityContext);
2925
- const renderData = node.getData(FlowNodeRenderData2);
3018
+ const renderData = node.getData(FlowNodeRenderData3);
2926
3019
  const portsData = node.getData(WorkflowNodePortsData);
2927
3020
  const readonly = usePlaygroundReadonlyState();
2928
3021
  const dragService = useService(WorkflowDragService);
@@ -2952,7 +3045,7 @@ function useNodeRender(nodeFromProps) {
2952
3045
  return;
2953
3046
  }
2954
3047
  isDragging.current = true;
2955
- dragService.startDragSelectedNodes(e).finally(
3048
+ dragService.startDragSelectedNodes(e)?.finally(
2956
3049
  () => setTimeout(() => {
2957
3050
  isDragging.current = false;
2958
3051
  })
@@ -2965,7 +3058,7 @@ function useNodeRender(nodeFromProps) {
2965
3058
  if (isDragging.current) {
2966
3059
  return;
2967
3060
  }
2968
- if (e.metaKey || e.shiftKey || e.ctrlKey) {
3061
+ if (e.shiftKey) {
2969
3062
  selectionService.toggleSelect(node);
2970
3063
  } else {
2971
3064
  selectionService.selectNode(node);
@@ -3034,11 +3127,11 @@ function useNodeRender(nodeFromProps) {
3034
3127
  }
3035
3128
 
3036
3129
  // src/hooks/use-current-dom-node.ts
3037
- import { FlowNodeRenderData as FlowNodeRenderData3 } from "@flowgram.ai/document";
3130
+ import { FlowNodeRenderData as FlowNodeRenderData4 } from "@flowgram.ai/document";
3038
3131
  import { useEntityFromContext } from "@flowgram.ai/core";
3039
3132
  function useCurrentDomNode() {
3040
3133
  const entity = useEntityFromContext();
3041
- const renderData = entity.getData(FlowNodeRenderData3);
3134
+ const renderData = entity.getData(FlowNodeRenderData4);
3042
3135
  return renderData.node;
3043
3136
  }
3044
3137
 
@@ -3068,20 +3161,20 @@ var InteractiveType = /* @__PURE__ */ ((InteractiveType2) => {
3068
3161
 
3069
3162
  // src/workflow-document-container-module.ts
3070
3163
  import { ContainerModule } from "inversify";
3071
- import { FlowDocument as FlowDocument2, FlowDocumentContribution } from "@flowgram.ai/document";
3072
3164
  import { bindContributions } from "@flowgram.ai/utils";
3165
+ import { FlowDocument as FlowDocument2, FlowDocumentContribution } from "@flowgram.ai/document";
3073
3166
 
3074
3167
  // src/workflow-document-contribution.ts
3075
- import { injectable as injectable8, inject as inject8 } from "inversify";
3168
+ import { injectable as injectable8, inject as inject9 } from "inversify";
3076
3169
  import {
3077
- FlowNodeRenderData as FlowNodeRenderData4,
3078
- FlowNodeTransformData as FlowNodeTransformData7
3170
+ FlowNodeRenderData as FlowNodeRenderData5,
3171
+ FlowNodeTransformData as FlowNodeTransformData8
3079
3172
  } from "@flowgram.ai/document";
3080
3173
  var WorkflowDocumentContribution = class {
3081
3174
  registerDocument(document2) {
3082
3175
  document2.registerNodeDatas(
3083
- FlowNodeTransformData7,
3084
- FlowNodeRenderData4,
3176
+ FlowNodeTransformData8,
3177
+ FlowNodeRenderData5,
3085
3178
  WorkflowNodePortsData,
3086
3179
  WorkflowNodeLinesData
3087
3180
  );
@@ -3089,7 +3182,7 @@ var WorkflowDocumentContribution = class {
3089
3182
  }
3090
3183
  };
3091
3184
  __decorateClass([
3092
- inject8(FreeLayout)
3185
+ inject9(FreeLayout)
3093
3186
  ], WorkflowDocumentContribution.prototype, "freeLayout", 2);
3094
3187
  WorkflowDocumentContribution = __decorateClass([
3095
3188
  injectable8()
@@ -3114,6 +3207,7 @@ var WorkflowDocumentContainerModule = new ContainerModule(
3114
3207
  bind(WorkflowSelectService).toSelf().inSingletonScope();
3115
3208
  bind(WorkflowHoverService).toSelf().inSingletonScope();
3116
3209
  bind(WorkflowResetLayoutService).toSelf().inSingletonScope();
3210
+ bind(WorkflowOperationBaseService).to(WorkflowOperationBaseServiceImpl).inSingletonScope();
3117
3211
  bind(URLParams).toDynamicValue(() => getUrlParams()).inSingletonScope();
3118
3212
  bindContributions(bind, WorkflowDocumentContribution, [FlowDocumentContribution]);
3119
3213
  bind(WorkflowDocumentOptions).toConstantValue({
@@ -3223,6 +3317,8 @@ export {
3223
3317
  WorkflowNodeEntity,
3224
3318
  WorkflowNodeLinesData,
3225
3319
  WorkflowNodePortsData,
3320
+ WorkflowOperationBaseService,
3321
+ WorkflowOperationBaseServiceImpl,
3226
3322
  WorkflowPortEntity,
3227
3323
  WorkflowResetLayoutService,
3228
3324
  WorkflowSelectService,