@flowgram.ai/free-layout-core 0.1.0-alpha.10

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 (85) hide show
  1. package/dist/esm/chunk-242F2JCI.js +16 -0
  2. package/dist/esm/chunk-242F2JCI.js.map +1 -0
  3. package/dist/esm/chunk-CGOMTQ3G.js +1 -0
  4. package/dist/esm/chunk-CGOMTQ3G.js.map +1 -0
  5. package/dist/esm/chunk-CTGO4RKX.js +22 -0
  6. package/dist/esm/chunk-CTGO4RKX.js.map +1 -0
  7. package/dist/esm/chunk-DDJTYHXN.js +1 -0
  8. package/dist/esm/chunk-DDJTYHXN.js.map +1 -0
  9. package/dist/esm/chunk-EUXUH3YW.js +15 -0
  10. package/dist/esm/chunk-EUXUH3YW.js.map +1 -0
  11. package/dist/esm/chunk-IKQUOAWQ.js +7 -0
  12. package/dist/esm/chunk-IKQUOAWQ.js.map +1 -0
  13. package/dist/esm/chunk-KNYZRMIO.js +1 -0
  14. package/dist/esm/chunk-KNYZRMIO.js.map +1 -0
  15. package/dist/esm/chunk-NU6G5HF4.js +1 -0
  16. package/dist/esm/chunk-NU6G5HF4.js.map +1 -0
  17. package/dist/esm/chunk-O4WKIIW2.js +7 -0
  18. package/dist/esm/chunk-O4WKIIW2.js.map +1 -0
  19. package/dist/esm/chunk-TQLT57GW.js +1 -0
  20. package/dist/esm/chunk-TQLT57GW.js.map +1 -0
  21. package/dist/esm/index.js +3471 -0
  22. package/dist/esm/index.js.map +1 -0
  23. package/dist/esm/typings/index.js +27 -0
  24. package/dist/esm/typings/index.js.map +1 -0
  25. package/dist/esm/typings/workflow-drag.js +2 -0
  26. package/dist/esm/typings/workflow-drag.js.map +1 -0
  27. package/dist/esm/typings/workflow-edge.js +2 -0
  28. package/dist/esm/typings/workflow-edge.js.map +1 -0
  29. package/dist/esm/typings/workflow-json.js +8 -0
  30. package/dist/esm/typings/workflow-json.js.map +1 -0
  31. package/dist/esm/typings/workflow-line.js +10 -0
  32. package/dist/esm/typings/workflow-line.js.map +1 -0
  33. package/dist/esm/typings/workflow-node.js +2 -0
  34. package/dist/esm/typings/workflow-node.js.map +1 -0
  35. package/dist/esm/typings/workflow-operation.js +8 -0
  36. package/dist/esm/typings/workflow-operation.js.map +1 -0
  37. package/dist/esm/typings/workflow-registry.js +2 -0
  38. package/dist/esm/typings/workflow-registry.js.map +1 -0
  39. package/dist/esm/typings/workflow-sub-canvas.js +2 -0
  40. package/dist/esm/typings/workflow-sub-canvas.js.map +1 -0
  41. package/dist/index.d.mts +565 -0
  42. package/dist/index.d.ts +565 -0
  43. package/dist/index.js +3515 -0
  44. package/dist/index.js.map +1 -0
  45. package/dist/typings/index.d.mts +23 -0
  46. package/dist/typings/index.d.ts +23 -0
  47. package/dist/typings/index.js +73 -0
  48. package/dist/typings/index.js.map +1 -0
  49. package/dist/typings/workflow-drag.d.mts +8 -0
  50. package/dist/typings/workflow-drag.d.ts +8 -0
  51. package/dist/typings/workflow-drag.js +19 -0
  52. package/dist/typings/workflow-drag.js.map +1 -0
  53. package/dist/typings/workflow-edge.d.mts +15 -0
  54. package/dist/typings/workflow-edge.d.ts +15 -0
  55. package/dist/typings/workflow-edge.js +19 -0
  56. package/dist/typings/workflow-edge.js.map +1 -0
  57. package/dist/typings/workflow-json.d.mts +8 -0
  58. package/dist/typings/workflow-json.d.ts +8 -0
  59. package/dist/typings/workflow-json.js +40 -0
  60. package/dist/typings/workflow-json.js.map +1 -0
  61. package/dist/typings/workflow-line.d.mts +8 -0
  62. package/dist/typings/workflow-line.d.ts +8 -0
  63. package/dist/typings/workflow-line.js +47 -0
  64. package/dist/typings/workflow-line.js.map +1 -0
  65. package/dist/typings/workflow-node.d.mts +8 -0
  66. package/dist/typings/workflow-node.d.ts +8 -0
  67. package/dist/typings/workflow-node.js +19 -0
  68. package/dist/typings/workflow-node.js.map +1 -0
  69. package/dist/typings/workflow-operation.d.mts +29 -0
  70. package/dist/typings/workflow-operation.d.ts +29 -0
  71. package/dist/typings/workflow-operation.js +31 -0
  72. package/dist/typings/workflow-operation.js.map +1 -0
  73. package/dist/typings/workflow-registry.d.mts +30 -0
  74. package/dist/typings/workflow-registry.d.ts +30 -0
  75. package/dist/typings/workflow-registry.js +19 -0
  76. package/dist/typings/workflow-registry.js.map +1 -0
  77. package/dist/typings/workflow-sub-canvas.d.mts +2 -0
  78. package/dist/typings/workflow-sub-canvas.d.ts +2 -0
  79. package/dist/typings/workflow-sub-canvas.js +19 -0
  80. package/dist/typings/workflow-sub-canvas.js.map +1 -0
  81. package/dist/workflow-line-entity-B2J3fUO1.d.ts +790 -0
  82. package/dist/workflow-line-entity-CW8YIX-0.d.mts +790 -0
  83. package/dist/workflow-sub-canvas-IQzlYvPD.d.mts +25 -0
  84. package/dist/workflow-sub-canvas-IQzlYvPD.d.ts +25 -0
  85. package/package.json +77 -0
@@ -0,0 +1,3471 @@
1
+ import {
2
+ URLParams
3
+ } from "./chunk-IKQUOAWQ.js";
4
+ import "./chunk-KNYZRMIO.js";
5
+ import "./chunk-NU6G5HF4.js";
6
+ import "./chunk-TQLT57GW.js";
7
+ import "./chunk-CGOMTQ3G.js";
8
+ import {
9
+ WorkflowContentChangeType
10
+ } from "./chunk-242F2JCI.js";
11
+ import {
12
+ LineColors,
13
+ LineType
14
+ } from "./chunk-CTGO4RKX.js";
15
+ import "./chunk-DDJTYHXN.js";
16
+ import {
17
+ WorkflowOperationBaseService
18
+ } from "./chunk-O4WKIIW2.js";
19
+ import {
20
+ __decorateClass
21
+ } from "./chunk-EUXUH3YW.js";
22
+
23
+ // src/workflow-commands.ts
24
+ var WorkflowCommands = /* @__PURE__ */ ((WorkflowCommands2) => {
25
+ WorkflowCommands2["DELETE_NODES"] = "DELETE_NODES";
26
+ WorkflowCommands2["COPY_NODES"] = "COPY_NODES";
27
+ WorkflowCommands2["PASTE_NODES"] = "PASTE_NODES";
28
+ WorkflowCommands2["ZOOM_IN"] = "ZOOM_IN";
29
+ WorkflowCommands2["ZOOM_OUT"] = "ZOOM_OUT";
30
+ WorkflowCommands2["UNDO"] = "UNDO";
31
+ WorkflowCommands2["REDO"] = "REDO";
32
+ return WorkflowCommands2;
33
+ })(WorkflowCommands || {});
34
+
35
+ // src/hooks/index.ts
36
+ import {
37
+ useConfigEntity,
38
+ useService as useService3,
39
+ usePlayground as usePlayground2,
40
+ useListenEvents as useListenEvents2,
41
+ usePlaygroundContainer,
42
+ usePlaygroundContext,
43
+ useEntities,
44
+ useEntityFromContext as useEntityFromContext3,
45
+ useEntityDataFromContext,
46
+ useRefresh as useRefresh2,
47
+ usePlaygroundLatest
48
+ } from "@flowgram.ai/core";
49
+
50
+ // src/hooks/use-node-render.tsx
51
+ import { useCallback, useEffect as useEffect2, useRef, useState, useContext, useMemo } from "react";
52
+ import { useObserve } from "@flowgram.ai/reactive";
53
+ import { getNodeForm } from "@flowgram.ai/node";
54
+ import { FlowNodeRenderData as FlowNodeRenderData3 } from "@flowgram.ai/document";
55
+ import {
56
+ MouseTouchEvent as MouseTouchEvent2,
57
+ PlaygroundEntityContext,
58
+ useListenEvents,
59
+ useService
60
+ } from "@flowgram.ai/core";
61
+
62
+ // src/service/workflow-select-service.ts
63
+ import { inject, injectable } from "inversify";
64
+ import {
65
+ Playground,
66
+ SelectionService,
67
+ TransformData as TransformData4
68
+ } from "@flowgram.ai/core";
69
+ import { Rectangle as Rectangle6, SizeSchema } from "@flowgram.ai/utils";
70
+
71
+ // src/utils/index.ts
72
+ import { bindConfigEntity } from "@flowgram.ai/core";
73
+ import { delay } from "@flowgram.ai/utils";
74
+
75
+ // src/utils/nanoid.ts
76
+ import { nanoid as nanoidOrigin } from "nanoid";
77
+ function nanoid(n) {
78
+ return nanoidOrigin(n);
79
+ }
80
+
81
+ // src/utils/compose.ts
82
+ import { compose, composeAsync } from "@flowgram.ai/utils";
83
+
84
+ // src/utils/fit-view.ts
85
+ import { TransformData } from "@flowgram.ai/core";
86
+ import { Rectangle } from "@flowgram.ai/utils";
87
+ var fitView = (doc, playgroundConfig, easing = true) => {
88
+ const bounds = Rectangle.enlarge(
89
+ doc.getAllNodes().map((node) => node.getData(TransformData).bounds)
90
+ );
91
+ return playgroundConfig.fitView(bounds, easing, 30);
92
+ };
93
+
94
+ // src/utils/get-anti-overlap-position.ts
95
+ import { TransformData as TransformData2 } from "@flowgram.ai/core";
96
+ function getAntiOverlapPosition(doc, position, containerNode) {
97
+ let { x, y } = position;
98
+ const nodes = containerNode ? containerNode.collapsedChildren : doc.getAllNodes();
99
+ const positions = nodes.map((n) => {
100
+ const transform = n.getData(TransformData2);
101
+ return { x: transform.position.x, y: transform.position.y };
102
+ }).sort((a, b) => a.y - b.y);
103
+ const minDistance = 3;
104
+ for (const pos of positions) {
105
+ const { x: posX, y: posY } = pos;
106
+ if (y - posY < -minDistance) {
107
+ break;
108
+ }
109
+ const deltaX = Math.abs(x - posX);
110
+ const deltaY = Math.abs(y - posY);
111
+ if (deltaX <= minDistance && deltaY <= minDistance) {
112
+ x += 30;
113
+ y += 30;
114
+ }
115
+ }
116
+ return { x, y };
117
+ }
118
+
119
+ // src/utils/statics.ts
120
+ import { Rectangle as Rectangle2 } from "@flowgram.ai/utils";
121
+ var getPortEntityId = (node, portType, portID = "") => `port_${portType}_${node.id}_${portID}`;
122
+ var WORKFLOW_LINE_ENTITY = "WorkflowLineEntity";
123
+ function domReactToBounds(react) {
124
+ return new Rectangle2(react.x, react.y, react.width, react.height);
125
+ }
126
+
127
+ // src/entities/workflow-node-entity.ts
128
+ import { FlowNodeEntity } from "@flowgram.ai/document";
129
+ var WorkflowNodeEntity = FlowNodeEntity;
130
+
131
+ // src/entities/workflow-line-entity.ts
132
+ import { isEqual as isEqual2 } from "lodash-es";
133
+ import { domUtils } from "@flowgram.ai/utils";
134
+ import { Entity as Entity2 } from "@flowgram.ai/core";
135
+
136
+ // src/entity-datas/workflow-node-ports-data.ts
137
+ import { isEqual } from "lodash-es";
138
+ import { FlowNodeRenderData } from "@flowgram.ai/document";
139
+ import { EntityData, SizeData } from "@flowgram.ai/core";
140
+
141
+ // src/entities/workflow-port-entity.ts
142
+ import { Rectangle as Rectangle3, Emitter } from "@flowgram.ai/utils";
143
+ import { FlowNodeTransformData } from "@flowgram.ai/document";
144
+ import {
145
+ Entity,
146
+ PlaygroundConfigEntity,
147
+ TransformData as TransformData3
148
+ } from "@flowgram.ai/core";
149
+ var PORT_SIZE = 24;
150
+ var WorkflowPortEntity = class extends Entity {
151
+ // relativePosition
152
+ constructor(opts) {
153
+ super(opts);
154
+ this.portID = "";
155
+ this._disabled = false;
156
+ this._hasError = false;
157
+ this._onErrorChangedEmitter = new Emitter();
158
+ this.onErrorChanged = this._onErrorChangedEmitter.event;
159
+ this.portID = opts.portID || "";
160
+ this.portType = opts.type;
161
+ this._disabled = opts.disabled ?? false;
162
+ this.node = opts.node;
163
+ this.updateTargetElement(opts.targetElement);
164
+ this.toDispose.push(this.node.getData(TransformData3).onDataChange(() => this.fireChange()));
165
+ this.toDispose.push(this.node.onDispose(this.dispose.bind(this)));
166
+ }
167
+ static getPortEntityId(node, portType, portID = "") {
168
+ return getPortEntityId(node, portType, portID);
169
+ }
170
+ // 获取连线是否为错误态
171
+ get hasError() {
172
+ return this._hasError;
173
+ }
174
+ // 设置连线的错误态,外部应使用 validate 进行更新
175
+ set hasError(hasError) {
176
+ this._hasError = hasError;
177
+ this._onErrorChangedEmitter.fire();
178
+ }
179
+ validate() {
180
+ const anyLineHasError = this.allLines.some((line) => {
181
+ if (line.disposed || line.isHidden) {
182
+ return false;
183
+ }
184
+ line.validateSelf();
185
+ return line.hasError;
186
+ });
187
+ const isPortHasError = this.node.document.isErrorPort(this);
188
+ this.hasError = anyLineHasError || isPortHasError;
189
+ }
190
+ isErrorPort() {
191
+ return this.node.document.isErrorPort(this);
192
+ }
193
+ get point() {
194
+ const { targetElement } = this;
195
+ const { bounds } = this.node.getData(FlowNodeTransformData);
196
+ if (targetElement) {
197
+ const pos = domReactToBounds(targetElement.getBoundingClientRect()).center;
198
+ return this.entityManager.getEntity(PlaygroundConfigEntity).getPosFromMouseEvent({
199
+ clientX: pos.x,
200
+ clientY: pos.y
201
+ });
202
+ }
203
+ if (this.portType === "input") {
204
+ return bounds.leftCenter;
205
+ }
206
+ return bounds.rightCenter;
207
+ }
208
+ /**
209
+ * 点的区域
210
+ */
211
+ get bounds() {
212
+ const { point } = this;
213
+ const halfSize = PORT_SIZE / 2;
214
+ return new Rectangle3(point.x - halfSize, point.y - halfSize, PORT_SIZE, PORT_SIZE);
215
+ }
216
+ isHovered(x, y) {
217
+ return this.bounds.contains(x, y);
218
+ }
219
+ /**
220
+ * 相对节点左上角的位置
221
+ */
222
+ get relativePosition() {
223
+ const { point } = this;
224
+ const { bounds } = this.node.getData(FlowNodeTransformData);
225
+ return {
226
+ x: point.x - bounds.x,
227
+ y: point.y - bounds.y
228
+ };
229
+ }
230
+ updateTargetElement(el) {
231
+ if (el !== this.targetElement) {
232
+ this.targetElement = el;
233
+ this.fireChange();
234
+ }
235
+ }
236
+ /**
237
+ * 是否被禁用
238
+ */
239
+ get disabled() {
240
+ const document2 = this.node.document;
241
+ if (typeof document2.options.isDisabledPort === "function") {
242
+ return document2.options.isDisabledPort(this);
243
+ }
244
+ if (this._disabled) {
245
+ return true;
246
+ }
247
+ const meta = this.node.getNodeMeta();
248
+ if (this.portType === "input") {
249
+ return !!meta.inputDisable;
250
+ }
251
+ return !!meta.outputDisable;
252
+ }
253
+ /**
254
+ * 当前点位上连接的线条
255
+ * @deprecated use `availableLines` instead
256
+ */
257
+ get lines() {
258
+ return this.allLines.filter((line) => !line.isDrawing);
259
+ }
260
+ /**
261
+ * 当前有效的线条,不包含正在画的线条和隐藏的线条(这个出现在线条重连会先把原来的线条隐藏)
262
+ */
263
+ get availableLines() {
264
+ return this.allLines.filter((line) => !line.isDrawing && !line.isHidden);
265
+ }
266
+ /**
267
+ * 当前点位上连接的线条(包含 isDrawing === true 的线条)
268
+ */
269
+ get allLines() {
270
+ const lines = [];
271
+ const allLines = this.entityManager.getEntities({
272
+ type: WORKFLOW_LINE_ENTITY
273
+ });
274
+ allLines.forEach((line) => {
275
+ if (line.toPort === this || line.fromPort === this) {
276
+ lines.push(line);
277
+ }
278
+ });
279
+ return lines;
280
+ }
281
+ dispose() {
282
+ this.lines.forEach((l) => l.dispose());
283
+ super.dispose();
284
+ }
285
+ };
286
+ WorkflowPortEntity.type = "WorkflowPortEntity";
287
+
288
+ // src/entity-datas/workflow-node-ports-data.ts
289
+ var WorkflowNodePortsData = class extends EntityData {
290
+ constructor(entity) {
291
+ super(entity);
292
+ /** 静态的 ports 数据 */
293
+ this._staticPorts = [];
294
+ /** 存储 port 实体的 id,用于判断 port 是否存在 */
295
+ this._portIDSet = /* @__PURE__ */ new Set();
296
+ this.entity = entity;
297
+ const meta = entity.getNodeMeta();
298
+ const defaultPorts = meta.useDynamicPort ? [] : [{ type: "input" }, { type: "output" }];
299
+ this._staticPorts = meta.defaultPorts?.slice() || defaultPorts;
300
+ this.updatePorts(this._staticPorts);
301
+ if (meta.useDynamicPort) {
302
+ this.toDispose.push(
303
+ // 只需要监听节点的大小,因为算的是相对位置
304
+ entity.getData(SizeData).onDataChange(() => {
305
+ if (entity.getData(SizeData).width && entity.getData(SizeData).height) {
306
+ this.updateDynamicPorts();
307
+ }
308
+ })
309
+ );
310
+ }
311
+ this.onDispose(() => {
312
+ this.allPorts.forEach((port) => port.dispose());
313
+ });
314
+ }
315
+ getDefaultData() {
316
+ return {};
317
+ }
318
+ /**
319
+ * 更新静态的 ports 数据
320
+ */
321
+ updateStaticPorts(ports) {
322
+ const meta = this.entity.getNodeMeta();
323
+ this._staticPorts = ports;
324
+ if (meta.useDynamicPort) {
325
+ this.updateDynamicPorts();
326
+ } else {
327
+ this.updatePorts(this._staticPorts);
328
+ }
329
+ }
330
+ /**
331
+ * 动态计算点位,通过 dom 的 data-port-key
332
+ */
333
+ updateDynamicPorts() {
334
+ const domNode = this.entity.getData(FlowNodeRenderData).node;
335
+ const elements = domNode.querySelectorAll("[data-port-id]");
336
+ const staticPorts = this._staticPorts;
337
+ const dynamicPorts = [];
338
+ if (elements.length > 0) {
339
+ dynamicPorts.push(
340
+ ...Array.from(elements).map((element) => ({
341
+ portID: element.getAttribute("data-port-id"),
342
+ type: element.getAttribute("data-port-type"),
343
+ targetElement: element
344
+ }))
345
+ );
346
+ }
347
+ this.updatePorts(staticPorts.concat(dynamicPorts));
348
+ }
349
+ /**
350
+ * 根据 key 获取 port 实体
351
+ */
352
+ getPortEntityByKey(portType, portKey) {
353
+ const entity = this.getOrCreatePortEntity({
354
+ type: portType,
355
+ portID: portKey
356
+ });
357
+ return entity;
358
+ }
359
+ /**
360
+ * 更新 ports 数据
361
+ */
362
+ updatePorts(ports) {
363
+ if (!isEqual(this._prePorts, ports)) {
364
+ const portKeys = ports.map((port) => this.getPortId(port.type, port.portID));
365
+ this._portIDSet.forEach((portId) => {
366
+ if (!portKeys.includes(portId)) {
367
+ this.getPortEntity(portId)?.dispose();
368
+ }
369
+ });
370
+ ports.forEach((port) => this.updatePortEntity(port));
371
+ this._prePorts = ports;
372
+ this.fireChange();
373
+ }
374
+ this.allPorts.forEach((port) => {
375
+ port.allLines.forEach((line) => {
376
+ line.validate();
377
+ });
378
+ port.validate();
379
+ });
380
+ }
381
+ /**
382
+ * 获取所有 port entities
383
+ */
384
+ get allPorts() {
385
+ return Array.from(this._portIDSet).map((portId) => this.getPortEntity(portId)).filter(Boolean);
386
+ }
387
+ /**
388
+ * 获取输入点位
389
+ */
390
+ get inputPorts() {
391
+ return this.allPorts.filter((port) => port.portType === "input");
392
+ }
393
+ /**
394
+ * 获取输出点位
395
+ */
396
+ get outputPorts() {
397
+ return this.allPorts.filter((port) => port.portType === "output");
398
+ }
399
+ /**
400
+ * 获取输入点位置
401
+ */
402
+ get inputPoints() {
403
+ return this.inputPorts.map((port) => port.point);
404
+ }
405
+ /**
406
+ * 获取输出点位置
407
+ */
408
+ get outputPoints() {
409
+ return this.inputPorts.map((port) => port.point);
410
+ }
411
+ /**
412
+ * 根据 key 获取 输入点位置
413
+ */
414
+ getInputPoint(key) {
415
+ return this.getPortEntityByKey("input", key).point;
416
+ }
417
+ /**
418
+ * 根据 key 获取输出点位置
419
+ */
420
+ getOutputPoint(key) {
421
+ return this.getPortEntityByKey("output", key).point;
422
+ }
423
+ /**
424
+ * 获取 port 实体
425
+ */
426
+ getPortEntity(portId) {
427
+ if (!this._portIDSet.has(portId)) {
428
+ return void 0;
429
+ }
430
+ return this.entity.entityManager.getEntityById(portId);
431
+ }
432
+ /**
433
+ * 拼接 port 实体的 id
434
+ */
435
+ getPortId(portType, portKey = "") {
436
+ return getPortEntityId(this.entity, portType, portKey);
437
+ }
438
+ /**
439
+ * 创建 port 实体
440
+ */
441
+ createPortEntity(portInfo) {
442
+ const id = this.getPortId(portInfo.type, portInfo.portID);
443
+ let portEntity = this.entity.entityManager.getEntityById(id);
444
+ if (!portEntity) {
445
+ portEntity = this.entity.entityManager.createEntity(WorkflowPortEntity, {
446
+ id,
447
+ node: this.entity,
448
+ ...portInfo
449
+ });
450
+ }
451
+ portEntity.onDispose(() => {
452
+ this._portIDSet.delete(id);
453
+ });
454
+ this._portIDSet.add(id);
455
+ return portEntity;
456
+ }
457
+ /**
458
+ * 获取或创建 port 实体
459
+ */
460
+ getOrCreatePortEntity(portInfo) {
461
+ const id = this.getPortId(portInfo.type, portInfo.portID);
462
+ return this.getPortEntity(id) ?? this.createPortEntity(portInfo);
463
+ }
464
+ /**
465
+ * 更新 port 实体
466
+ */
467
+ updatePortEntity(portInfo) {
468
+ const portEntity = this.getOrCreatePortEntity(portInfo);
469
+ if (portInfo.targetElement) {
470
+ portEntity.updateTargetElement(portInfo.targetElement);
471
+ }
472
+ return portEntity;
473
+ }
474
+ };
475
+ WorkflowNodePortsData.type = "WorkflowNodePortsData";
476
+
477
+ // src/entity-datas/workflow-node-lines-data.ts
478
+ import { Disposable } from "@flowgram.ai/utils";
479
+ import { EntityData as EntityData2 } from "@flowgram.ai/core";
480
+ var _WorkflowNodeLinesData = class _WorkflowNodeLinesData extends EntityData2 {
481
+ getDefaultData() {
482
+ return {
483
+ inputLines: [],
484
+ outputLines: []
485
+ };
486
+ }
487
+ constructor(entity) {
488
+ super(entity);
489
+ this.entity = entity;
490
+ this.entity.preDispose.push(
491
+ Disposable.create(() => {
492
+ this.inputLines.slice().forEach((line) => line.dispose());
493
+ this.outputLines.slice().forEach((line) => line.dispose());
494
+ })
495
+ );
496
+ }
497
+ /**
498
+ * 输入线条
499
+ */
500
+ get inputLines() {
501
+ return this.data.inputLines;
502
+ }
503
+ /**
504
+ * 输出线条
505
+ */
506
+ get outputLines() {
507
+ return this.data.outputLines;
508
+ }
509
+ /**
510
+ * 输入节点
511
+ */
512
+ get inputNodes() {
513
+ return this.inputLines.map((l) => l.from).filter(Boolean);
514
+ }
515
+ /**
516
+ * 所有输入节点
517
+ */
518
+ get allInputNodes() {
519
+ const nodeSet = /* @__PURE__ */ new Set();
520
+ const handleNode = (node) => {
521
+ if (nodeSet.has(node)) {
522
+ return;
523
+ }
524
+ nodeSet.add(node);
525
+ const { inputNodes } = node.getData(_WorkflowNodeLinesData);
526
+ if (!inputNodes || !inputNodes.length) {
527
+ return;
528
+ }
529
+ inputNodes.forEach((inputNode) => {
530
+ if (inputNode?.parent === node || node?.parent === inputNode) {
531
+ return;
532
+ }
533
+ handleNode(inputNode);
534
+ });
535
+ };
536
+ handleNode(this.entity);
537
+ nodeSet.delete(this.entity);
538
+ return Array.from(nodeSet);
539
+ }
540
+ /**
541
+ * 输出节点
542
+ */
543
+ get outputNodes() {
544
+ return this.outputLines.map((l) => l.to).filter(Boolean);
545
+ }
546
+ /**
547
+ * 输入输出节点
548
+ */
549
+ get allOutputNodes() {
550
+ const nodeSet = /* @__PURE__ */ new Set();
551
+ const handleNode = (node) => {
552
+ if (nodeSet.has(node)) {
553
+ return;
554
+ }
555
+ nodeSet.add(node);
556
+ const { outputNodes } = node.getData(_WorkflowNodeLinesData);
557
+ if (!outputNodes || !outputNodes.length) {
558
+ return;
559
+ }
560
+ outputNodes.forEach((outputNode) => {
561
+ if (outputNode?.parent === node || node?.parent === outputNode) {
562
+ return;
563
+ }
564
+ handleNode(outputNode);
565
+ });
566
+ };
567
+ handleNode(this.entity);
568
+ nodeSet.delete(this.entity);
569
+ return Array.from(nodeSet);
570
+ }
571
+ addLine(line) {
572
+ if (line.from === this.entity) {
573
+ this.outputLines.push(line);
574
+ } else {
575
+ this.inputLines.push(line);
576
+ }
577
+ this.fireChange();
578
+ }
579
+ removeLine(line) {
580
+ const { inputLines, outputLines } = this;
581
+ const inputIndex = inputLines.indexOf(line);
582
+ const outputIndex = outputLines.indexOf(line);
583
+ if (inputIndex !== -1) {
584
+ inputLines.splice(inputIndex, 1);
585
+ this.fireChange();
586
+ }
587
+ if (outputIndex !== -1) {
588
+ outputLines.splice(outputIndex, 1);
589
+ this.fireChange();
590
+ }
591
+ }
592
+ };
593
+ _WorkflowNodeLinesData.type = "WorkflowNodeLinesData";
594
+ var WorkflowNodeLinesData = _WorkflowNodeLinesData;
595
+
596
+ // src/entity-datas/workflow-line-render-data.ts
597
+ import { Rectangle as Rectangle4 } from "@flowgram.ai/utils";
598
+ import { EntityData as EntityData3 } from "@flowgram.ai/core";
599
+ var WorkflowLineRenderData = class extends EntityData3 {
600
+ constructor(entity) {
601
+ super(entity);
602
+ this.syncContributions();
603
+ }
604
+ getDefaultData() {
605
+ return {
606
+ version: "",
607
+ contributions: /* @__PURE__ */ new Map(),
608
+ position: {
609
+ from: { x: 0, y: 0 },
610
+ to: { x: 0, y: 0 }
611
+ }
612
+ };
613
+ }
614
+ get renderVersion() {
615
+ return this.data.version;
616
+ }
617
+ get position() {
618
+ return this.data.position;
619
+ }
620
+ get path() {
621
+ return this.currentLine?.path ?? "";
622
+ }
623
+ calcDistance(pos) {
624
+ return this.currentLine?.calcDistance(pos) ?? Number.MAX_SAFE_INTEGER;
625
+ }
626
+ get bounds() {
627
+ return this.currentLine?.bounds ?? new Rectangle4();
628
+ }
629
+ /**
630
+ * 更新数据
631
+ * WARNING: 这个方法,必须在 requestAnimationFrame / useLayoutEffect 中调用,否则会引起浏览器强制重排
632
+ */
633
+ update() {
634
+ this.syncContributions();
635
+ const oldVersion = this.data.version;
636
+ this.updatePosition();
637
+ const newVersion = this.data.version;
638
+ if (oldVersion === newVersion) {
639
+ return;
640
+ }
641
+ this.data.version = newVersion;
642
+ this.currentLine?.update({
643
+ fromPos: this.data.position.from,
644
+ toPos: this.data.position.to
645
+ });
646
+ }
647
+ get lineType() {
648
+ return this.entity.renderType ?? this.entity.linesManager.lineType;
649
+ }
650
+ /**
651
+ * 更新版本
652
+ * WARNING: 这个方法,必须在 requestAnimationFrame / useLayoutEffect 中调用,否则会引起浏览器强制重排
653
+ */
654
+ updatePosition() {
655
+ this.data.position.from = this.entity.from.getData(WorkflowNodePortsData).getOutputPoint(this.entity.info.fromPort);
656
+ this.data.position.to = this.entity.info.drawingTo ?? this.entity.to?.getData(WorkflowNodePortsData)?.getInputPoint(this.entity.info.toPort) ?? {
657
+ x: this.data.position.from.x,
658
+ y: this.data.position.from.y
659
+ };
660
+ this.data.version = [
661
+ this.lineType,
662
+ this.data.position.from.x,
663
+ this.data.position.from.y,
664
+ this.data.position.to.x,
665
+ this.data.position.to.y
666
+ ].join("-");
667
+ }
668
+ get currentLine() {
669
+ return this.data.contributions.get(this.lineType);
670
+ }
671
+ syncContributions() {
672
+ if (this.entity.linesManager.contributionFactories.length === this.data.contributions.size) {
673
+ return;
674
+ }
675
+ this.entity.linesManager.contributionFactories.forEach((factory) => {
676
+ this.registerContribution(factory);
677
+ });
678
+ }
679
+ registerContribution(contributionFactory) {
680
+ if (this.data.contributions.has(contributionFactory.type)) {
681
+ return;
682
+ }
683
+ const contribution = new contributionFactory(this.entity);
684
+ this.data.contributions.set(contributionFactory.type, contribution);
685
+ }
686
+ };
687
+ WorkflowLineRenderData.type = "WorkflowLineRenderData";
688
+
689
+ // src/entities/workflow-line-entity.ts
690
+ var LINE_HOVER_DISTANCE = 8;
691
+ var POINT_RADIUS = 10;
692
+ var _WorkflowLineEntity = class _WorkflowLineEntity extends Entity2 {
693
+ constructor(opts) {
694
+ super(opts);
695
+ this._processing = false;
696
+ this._hasError = false;
697
+ this.stackIndex = 0;
698
+ /**
699
+ * 线条数据
700
+ */
701
+ this.info = {
702
+ from: ""
703
+ };
704
+ this.document = opts.document;
705
+ this.linesManager = opts.linesManager;
706
+ this.initInfo({
707
+ from: opts.from,
708
+ to: opts.to,
709
+ drawingTo: opts.drawingTo,
710
+ fromPort: opts.fromPort,
711
+ toPort: opts.toPort
712
+ });
713
+ if (opts.drawingTo) {
714
+ this.isDrawing = true;
715
+ }
716
+ }
717
+ /**
718
+ * 转成线条 id
719
+ * @param info
720
+ */
721
+ static portInfoToLineId(info) {
722
+ const { from, to, fromPort, toPort } = info;
723
+ return `${from}_${fromPort || ""}-${to || ""}_${toPort || ""}`;
724
+ }
725
+ /**
726
+ * 获取线条的前置节点
727
+ */
728
+ get from() {
729
+ return this._from;
730
+ }
731
+ /**
732
+ * 获取线条的后置节点
733
+ */
734
+ get to() {
735
+ return this._to;
736
+ }
737
+ get isHidden() {
738
+ return this.highlightColor === this.linesManager.lineColor.hidden;
739
+ }
740
+ get inContainer() {
741
+ const nodeInContainer = (node) => !!node?.parent && node.parent.flowNodeType !== "root";
742
+ return nodeInContainer(this.from) || nodeInContainer(this.to);
743
+ }
744
+ /**
745
+ * 获取是否 testrun processing
746
+ */
747
+ get processing() {
748
+ return this._processing;
749
+ }
750
+ /**
751
+ * 设置 testrun processing 状态
752
+ */
753
+ set processing(status) {
754
+ if (this._processing !== status) {
755
+ this._processing = status;
756
+ this.fireChange();
757
+ }
758
+ }
759
+ // 获取连线是否为错误态
760
+ get hasError() {
761
+ return this._hasError;
762
+ }
763
+ // 设置连线的错误态
764
+ set hasError(hasError) {
765
+ if (this._hasError !== hasError) {
766
+ this._hasError = hasError;
767
+ this.fireChange();
768
+ }
769
+ if (this._node) {
770
+ this._node.dataset.hasError = this.hasError ? "true" : "false";
771
+ }
772
+ }
773
+ /**
774
+ * 设置线条的后置节点
775
+ */
776
+ setToPort(toPort) {
777
+ if (!this.isDrawing) {
778
+ throw new Error("[setToPort] only support drawing line.");
779
+ }
780
+ if (this.toPort === toPort) {
781
+ return;
782
+ }
783
+ if (toPort && toPort.portType === "input" && this.linesManager.canAddLine(this.fromPort, toPort, true)) {
784
+ const { node, portID } = toPort;
785
+ this._to = node;
786
+ this.info.drawingTo = void 0;
787
+ this.info.isDefaultLine = false;
788
+ this.info.to = node.id;
789
+ this.info.toPort = portID;
790
+ } else {
791
+ this._to = void 0;
792
+ this.info.to = void 0;
793
+ this.info.toPort = "";
794
+ }
795
+ this.fireChange();
796
+ }
797
+ /**
798
+ * 设置线条画线时的目标位置
799
+ */
800
+ set drawingTo(pos) {
801
+ const oldDrawingTo = this.info.drawingTo;
802
+ if (!pos) {
803
+ this.info.drawingTo = void 0;
804
+ this.fireChange();
805
+ return;
806
+ }
807
+ if (!oldDrawingTo || pos.x !== oldDrawingTo.x || pos.y !== oldDrawingTo.y) {
808
+ this.info.to = void 0;
809
+ this.info.isDefaultLine = false;
810
+ this.info.drawingTo = pos;
811
+ this.fireChange();
812
+ }
813
+ }
814
+ /**
815
+ * 获取线条正在画线的位置
816
+ */
817
+ get drawingTo() {
818
+ return this.info.drawingTo;
819
+ }
820
+ get highlightColor() {
821
+ return this.info.highlightColor || "";
822
+ }
823
+ set highlightColor(color) {
824
+ if (this.info.highlightColor !== color) {
825
+ this.info.highlightColor = color;
826
+ this.fireChange();
827
+ }
828
+ }
829
+ /**
830
+ * 获取线条的边框位置大小
831
+ */
832
+ get bounds() {
833
+ return this.getData(WorkflowLineRenderData).bounds;
834
+ }
835
+ /**
836
+ * 获取点和线最接近的距离
837
+ */
838
+ getHoverDist(pos) {
839
+ return this.getData(WorkflowLineRenderData).calcDistance(pos);
840
+ }
841
+ get fromPort() {
842
+ return this.from.getData(WorkflowNodePortsData).getPortEntityByKey("output", this.info.fromPort);
843
+ }
844
+ get toPort() {
845
+ if (!this.to) {
846
+ return void 0;
847
+ }
848
+ return this.to.getData(WorkflowNodePortsData).getPortEntityByKey("input", this.info.toPort);
849
+ }
850
+ /**
851
+ * 获取线条真实的输入输出节点坐标
852
+ */
853
+ get position() {
854
+ return this.getData(WorkflowLineRenderData).position;
855
+ }
856
+ /** 是否反转箭头 */
857
+ get reverse() {
858
+ return this.linesManager.isReverseLine(this);
859
+ }
860
+ /** 是否隐藏箭头 */
861
+ get hideArrow() {
862
+ return this.linesManager.isHideArrowLine(this);
863
+ }
864
+ /** 是否流动 */
865
+ get flowing() {
866
+ return this.linesManager.isFlowingLine(this);
867
+ }
868
+ /** 是否禁用 */
869
+ get disabled() {
870
+ return this.linesManager.isDisabledLine(this);
871
+ }
872
+ /** 是否竖向 */
873
+ get vertical() {
874
+ return this.linesManager.isVerticalLine(this);
875
+ }
876
+ /** 获取线条渲染器类型 */
877
+ get renderType() {
878
+ return this.linesManager.setLineRenderType(this);
879
+ }
880
+ /** 获取线条样式 */
881
+ get className() {
882
+ return this.linesManager.setLineClassName(this) ?? "";
883
+ }
884
+ get color() {
885
+ return this.linesManager.getLineColor(this);
886
+ }
887
+ /**
888
+ * 初始化线条
889
+ * @param info 线条信息
890
+ */
891
+ initInfo(info) {
892
+ if (!isEqual2(info, this.info)) {
893
+ this.info = info;
894
+ this._from = this.document.getNode(info.from);
895
+ this._to = info.to ? this.document.getNode(info.to) : void 0;
896
+ this.fireChange();
897
+ }
898
+ }
899
+ // 校验连线是否为错误态
900
+ validate() {
901
+ const { fromPort, toPort } = this;
902
+ this.validateSelf();
903
+ fromPort?.validate();
904
+ toPort?.validate();
905
+ }
906
+ validateSelf() {
907
+ const { fromPort, toPort } = this;
908
+ if (fromPort) {
909
+ this.hasError = this.linesManager.isErrorLine(fromPort, toPort);
910
+ }
911
+ }
912
+ is(line) {
913
+ if (line instanceof _WorkflowLineEntity) {
914
+ return this === line;
915
+ }
916
+ return _WorkflowLineEntity.portInfoToLineId(line) === this.id;
917
+ }
918
+ canRemove(newLineInfo) {
919
+ return this.linesManager.canRemove(this, newLineInfo);
920
+ }
921
+ get node() {
922
+ if (this._node) return this._node;
923
+ this._node = domUtils.createDivWithClass("gedit-flow-activity-line");
924
+ this._node.dataset.testid = "sdk.workflow.canvas.line";
925
+ this._node.dataset.lineId = this.id;
926
+ this._node.dataset.fromNodeId = this.from.id;
927
+ this._node.dataset.fromPortId = this.fromPort?.id ?? "";
928
+ this._node.dataset.toNodeId = this.to?.id ?? "";
929
+ this._node.dataset.toPortId = this.toPort?.id ?? "";
930
+ this._node.dataset.hasError = this.hasError ? "true" : "false";
931
+ return this._node;
932
+ }
933
+ toJSON() {
934
+ const json = {
935
+ sourceNodeID: this.info.from,
936
+ targetNodeID: this.info.to,
937
+ sourcePortID: this.info.fromPort,
938
+ targetPortID: this.info.toPort
939
+ };
940
+ if (!json.sourcePortID) {
941
+ delete json.sourcePortID;
942
+ }
943
+ if (!json.targetPortID) {
944
+ delete json.targetPortID;
945
+ }
946
+ return json;
947
+ }
948
+ /** 触发线条渲染 */
949
+ fireRender() {
950
+ this.fireChange();
951
+ }
952
+ };
953
+ _WorkflowLineEntity.type = WORKFLOW_LINE_ENTITY;
954
+ var WorkflowLineEntity = _WorkflowLineEntity;
955
+
956
+ // src/service/workflow-select-service.ts
957
+ var WorkflowSelectService = class {
958
+ get onSelectionChanged() {
959
+ return this.selectionService.onSelectionChanged;
960
+ }
961
+ get selection() {
962
+ return this.selectionService.selection;
963
+ }
964
+ set selection(entities) {
965
+ this.selectionService.selection = entities;
966
+ }
967
+ /**
968
+ * 当前激活的节点只能有一个
969
+ */
970
+ get activatedNode() {
971
+ const { selectedNodes } = this;
972
+ if (selectedNodes.length !== 1) {
973
+ return void 0;
974
+ }
975
+ return selectedNodes[0];
976
+ }
977
+ isSelected(id) {
978
+ return this.selectionService.selection.some((s) => s.id === id);
979
+ }
980
+ isActivated(id) {
981
+ return this.activatedNode?.id === id;
982
+ }
983
+ /**
984
+ * 选中的节点
985
+ */
986
+ get selectedNodes() {
987
+ return this.selectionService.selection.filter(
988
+ (n) => n instanceof WorkflowNodeEntity
989
+ );
990
+ }
991
+ /**
992
+ * 选中
993
+ * @param node
994
+ */
995
+ selectNode(node) {
996
+ this.selectionService.selection = [node];
997
+ }
998
+ toggleSelect(node) {
999
+ if (this.selectionService.selection.includes(node)) {
1000
+ this.selectionService.selection = this.selectionService.selection.filter((n) => n !== node);
1001
+ } else {
1002
+ this.selectionService.selection = this.selectionService.selection.concat(node);
1003
+ }
1004
+ }
1005
+ select(node) {
1006
+ this.selectionService.selection = [node];
1007
+ }
1008
+ clear() {
1009
+ this.selectionService.selection = [];
1010
+ }
1011
+ /**
1012
+ * 选中并滚动到节点
1013
+ * @param node
1014
+ */
1015
+ async selectNodeAndScrollToView(node, fitView2) {
1016
+ this.selectNodeAndFocus(node);
1017
+ const DELAY_TIME = 30;
1018
+ await delay(DELAY_TIME);
1019
+ const scrollConfig = {
1020
+ entities: [node]
1021
+ };
1022
+ if (fitView2) {
1023
+ const bounds = Rectangle6.enlarge([node.getData(TransformData4).bounds]).pad(
1024
+ 30,
1025
+ 30
1026
+ );
1027
+ const viewport = this.playground.config.getViewport(false);
1028
+ const zoom = SizeSchema.fixSize(bounds, viewport);
1029
+ scrollConfig.zoom = zoom;
1030
+ scrollConfig.scrollToCenter = true;
1031
+ scrollConfig.easing = true;
1032
+ }
1033
+ return this.playground.config.scrollToView(scrollConfig);
1034
+ }
1035
+ selectNodeAndFocus(node) {
1036
+ this.select(node);
1037
+ this.playground.node.focus();
1038
+ }
1039
+ };
1040
+ __decorateClass([
1041
+ inject(SelectionService)
1042
+ ], WorkflowSelectService.prototype, "selectionService", 2);
1043
+ __decorateClass([
1044
+ inject(Playground)
1045
+ ], WorkflowSelectService.prototype, "playground", 2);
1046
+ WorkflowSelectService = __decorateClass([
1047
+ injectable()
1048
+ ], WorkflowSelectService);
1049
+
1050
+ // src/service/workflow-hover-service.ts
1051
+ import { inject as inject2, injectable as injectable2 } from "inversify";
1052
+ import { Emitter as Emitter2 } from "@flowgram.ai/utils";
1053
+ import { EntityManager } from "@flowgram.ai/core";
1054
+ var WorkflowHoverService = class {
1055
+ constructor() {
1056
+ this.onHoveredChangeEmitter = new Emitter2();
1057
+ this.onUpdateHoverPositionEmitter = new Emitter2();
1058
+ this.onHoveredChange = this.onHoveredChangeEmitter.event;
1059
+ this.onUpdateHoverPosition = this.onUpdateHoverPositionEmitter.event;
1060
+ // 当前鼠标 hover 位置
1061
+ this.hoveredPos = { x: 0, y: 0 };
1062
+ /**
1063
+ * 当前 hovered 的 节点或者线条或者点
1064
+ * 1: nodeId / lineId (节点 / 线条)
1065
+ * 2: nodeId:portKey (节点连接点)
1066
+ */
1067
+ this.hoveredKey = "";
1068
+ }
1069
+ /**
1070
+ * 更新 hover 的内容
1071
+ * @param hoveredKey hovered key
1072
+ */
1073
+ updateHoveredKey(hoveredKey) {
1074
+ if (this.hoveredKey !== hoveredKey) {
1075
+ this.hoveredKey = hoveredKey;
1076
+ this.onHoveredChangeEmitter.fire(hoveredKey);
1077
+ }
1078
+ }
1079
+ updateHoverPosition(position, target) {
1080
+ this.hoveredPos = position;
1081
+ this.onUpdateHoverPositionEmitter.fire({
1082
+ position,
1083
+ target
1084
+ });
1085
+ }
1086
+ /**
1087
+ * 清空 hover 内容
1088
+ */
1089
+ clearHovered() {
1090
+ this.updateHoveredKey("");
1091
+ }
1092
+ /**
1093
+ * 判断是否 hover
1094
+ * @param nodeId hoveredKey
1095
+ * @returns 是否 hover
1096
+ */
1097
+ isHovered(nodeId) {
1098
+ return nodeId === this.hoveredKey;
1099
+ }
1100
+ isSomeHovered() {
1101
+ return !!this.hoveredKey;
1102
+ }
1103
+ /**
1104
+ * 获取被 hover 的节点或线条
1105
+ */
1106
+ get hoveredNode() {
1107
+ return this.entityManager.getEntityById(this.hoveredKey);
1108
+ }
1109
+ };
1110
+ __decorateClass([
1111
+ inject2(EntityManager)
1112
+ ], WorkflowHoverService.prototype, "entityManager", 2);
1113
+ WorkflowHoverService = __decorateClass([
1114
+ injectable2()
1115
+ ], WorkflowHoverService);
1116
+
1117
+ // src/service/workflow-drag-service.ts
1118
+ import { nanoid as nanoid3 } from "nanoid";
1119
+ import { inject as inject6, injectable as injectable6, postConstruct as postConstruct2 } from "inversify";
1120
+ import {
1121
+ domUtils as domUtils2,
1122
+ PromiseDeferred,
1123
+ Emitter as Emitter5,
1124
+ DisposableCollection as DisposableCollection2,
1125
+ Rectangle as Rectangle8,
1126
+ delay as delay2
1127
+ } from "@flowgram.ai/utils";
1128
+ import {
1129
+ FlowNodeTransformData as FlowNodeTransformData6,
1130
+ FlowOperationBaseService
1131
+ } from "@flowgram.ai/document";
1132
+ import { FlowNodeBaseType as FlowNodeBaseType2 } from "@flowgram.ai/document";
1133
+ import {
1134
+ CommandService,
1135
+ MouseTouchEvent,
1136
+ PlaygroundConfigEntity as PlaygroundConfigEntity5,
1137
+ PlaygroundDrag,
1138
+ TransformData as TransformData8
1139
+ } from "@flowgram.ai/core";
1140
+
1141
+ // src/workflow-lines-manager.ts
1142
+ import { last } from "lodash-es";
1143
+ import { inject as inject3, injectable as injectable3 } from "inversify";
1144
+ import { DisposableCollection, Emitter as Emitter3 } from "@flowgram.ai/utils";
1145
+ import { FlowNodeRenderData as FlowNodeRenderData2, FlowNodeTransformData as FlowNodeTransformData3 } from "@flowgram.ai/document";
1146
+ import { EntityManager as EntityManager2, PlaygroundConfigEntity as PlaygroundConfigEntity2 } from "@flowgram.ai/core";
1147
+
1148
+ // src/workflow-document-option.ts
1149
+ import { FlowNodeErrorData } from "@flowgram.ai/form-core";
1150
+ import { FlowNodeTransformData as FlowNodeTransformData2 } from "@flowgram.ai/document";
1151
+ import { TransformData as TransformData5 } from "@flowgram.ai/core";
1152
+
1153
+ // src/utils/flow-node-form-data.ts
1154
+ import { FlowNodeFormData } from "@flowgram.ai/form-core";
1155
+ function getFlowNodeFormData(node) {
1156
+ return node.getData(FlowNodeFormData);
1157
+ }
1158
+ function toFormJSON(node) {
1159
+ const formData = node.getData(FlowNodeFormData);
1160
+ if (!formData || !node.getNodeRegistry().formMeta) return void 0;
1161
+ return formData.toJSON();
1162
+ }
1163
+ function initFormDataFromJSON(node, json, isFirstCreate) {
1164
+ const formData = node.getData(FlowNodeFormData);
1165
+ const registry = node.getNodeRegistry();
1166
+ const { formMeta } = registry;
1167
+ if (formData && formMeta) {
1168
+ if (isFirstCreate) {
1169
+ formData.createForm(formMeta, json.data);
1170
+ formData.onDataChange(() => {
1171
+ node.document.fireContentChange({
1172
+ type: "NODE_DATA_CHANGE" /* NODE_DATA_CHANGE */,
1173
+ toJSON: () => formData.toJSON(),
1174
+ entity: node
1175
+ });
1176
+ });
1177
+ } else {
1178
+ formData.updateFormValues(json.data);
1179
+ }
1180
+ }
1181
+ }
1182
+
1183
+ // src/workflow-document-option.ts
1184
+ var WorkflowDocumentOptions = Symbol("WorkflowDocumentOptions");
1185
+ var WorkflowDocumentOptionsDefault = {
1186
+ cursors: {
1187
+ grab: 'url("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjEiIHZpZXdCb3g9IjAgMCAyMCAyMSIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0xMC40ODczIDIuNjIzNzhDOS45MDczMSAyLjYyMzc4IDkuNDM3MTMgMy4wOTM5NiA5LjQzNzEzIDMuNjczOTZWNS4xNDM3NkM5LjM5NDI4IDQuNDAyNzQgOC43Nzk3OCAzLjgxNTA0IDguMDI4MDIgMy44MTUwNEM3LjI0ODQ4IDMuODE1MDQgNi42MTY1MyA0LjQ0Njk5IDYuNjE2NTMgNS4yMjY1M1YxMS44Mjg5TDUuNjc0MTggMTEuMDA0OUM1LjE1NDg3IDEwLjU1MDkgNC40MDk1IDEwLjQ2MzYgMy43OTkzOCAxMC43ODU1TDMuNjk2OTQgMTAuODM5NkMzLjA2MjE3IDExLjE3NDUgMi45MjI2IDEyLjAyMjggMy40MTY2MiAxMi41NDM0TDcuMzM5NTkgMTYuNjc3NVYxNy4zMjU5QzcuMzM5NTkgMTcuNzg2MiA3LjcxMjY5IDE4LjE1OTMgOC4xNzI5MiAxOC4xNTkzSDEzLjgwODRDMTQuMjY4NyAxOC4xNTkzIDE0LjY0MTcgMTcuNzg2MiAxNC42NDE3IDE3LjMyNTlWMTYuNzkzNUMxNS44MDk0IDE1LjY0ODUgMTYuNDY3MyAxNC4wODE5IDE2LjQ2NzMgMTIuNDQ2NVYxMS40OTY3TDE2LjQ2NzEgNi42MzY4NUMxNi40NjcxIDUuOTU2MyAxNS45MTU0IDUuNDA0NjEgMTUuMjM0OCA1LjQwNDYxQzE0LjU1NDMgNS40MDQ2MSAxNC4wMDI2IDUuOTU2MyAxNC4wMDI2IDYuNjM2ODVMMTQuMDAyMSA1LjA0NzI4QzE0LjAwMjEgNC4zNjY3MyAxMy40NTA0IDMuODE1MDQgMTIuNzY5OCAzLjgxNTA0QzEyLjA4OTMgMy44MTUwNCAxMS41Mzc2IDQuMzY2NzMgMTEuNTM3NiA1LjA0NzI4TDExLjUzNzUgMy42NzM5NUMxMS41Mzc1IDMuMDkzOTYgMTEuMDY3MyAyLjYyMzc4IDEwLjQ4NzMgMi42MjM3OFoiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNMTAuNDg3NCAxLjM3NDAyQzExLjM2MTIgMS4zNzQwMiAxMi4xMjExIDEuODYxMTggMTIuNTEwNSAyLjU3ODY4QzEyLjU5NTggMi41Njk4MyAxMi42ODIzIDIuNTY1MjggMTIuNzcgMi41NjUyOEMxMy44Mjc4IDIuNTY1MjggMTQuNzMxMSAzLjIyNzAxIDE1LjA4ODUgNC4xNTkxMUMxNS4xMzcgNC4xNTYyOSAxNS4xODU4IDQuMTU0ODYgMTUuMjM1IDQuMTU0ODZDMTYuNjA1OSA0LjE1NDg2IDE3LjcxNzIgNS4yNjYxOSAxNy43MTcyIDYuNjM3MDlMMTcuNzE3NCAxMi40NDY3QzE3LjcxNzQgMTQuMjM1NSAxNy4wNjQ0IDE1Ljk1NTkgMTUuODkxOSAxNy4yOTA0VjE3LjMyNjJDMTUuODkxOSAxOC40NzY4IDE0Ljk1OTEgMTkuNDA5NSAxMy44MDg1IDE5LjQwOTVIOC4xNzMwNkM3LjAyMjQ3IDE5LjQwOTUgNi4wODk3MyAxOC40NzY4IDYuMDg5NzMgMTcuMzI2MlYxNy4xNzY0TDIuNTEwMDMgMTMuNDA0MUMxLjQ0NTk5IDEyLjI4MjggMS43NDY2IDEwLjQ1NTUgMy4xMTM3OSA5LjczNDI0TDMuMjE2MjQgOS42ODAxOUMzLjg5MTY4IDkuMzIzODMgNC42NjE4NSA5LjI1NDAxIDUuMzY2NjYgOS40NTE5OFY1LjIyNjc4QzUuMzY2NjYgMy43NTY4NyA2LjU1ODI2IDIuNTY1MjggOC4wMjgxNiAyLjU2NTI4QzguMTcyOTMgMi41NjUyOCA4LjMxNDk5IDIuNTc2ODQgOC40NTM0NyAyLjU5OTA3QzguODM5NDMgMS44NzA0MiA5LjYwNTQ2IDEuMzc0MDIgMTAuNDg3NCAxLjM3NDAyWk0xMi40NDc2IDMuODU3ODdWOS40NzY0NkMxMi40NDc2IDkuNzI4NTIgMTIuMjQzMyA5LjkzMjg1IDExLjk5MTMgOS45MzI4NUMxMS43MzkyIDkuOTMyODUgMTEuNTM0OSA5LjcyODUyIDExLjUzNDkgOS40NzY0NlYzLjc5NjU1QzExLjUzNDkgMy43Nzk1NiAxMS41MzU4IDMuNzYyNzcgMTEuNTM3NiAzLjc0NjI2VjMuNjc0MkMxMS41Mzc2IDMuNDMyODIgMTEuNDU2MiAzLjIxMDQ2IDExLjMxOTMgMy4wMzMwOUMxMS4xMjcyIDIuNzg0MjggMTAuODI2MSAyLjYyNDAyIDEwLjQ4NzQgMi42MjQwMkMxMC4xMjM4IDIuNjI0MDIgOS44MDMzMiAyLjgwODg2IDkuNjE0ODMgMy4wODk3QzkuNTAyNjkgMy4yNTY3OSA5LjQzNzI2IDMuNDU3ODUgOS40MzcyNiAzLjY3NDJWMy43ODU3M0M5LjQzNzM1IDMuNzg5MzMgOS40MzczOSAzLjc5Mjk0IDkuNDM3MzkgMy43OTY1NVY5LjkwMTdDOS40MzczOSAxMC4xNTM3IDkuMjMzMDYgMTAuMzU4MSA4Ljk4MTAxIDEwLjM1ODFDOC43Mjg5NSAxMC4zNTgxIDguNTI0NjIgMTAuMTUzNyA4LjUyNDYyIDkuOTAxN1YzLjkwNTA3QzguNDE3NzMgMy44NjQ5IDguMzA0NjggMy44MzczMiA4LjE4NzI2IDMuODI0MTVDOC4xMzUwNCAzLjgxODI5IDguMDgxOTUgMy44MTUyOCA4LjAyODE2IDMuODE1MjhDNy4yNDg2MSAzLjgxNTI4IDYuNjE2NjYgNC40NDcyMyA2LjYxNjY2IDUuMjI2NzhWMTEuODI5Mkw1LjY3NDMxIDExLjAwNTJDNS41Nzg2OCAxMC45MjE2IDUuNDc1MzcgMTAuODUwNCA1LjM2NjY2IDEwLjc5MTlDNC44ODUwNiAxMC41MzI5IDQuMjk3MjggMTAuNTIzMSAzLjc5OTUyIDEwLjc4NThMMy42OTcwNyAxMC44Mzk4QzMuMDYyMzEgMTEuMTc0NyAyLjkyMjczIDEyLjAyMzEgMy40MTY3NSAxMi41NDM3TDcuMzM5NzMgMTYuNjc3N1YxNy4zMjYyQzcuMzM5NzMgMTcuNzg2NCA3LjcxMjgyIDE4LjE1OTUgOC4xNzMwNiAxOC4xNTk1SDEzLjgwODVDMTQuMjY4OCAxOC4xNTk1IDE0LjY0MTkgMTcuNzg2NCAxNC42NDE5IDE3LjMyNjJWMTYuNzkzOEMxNS43Mzc5IDE1LjcxOSAxNi4zODQ3IDE0LjI3MjggMTYuNDYgMTIuNzQ3QzE2LjQ2NDEgMTIuNjY0MSAxNi40NjY1IDEyLjU4MDkgMTYuNDY3MiAxMi40OTc1TDE2LjQ2NzQgMTIuNDQ2N0wxNi40NjcyIDYuNjM3MDlDMTYuNDY3MiA1Ljk2MjMgMTUuOTI0OCA1LjQxNDE5IDE1LjI1MjIgNS40MDQ5N0wxNS4yMzUgNS40MDQ4NkMxNS4xMjQ2IDUuNDA0ODYgMTUuMDE3NyA1LjQxOTM2IDE0LjkxNTkgNS40NDY1NlY5LjYwMjI2QzE0LjkxNTkgOS44NTQzMSAxNC43MTE2IDEwLjA1ODYgMTQuNDU5NSAxMC4wNTg2QzE0LjIwNzUgMTAuMDU4NiAxNC4wMDMxIDkuODU0MzEgMTQuMDAzMSA5LjYwMjI2VjYuNjA1MTRDMTQuMDAyOSA2LjYxNTc2IDE0LjAwMjcgNi42MjY0MSAxNC4wMDI3IDYuNjM3MDlWOS4yNzcwNUwxNC4wMDIyIDUuMDQ3NTJDMTQuMDAyMiA0Ljg2OTEzIDEzLjk2NDMgNC42OTk2IDEzLjg5NjEgNC41NDY1M0MxMy43MDY0IDQuMTIwNzIgMTMuMjgyMiAzLjgyMjM1IDEyLjc4NzYgMy44MTU0MUwxMi43NyAzLjgxNTI4QzEyLjY1ODQgMy44MTUyOCAxMi41NTA0IDMuODMwMSAxMi40NDc2IDMuODU3ODdaIiBmaWxsPSIjMUQxQzIzIi8+Cjwvc3ZnPg=="), auto',
1188
+ grabbing: 'url("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjEiIHZpZXdCb3g9IjAgMCAyMCAyMSIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik02LjYxODE3IDUuNTk4NzVDNi42MTgxNyA0LjgxOTIgNy4yNTAxMiA0LjE4NzI2IDguMDI5NjcgNC4xODcyNkM4Ljc3ODczIDQuMTg3MjYgOS4zOTE1MiA0Ljc3MDc1IDkuNDM4MjkgNS41MDgwMUM5LjQ1OTkyIDQuOTQ3MSA5LjkyMTQ3IDQuNDk5MDIgMTAuNDg3NyA0LjQ5OTAyQzExLjA2NzcgNC40OTkwMiAxMS41Mzc4IDQuOTY5MiAxMS41Mzc4IDUuNTQ5MTlWOC43NjI0NkwxMS41Mzc5IDYuNzExNUMxMS41Mzc5IDYuMDMwOTUgMTIuMDg5NiA1LjQ3OTI2IDEyLjc3MDIgNS40NzkyNkMxMy40NTA3IDUuNDc5MjYgMTQuMDAyNCA2LjAzMDk1IDE0LjAwMjQgNi43MTE1TDE0LjAwMjQgOC43NjI0NkwxNC4wMDI5IDguMDE5ODNDMTQuMDAyOSA3LjMzOTI5IDE0LjU1NDYgNi43ODc1OSAxNS4yMzUyIDYuNzg3NTlDMTUuOTE1NyA2Ljc4NzU5IDE2LjQ2NzQgNy4zMzkyOCAxNi40Njc0IDguMDE5ODNWMTEuNDk3TDE2LjQ2NzUgMTIuNDQ2N0MxNi40Njc1IDE0LjA4MjEgMTUuODA5NiAxNS42NDg3IDE0LjY0MiAxNi43OTM4VjE3LjMyNjJDMTQuNjQyIDE3Ljc4NjQgMTQuMjY4OSAxOC4xNTk1IDEzLjgwODcgMTguMTU5NUg4LjE3MzE3QzcuNzEyOTMgMTguMTU5NSA3LjMzOTg0IDE3Ljc4NjQgNy4zMzk4NCAxNy4zMjYyVjE1Ljk0MjRMNS4zNDU2MiAxNC43NTM0QzQuNTg5MjQgMTQuMzAyNCA0LjEyNTkxIDEzLjQ4NjcgNC4xMjU4OSAxMi42MDYxTDQuMTI1ODMgOS4yODM4M0M0LjEyNTgyIDguOTU0MjcgNC4zMjAwMyA4LjY1NTY2IDQuNjIxMjkgOC41MjIwNUw2LjYxODE3IDcuNjM2MzRWNS41OTg3NVoiIGZpbGw9IndoaXRlIi8+CjxwYXRoIGZpbGwtcnVsZT0iZXZlbm9kZCIgY2xpcC1ydWxlPSJldmVub2RkIiBkPSJNMTAuNDg3OCAzLjI0OTAyQzExLjI3OTYgMy4yNDkwMiAxMS45Nzc4IDMuNjQ5MDIgMTIuMzkxNyA0LjI1Nzk2QzEyLjUxNTEgNC4yMzkwNiAxMi42NDE2IDQuMjI5MjYgMTIuNzcwMyA0LjIyOTI2QzEzLjcyMjQgNC4yMjkyNiAxNC41NDkzIDQuNzY1MzEgMTQuOTY1NyA1LjU1MjA3QzE1LjA1NDMgNS41NDI1IDE1LjE0NDIgNS41Mzc1OSAxNS4yMzUzIDUuNTM3NTlDMTYuNjA2MiA1LjUzNzU5IDE3LjcxNzYgNi42NDg5MyAxNy43MTc2IDguMDE5ODNMMTcuNzE3NyAxMi40NDY3QzE3LjcxNzcgMTQuMjM1NSAxNy4wNjQ3IDE1Ljk1NTkgMTUuODkyMSAxNy4yOTA0VjE3LjMyNjJDMTUuODkyMSAxOC40NzY4IDE0Ljk1OTQgMTkuNDA5NSAxMy44MDg4IDE5LjQwOTVIOC4xNzMzMkM3LjAyMjczIDE5LjQwOTUgNi4wODk5OCAxOC40NzY4IDYuMDg5OTggMTcuMzI2MlYxNi42NTI0TDQuNzA1NjMgMTUuODI3QzMuNTcxMDYgMTUuMTUwNSAyLjg3NjA3IDEzLjkyNzEgMi44NzYwNCAxMi42MDYxTDIuODc1OTggOS4yODM4NUMyLjg3NTk2IDguNDU5OTYgMy4zNjE0OSA3LjcxMzQ1IDQuMTE0NjIgNy4zNzk0TDUuMzY4MzIgNi44MjMzM1Y1LjU5ODc1QzUuMzY4MzIgNC4xMjg4NSA2LjU1OTkxIDIuOTM3MjYgOC4wMjk4MiAyLjkzNzI2QzguNjA4MzEgMi45MzcyNiA5LjE0MzU1IDMuMTIxNyA5LjU4MDA1IDMuNDM1MDVDOS44NTg1MyAzLjMxNTMyIDEwLjE2NTQgMy4yNDkwMiAxMC40ODc4IDMuMjQ5MDJaTTEyLjQ0NzkgNS41MjE4NlY5LjQ3NTU3QzEyLjQ0NzkgOS43Mjc2MiAxMi4yNDM2IDkuOTMxOTUgMTEuOTkxNiA5LjkzMTk1QzExLjc1NjggOS45MzE5NSAxMS41NjM0IDkuNzU0NjUgMTEuNTM4IDkuNTI2NjNDMTEuNTM2MSA5LjUwOTg3IDExLjUzNTIgOS40OTI4MyAxMS41MzUyIDkuNDc1NTdWNS40NzE1OEMxMS41MTU0IDUuMjAwODMgMTEuMzkzIDQuOTU4NTggMTEuMjA2NiA0Ljc4MzU4QzExLjAxODggNC42MDcxMSAxMC43NjU5IDQuNDk5MDIgMTAuNDg3OCA0LjQ5OTAyQzEwLjQ3NjYgNC40OTkwMiAxMC40NjU0IDQuNDk5MTkgMTAuNDU0MiA0LjQ5OTU0QzkuOTAzNDcgNC41MTY4NCA5LjQ1OTY0IDQuOTU4MjQgOS40Mzg0NCA1LjUwODAxQzkuNDM4MiA1LjUwNDMgOS40Mzc5NSA1LjUwMDU4IDkuNDM3NjkgNS40OTY4OFY5LjkwMjQzQzkuNDM3NjkgMTAuMTU0NSA5LjIzMzM2IDEwLjM1ODggOC45ODEzMSAxMC4zNTg4QzguNzI5MjUgMTAuMzU4OCA4LjUyNDkyIDEwLjE1NDUgOC41MjQ5MiA5LjkwMjQzVjQuMjc2NTNDOC4zNzA4NiA0LjIxODgyIDguMjA0MDIgNC4xODcyNiA4LjAyOTgyIDQuMTg3MjZDNy4yNTAyNyA0LjE4NzI2IDYuNjE4MzIgNC44MTkyIDYuNjE4MzIgNS41OTg3NUw2LjYxODI3IDkuOTc1OTlDNi42MTgyNyAxMC4yMjggNi40MTM5NCAxMC40MzI0IDYuMTYxODkgMTAuNDMyNEM1LjkwOTgzIDEwLjQzMjQgNS43MDU1IDEwLjIyOCA1LjcwNTUgOS45NzU5OVY4LjA0MTIyTDQuNjIxNDQgOC41MjIwNUM0LjMyMDE4IDguNjU1NjYgNC4xMjU5NyA4Ljk1NDI3IDQuMTI1OTggOS4yODM4M0w0LjEyNjA0IDEyLjYwNjFDNC4xMjYwNiAxMy40ODY3IDQuNTg5MzkgMTQuMzAyNCA1LjM0NTc2IDE0Ljc1MzRMNy4zMzk5OCAxNS45NDI0VjE3LjMyNjJDNy4zMzk5OCAxNy43ODY0IDcuNzEzMDggMTguMTU5NSA4LjE3MzMyIDE4LjE1OTVIMTMuODA4OEMxNC4yNjkgMTguMTU5NSAxNC42NDIxIDE3Ljc4NjQgMTQuNjQyMSAxNy4zMjYyVjE2Ljc5MzhDMTUuNzM4MSAxNS43MTkgMTYuMzg1IDE0LjI3MjggMTYuNDYwMyAxMi43NDdDMTYuNDY0NiAxMi42NiAxNi40NjcgMTIuNTcyOCAxNi40Njc2IDEyLjQ4NTRMMTYuNDY3NyAxMi40NDY3TDE2LjQ2NzYgOC4wMTk4M0MxNi40Njc2IDcuMzQ1MDQgMTUuOTI1MiA2Ljc5NjkzIDE1LjI1MjUgNi43ODc3MUwxNS4yMzUzIDYuNzg3NTlDMTUuMTI1IDYuNzg3NTkgMTUuMDE4IDYuODAyMSAxNC45MTYyIDYuODI5MzFWOS42MDEzNkMxNC45MTYyIDkuODUzNDIgMTQuNzExOSAxMC4wNTc3IDE0LjQ1OTggMTAuMDU3N0MxNC4yMDc4IDEwLjA1NzcgMTQuMDAzNCA5Ljg1MzQxIDE0LjAwMzQgOS42MDEzNlY3Ljk4OTg1QzE0LjAwMzIgNy45OTk4MiAxNC4wMDMxIDguMDA5ODEgMTQuMDAzMSA4LjAxOTgzTDE0LjAwMzQgOS42MDEzNkwxNC4wMDI1IDYuNzExNUMxNC4wMDI1IDYuNDQ5NzQgMTMuOTIwOSA2LjIwNzA1IDEzLjc4MTggNi4wMDc0OEMxMy41NjIgNS42OTI0MiAxMy4xOTg5IDUuNDg0ODMgMTIuNzg3IDUuNDc5MzdMMTIuNzcwMyA1LjQ3OTI2QzEyLjY1ODggNS40NzkyNiAxMi41NTA3IDUuNDk0MDggMTIuNDQ3OSA1LjUyMTg2WiIgZmlsbD0iIzFEMUMyMyIvPgo8L3N2Zz4="), auto'
1189
+ },
1190
+ fromNodeJSON(node, json, isFirstCreate) {
1191
+ initFormDataFromJSON(node, json, isFirstCreate);
1192
+ return;
1193
+ },
1194
+ toNodeJSON(node) {
1195
+ const nodeError = node.getData(FlowNodeErrorData)?.getError();
1196
+ if (nodeError) {
1197
+ throw nodeError;
1198
+ }
1199
+ const transform = node.getData(TransformData5);
1200
+ let formJSON = toFormJSON(node);
1201
+ const metaData = {};
1202
+ const nodeMeta = node.getNodeMeta();
1203
+ const subCanvas = nodeMeta.subCanvas?.(node);
1204
+ if (subCanvas?.isCanvas === false) {
1205
+ const canvasNodeTransform = subCanvas.canvasNode.getData(FlowNodeTransformData2);
1206
+ const { x, y } = canvasNodeTransform.transform.position;
1207
+ metaData.canvasPosition = { x, y };
1208
+ }
1209
+ const json = {
1210
+ id: node.id,
1211
+ type: node.flowNodeType,
1212
+ meta: {
1213
+ position: { x: transform.position.x, y: transform.position.y },
1214
+ ...metaData
1215
+ },
1216
+ data: formJSON
1217
+ };
1218
+ return json;
1219
+ }
1220
+ };
1221
+
1222
+ // src/workflow-lines-manager.ts
1223
+ var WorkflowLinesManager = class {
1224
+ constructor() {
1225
+ this.toDispose = new DisposableCollection();
1226
+ // 线条类型
1227
+ this._lineType = 0 /* BEZIER */;
1228
+ this.onAvailableLinesChangeEmitter = new Emitter3();
1229
+ this.onForceUpdateEmitter = new Emitter3();
1230
+ /**
1231
+ * 有效的线条被添加或者删除时候触发,未连上的线条不算
1232
+ */
1233
+ this.onAvailableLinesChange = this.onAvailableLinesChangeEmitter.event;
1234
+ /**
1235
+ * 强制渲染 lines
1236
+ */
1237
+ this.onForceUpdate = this.onForceUpdateEmitter.event;
1238
+ this.contributionFactories = [];
1239
+ /**
1240
+ * 是否在调整线条
1241
+ */
1242
+ this.isDrawing = false;
1243
+ }
1244
+ init(doc) {
1245
+ this.document = doc;
1246
+ }
1247
+ forceUpdate() {
1248
+ this.onForceUpdateEmitter.fire();
1249
+ }
1250
+ get lineType() {
1251
+ return this._lineType;
1252
+ }
1253
+ get lineColor() {
1254
+ const color = {
1255
+ default: "var(--g-workflow-line-color-default,#4d53e8)" /* DEFUALT */,
1256
+ error: "var(--g-workflow-line-color-error,red)" /* ERROR */,
1257
+ hidden: "var(--g-workflow-line-color-hidden,transparent)" /* HIDDEN */,
1258
+ drawing: "var(--g-workflow-line-color-drawing, #5DD6E3)" /* DRAWING */,
1259
+ hovered: "var(--g-workflow-line-color-hover,#37d0ff)" /* HOVER */,
1260
+ selected: "var(--g-workflow-line-color-selected,#37d0ff)" /* SELECTED */,
1261
+ flowing: "var(--g-workflow-line-color-flowing,#4d53e8)" /* FLOWING */
1262
+ };
1263
+ if (this.options.lineColor) {
1264
+ Object.assign(color, this.options.lineColor);
1265
+ }
1266
+ return color;
1267
+ }
1268
+ switchLineType(newType) {
1269
+ if (newType === void 0) {
1270
+ if (this._lineType === 0 /* BEZIER */) {
1271
+ newType = 1 /* LINE_CHART */;
1272
+ } else {
1273
+ newType = 0 /* BEZIER */;
1274
+ }
1275
+ }
1276
+ if (newType !== this._lineType) {
1277
+ this._lineType = newType;
1278
+ this.getAllLines().forEach((line) => {
1279
+ line.getData(WorkflowLineRenderData).update();
1280
+ });
1281
+ window.requestAnimationFrame(() => {
1282
+ this.entityManager.fireEntityChanged(WorkflowLineEntity.type);
1283
+ });
1284
+ }
1285
+ return this._lineType;
1286
+ }
1287
+ getAllLines() {
1288
+ return this.entityManager.getEntities(WorkflowLineEntity);
1289
+ }
1290
+ hasLine(portInfo) {
1291
+ return !!this.entityManager.getEntityById(
1292
+ WorkflowLineEntity.portInfoToLineId(portInfo)
1293
+ );
1294
+ }
1295
+ getLine(portInfo) {
1296
+ return this.entityManager.getEntityById(
1297
+ WorkflowLineEntity.portInfoToLineId(portInfo)
1298
+ );
1299
+ }
1300
+ replaceLine(oldPortInfo, newPortInfo) {
1301
+ const oldLine = this.getLine(oldPortInfo);
1302
+ if (oldLine) {
1303
+ oldLine.dispose();
1304
+ }
1305
+ return this.createLine(newPortInfo);
1306
+ }
1307
+ createLine(options) {
1308
+ const { from, to, drawingTo, fromPort, toPort } = options;
1309
+ const available = Boolean(from && to);
1310
+ const key = options.key || WorkflowLineEntity.portInfoToLineId(options);
1311
+ let line = this.entityManager.getEntityById(key);
1312
+ if (line) {
1313
+ line.highlightColor = "";
1314
+ line.validate();
1315
+ return line;
1316
+ }
1317
+ const fromNode = this.entityManager.getEntityById(from)?.getData(WorkflowNodeLinesData);
1318
+ const toNode = to ? this.entityManager.getEntityById(to).getData(WorkflowNodeLinesData) : void 0;
1319
+ if (!fromNode) {
1320
+ return;
1321
+ }
1322
+ this.isDrawing = Boolean(drawingTo);
1323
+ line = this.entityManager.createEntity(WorkflowLineEntity, {
1324
+ id: key,
1325
+ document: this.document,
1326
+ linesManager: this,
1327
+ from,
1328
+ fromPort,
1329
+ toPort,
1330
+ to,
1331
+ drawingTo
1332
+ });
1333
+ this.registerData(line);
1334
+ fromNode.addLine(line);
1335
+ toNode?.addLine(line);
1336
+ line.onDispose(() => {
1337
+ if (drawingTo) {
1338
+ this.isDrawing = false;
1339
+ }
1340
+ fromNode.removeLine(line);
1341
+ toNode?.removeLine(line);
1342
+ line.validate();
1343
+ });
1344
+ line.onDispose(() => {
1345
+ if (available) {
1346
+ this.onAvailableLinesChangeEmitter.fire({
1347
+ type: "DELETE_LINE" /* DELETE_LINE */,
1348
+ toJSON: () => line.toJSON(),
1349
+ entity: line
1350
+ });
1351
+ }
1352
+ });
1353
+ if (available) {
1354
+ this.onAvailableLinesChangeEmitter.fire({
1355
+ type: "ADD_LINE" /* ADD_LINE */,
1356
+ toJSON: () => line.toJSON(),
1357
+ entity: line
1358
+ });
1359
+ }
1360
+ line.validate();
1361
+ return line;
1362
+ }
1363
+ /**
1364
+ * 获取线条中距离鼠标位置最近的线条和距离
1365
+ * @param mousePos 鼠标位置
1366
+ * @param minDistance 最小检测距离
1367
+ * @returns 距离鼠标位置最近的线条 以及距离
1368
+ */
1369
+ getCloseInLineFromMousePos(mousePos, minDistance = LINE_HOVER_DISTANCE) {
1370
+ let targetLine, targetLineDist;
1371
+ this.getAllLines().forEach((line) => {
1372
+ const dist = line.getHoverDist(mousePos);
1373
+ if (dist <= minDistance && (!targetLineDist || targetLineDist >= dist)) {
1374
+ targetLineDist = dist;
1375
+ targetLine = line;
1376
+ }
1377
+ });
1378
+ return targetLine;
1379
+ }
1380
+ dispose() {
1381
+ this.toDispose.dispose();
1382
+ }
1383
+ get disposed() {
1384
+ return this.toDispose.disposed;
1385
+ }
1386
+ isErrorLine(fromPort, toPort) {
1387
+ if (this.options.isErrorLine) {
1388
+ return this.options.isErrorLine(fromPort, toPort, this);
1389
+ }
1390
+ return false;
1391
+ }
1392
+ isReverseLine(line) {
1393
+ if (this.options.isReverseLine) {
1394
+ return this.options.isReverseLine(line);
1395
+ }
1396
+ return false;
1397
+ }
1398
+ isHideArrowLine(line) {
1399
+ if (this.options.isHideArrowLine) {
1400
+ return this.options.isHideArrowLine(line);
1401
+ }
1402
+ return false;
1403
+ }
1404
+ isFlowingLine(line) {
1405
+ if (this.options.isFlowingLine) {
1406
+ return this.options.isFlowingLine(line);
1407
+ }
1408
+ return false;
1409
+ }
1410
+ isDisabledLine(line) {
1411
+ if (this.options.isDisabledLine) {
1412
+ return this.options.isDisabledLine(line);
1413
+ }
1414
+ return false;
1415
+ }
1416
+ isVerticalLine(line) {
1417
+ if (this.options.isVerticalLine) {
1418
+ return this.options.isVerticalLine(line);
1419
+ }
1420
+ return false;
1421
+ }
1422
+ setLineRenderType(line) {
1423
+ if (this.options.setLineRenderType) {
1424
+ return this.options.setLineRenderType(line);
1425
+ }
1426
+ return void 0;
1427
+ }
1428
+ setLineClassName(line) {
1429
+ if (this.options.setLineClassName) {
1430
+ return this.options.setLineClassName(line);
1431
+ }
1432
+ return void 0;
1433
+ }
1434
+ getLineColor(line) {
1435
+ if (line.isHidden) {
1436
+ return this.lineColor.hidden;
1437
+ }
1438
+ if (line.hasError) {
1439
+ return this.lineColor.error;
1440
+ }
1441
+ if (line.highlightColor) {
1442
+ return line.highlightColor;
1443
+ }
1444
+ if (line.drawingTo) {
1445
+ return this.lineColor.drawing;
1446
+ }
1447
+ if (this.hoverService.isHovered(line.id)) {
1448
+ return this.lineColor.hovered;
1449
+ }
1450
+ if (this.selectService.isSelected(line.id)) {
1451
+ return this.lineColor.selected;
1452
+ }
1453
+ if (this.isFlowingLine(line)) {
1454
+ return this.lineColor.flowing;
1455
+ }
1456
+ return this.lineColor.default;
1457
+ }
1458
+ canAddLine(fromPort, toPort, silent) {
1459
+ if (fromPort === toPort || fromPort.node === toPort.node || fromPort.portType !== "output" || toPort.portType !== "input" || toPort.disabled) {
1460
+ return false;
1461
+ }
1462
+ if (this.options.canAddLine) {
1463
+ return this.options.canAddLine(fromPort, toPort, this, silent);
1464
+ }
1465
+ return fromPort.node !== toPort.node;
1466
+ }
1467
+ toJSON() {
1468
+ return this.getAllLines().filter((l) => !l.isDrawing).map((l) => l.toJSON());
1469
+ }
1470
+ getPortById(portId) {
1471
+ return this.entityManager.getEntityById(portId);
1472
+ }
1473
+ canRemove(line, newLineInfo, silent) {
1474
+ if (this.options && this.options.canDeleteLine && !this.options.canDeleteLine(line, newLineInfo, silent)) {
1475
+ return false;
1476
+ }
1477
+ return true;
1478
+ }
1479
+ canReset(fromPort, oldToPort, newToPort) {
1480
+ if (this.options && this.options.canResetLine && !this.options.canResetLine(fromPort, oldToPort, newToPort, this)) {
1481
+ return false;
1482
+ }
1483
+ return true;
1484
+ }
1485
+ /**
1486
+ * 根据鼠标位置找到 port
1487
+ * @param pos
1488
+ */
1489
+ getPortFromMousePos(pos) {
1490
+ const allNodes = this.getSortedNodes().reverse();
1491
+ const allPorts = allNodes.map((node) => node.getData(WorkflowNodePortsData).allPorts).flat();
1492
+ const targetPort = allPorts.find((port) => port.isHovered(pos.x, pos.y));
1493
+ if (targetPort) {
1494
+ const containNodes = this.getContainNodesFromMousePos(pos);
1495
+ const targetNode = last(containNodes);
1496
+ if (targetNode && targetNode !== targetPort.node) {
1497
+ return;
1498
+ }
1499
+ }
1500
+ return targetPort;
1501
+ }
1502
+ /**
1503
+ * 根据鼠标位置找到 node
1504
+ * @param pos - 鼠标位置
1505
+ */
1506
+ getNodeFromMousePos(pos) {
1507
+ const { selection } = this.selectService;
1508
+ const containNodes = this.getContainNodesFromMousePos(pos);
1509
+ if (selection?.length) {
1510
+ const filteredNodes = containNodes.filter(
1511
+ (node) => selection.some((_node) => node.id === _node.id)
1512
+ );
1513
+ if (filteredNodes?.length) {
1514
+ return last(filteredNodes);
1515
+ }
1516
+ }
1517
+ return last(containNodes);
1518
+ }
1519
+ registerContribution(factory) {
1520
+ this.contributionFactories.push(factory);
1521
+ return this;
1522
+ }
1523
+ registerData(line) {
1524
+ line.addData(WorkflowLineRenderData);
1525
+ }
1526
+ getSortedNodes() {
1527
+ return this.document.getAllNodes().sort((a, b) => this.getNodeIndex(a) - this.getNodeIndex(b));
1528
+ }
1529
+ /** 获取鼠标坐标位置的所有节点(stackIndex 从小到大排序) */
1530
+ getContainNodesFromMousePos(pos) {
1531
+ const allNodes = this.getSortedNodes();
1532
+ const zoom = this.entityManager.getEntity(PlaygroundConfigEntity2)?.config?.zoom || 1;
1533
+ const containNodes = allNodes.map((node) => {
1534
+ const { bounds } = node.getData(FlowNodeTransformData3);
1535
+ if (bounds.clone().pad(4 / zoom).contains(pos.x, pos.y)) {
1536
+ return node;
1537
+ }
1538
+ }).filter(Boolean);
1539
+ return containNodes;
1540
+ }
1541
+ getNodeIndex(node) {
1542
+ const nodeRenderData = node.getData(FlowNodeRenderData2);
1543
+ return nodeRenderData.stackIndex;
1544
+ }
1545
+ };
1546
+ __decorateClass([
1547
+ inject3(WorkflowHoverService)
1548
+ ], WorkflowLinesManager.prototype, "hoverService", 2);
1549
+ __decorateClass([
1550
+ inject3(WorkflowSelectService)
1551
+ ], WorkflowLinesManager.prototype, "selectService", 2);
1552
+ __decorateClass([
1553
+ inject3(EntityManager2)
1554
+ ], WorkflowLinesManager.prototype, "entityManager", 2);
1555
+ __decorateClass([
1556
+ inject3(WorkflowDocumentOptions)
1557
+ ], WorkflowLinesManager.prototype, "options", 2);
1558
+ WorkflowLinesManager = __decorateClass([
1559
+ injectable3()
1560
+ ], WorkflowLinesManager);
1561
+
1562
+ // src/workflow-document.ts
1563
+ import { customAlphabet } from "nanoid";
1564
+ import { inject as inject5, injectable as injectable5, optional, postConstruct } from "inversify";
1565
+ import { Emitter as Emitter4 } from "@flowgram.ai/utils";
1566
+ import { NodeEngineContext } from "@flowgram.ai/form-core";
1567
+ import {
1568
+ FlowDocument,
1569
+ FlowNodeBaseType,
1570
+ FlowNodeTransformData as FlowNodeTransformData5
1571
+ } from "@flowgram.ai/document";
1572
+ import {
1573
+ injectPlaygroundContext,
1574
+ PlaygroundConfigEntity as PlaygroundConfigEntity4,
1575
+ PositionData,
1576
+ TransformData as TransformData7
1577
+ } from "@flowgram.ai/core";
1578
+
1579
+ // src/layout/free-layout.ts
1580
+ import { inject as inject4, injectable as injectable4 } from "inversify";
1581
+ import {
1582
+ PaddingSchema,
1583
+ Rectangle as Rectangle7,
1584
+ SizeSchema as SizeSchema2
1585
+ } from "@flowgram.ai/utils";
1586
+ import {
1587
+ FlowDocumentProvider,
1588
+ FlowNodeTransformData as FlowNodeTransformData4
1589
+ } from "@flowgram.ai/document";
1590
+ import { PlaygroundConfigEntity as PlaygroundConfigEntity3, TransformData as TransformData6 } from "@flowgram.ai/core";
1591
+ var FREE_LAYOUT_KEY = "free-layout";
1592
+ var FreeLayout = class {
1593
+ constructor() {
1594
+ this.name = FREE_LAYOUT_KEY;
1595
+ }
1596
+ get document() {
1597
+ return this.documentProvider();
1598
+ }
1599
+ /**
1600
+ * 更新布局
1601
+ */
1602
+ update() {
1603
+ if (this.document.root.getData(FlowNodeTransformData4)?.localDirty) {
1604
+ this.document.root.clearMemoGlobal();
1605
+ }
1606
+ }
1607
+ syncTransform(node) {
1608
+ const transform = node.getData(FlowNodeTransformData4);
1609
+ if (!transform.localDirty) {
1610
+ return;
1611
+ }
1612
+ node.clearMemoGlobal();
1613
+ node.clearMemoLocal();
1614
+ transform.transform.update({
1615
+ size: transform.data.size
1616
+ });
1617
+ if (!node.parent) {
1618
+ return;
1619
+ }
1620
+ node.parent.clearMemoGlobal();
1621
+ node.parent.clearMemoLocal();
1622
+ const parentTransform = node.parent.getData(FlowNodeTransformData4);
1623
+ parentTransform.transform.fireChange();
1624
+ }
1625
+ /**
1626
+ * 更新所有受影响的上下游节点
1627
+ */
1628
+ updateAffectedTransform(node) {
1629
+ const transformData = node.transform;
1630
+ if (!transformData.localDirty) {
1631
+ return;
1632
+ }
1633
+ const allParents = this.getAllParents(node);
1634
+ const allBlocks = this.getAllBlocks(node).reverse();
1635
+ const affectedNodes = [...allBlocks, ...allParents];
1636
+ affectedNodes.forEach((node2) => {
1637
+ this.fireChange(node2);
1638
+ });
1639
+ }
1640
+ /**
1641
+ * 获取节点的 padding 数据
1642
+ * @param node
1643
+ */
1644
+ getPadding(node) {
1645
+ const { padding } = node.getNodeMeta();
1646
+ const transform = node.getData(FlowNodeTransformData4);
1647
+ if (padding) {
1648
+ return typeof padding === "function" ? padding(transform) : padding;
1649
+ }
1650
+ return PaddingSchema.empty();
1651
+ }
1652
+ /**
1653
+ * 默认滚动到 fitview 区域
1654
+ * @param contentSize
1655
+ */
1656
+ getInitScroll(contentSize) {
1657
+ const bounds = Rectangle7.enlarge(
1658
+ this.document.getAllNodes().map((node) => node.getData(TransformData6).bounds)
1659
+ ).pad(30, 30);
1660
+ const viewport = this.playgroundConfig.getViewport(false);
1661
+ const zoom = SizeSchema2.fixSize(bounds, viewport);
1662
+ return {
1663
+ scrollX: (bounds.x + bounds.width / 2) * zoom - this.playgroundConfig.config.width / 2,
1664
+ scrollY: (bounds.y + bounds.height / 2) * zoom - this.playgroundConfig.config.height / 2
1665
+ };
1666
+ }
1667
+ /**
1668
+ * 获取默认输入点
1669
+ */
1670
+ getDefaultInputPoint(node) {
1671
+ return node.getData(TransformData6).bounds.leftCenter;
1672
+ }
1673
+ /**
1674
+ * 获取默认输出点
1675
+ */
1676
+ getDefaultOutputPoint(node) {
1677
+ return node.getData(TransformData6).bounds.rightCenter;
1678
+ }
1679
+ /**
1680
+ * 水平中心点
1681
+ */
1682
+ getDefaultNodeOrigin() {
1683
+ return { x: 0.5, y: 0 };
1684
+ }
1685
+ getAllParents(node) {
1686
+ const parents = [];
1687
+ let current = node.parent;
1688
+ while (current) {
1689
+ parents.push(current);
1690
+ current = current.parent;
1691
+ }
1692
+ return parents;
1693
+ }
1694
+ getAllBlocks(node) {
1695
+ return node.blocks.reduce(
1696
+ (acc, child) => [...acc, ...this.getAllBlocks(child)],
1697
+ [node]
1698
+ );
1699
+ }
1700
+ fireChange(node) {
1701
+ const transformData = node?.transform;
1702
+ if (!node || !transformData?.localDirty) {
1703
+ return;
1704
+ }
1705
+ node.clearMemoGlobal();
1706
+ node.clearMemoLocal();
1707
+ transformData.transform.fireChange();
1708
+ }
1709
+ };
1710
+ __decorateClass([
1711
+ inject4(PlaygroundConfigEntity3)
1712
+ ], FreeLayout.prototype, "playgroundConfig", 2);
1713
+ __decorateClass([
1714
+ inject4(FlowDocumentProvider)
1715
+ ], FreeLayout.prototype, "documentProvider", 2);
1716
+ FreeLayout = __decorateClass([
1717
+ injectable4()
1718
+ ], FreeLayout);
1719
+
1720
+ // src/workflow-document.ts
1721
+ var nanoid2 = customAlphabet("1234567890", 5);
1722
+ var WorkflowDocumentProvider = Symbol("WorkflowDocumentProvider");
1723
+ var WorkflowDocument = class extends FlowDocument {
1724
+ constructor() {
1725
+ super(...arguments);
1726
+ this._onContentChangeEmitter = new Emitter4();
1727
+ this.onLoadedEmitter = new Emitter4();
1728
+ this.onContentChange = this._onContentChangeEmitter.event;
1729
+ this._onReloadEmitter = new Emitter4();
1730
+ this.onReload = this._onReloadEmitter.event;
1731
+ /**
1732
+ * 数据加载完成
1733
+ */
1734
+ this.onLoaded = this.onLoadedEmitter.event;
1735
+ this._loading = false;
1736
+ this.options = {};
1737
+ }
1738
+ get loading() {
1739
+ return this._loading;
1740
+ }
1741
+ async fitView(easing) {
1742
+ return fitView(this, this.playgroundConfig, easing).then(() => {
1743
+ this.linesManager.forceUpdate();
1744
+ });
1745
+ }
1746
+ init() {
1747
+ super.init();
1748
+ this.currentLayoutKey = this.options.defaultLayout || FREE_LAYOUT_KEY;
1749
+ this.linesManager.init(this);
1750
+ this.playgroundConfig.getCursors = () => this.options.cursors;
1751
+ this.linesManager.onAvailableLinesChange((e) => this.fireContentChange(e));
1752
+ this.playgroundConfig.onReadonlyOrDisabledChange(({ readonly }) => {
1753
+ if (this.nodeEngineContext) {
1754
+ this.nodeEngineContext.readonly = readonly;
1755
+ }
1756
+ });
1757
+ }
1758
+ async load() {
1759
+ if (this.disposed) return;
1760
+ this._loading = true;
1761
+ await super.load();
1762
+ this._loading = false;
1763
+ this.onLoadedEmitter.fire();
1764
+ }
1765
+ async reload(json, delayTime = 0) {
1766
+ if (this.disposed) return;
1767
+ this._loading = true;
1768
+ this.clear();
1769
+ this.fromJSON(json);
1770
+ await delay(delayTime);
1771
+ this._loading = false;
1772
+ this._onReloadEmitter.fire(this);
1773
+ }
1774
+ /**
1775
+ * 从数据加载
1776
+ * @param json
1777
+ */
1778
+ fromJSON(json, fireRender = true) {
1779
+ if (this.disposed) return;
1780
+ const workflowJSON = {
1781
+ nodes: json.nodes ?? [],
1782
+ edges: json.edges ?? []
1783
+ };
1784
+ this.entityManager.changeEntityLocked = true;
1785
+ this.renderJSON(workflowJSON);
1786
+ this.entityManager.changeEntityLocked = false;
1787
+ this.transformer.loading = false;
1788
+ if (fireRender) {
1789
+ this.fireRender();
1790
+ }
1791
+ }
1792
+ /**
1793
+ * 清空画布
1794
+ */
1795
+ clear() {
1796
+ this.getAllNodes().map((node) => node.dispose());
1797
+ this.linesManager.getAllLines().map((line) => line.dispose());
1798
+ this.getAllPorts().map((port) => port.dispose());
1799
+ this.selectServices.clear();
1800
+ }
1801
+ /**
1802
+ * 创建流程节点
1803
+ * @param json
1804
+ */
1805
+ createWorkflowNode(json, isClone = false, parentId) {
1806
+ const isExistedNode = this.getNode(json.id);
1807
+ const parent = this.getNode(parentId ?? this.root.id) ?? this.root;
1808
+ const node = this.addNode(
1809
+ {
1810
+ ...json,
1811
+ parent
1812
+ },
1813
+ void 0,
1814
+ true
1815
+ );
1816
+ const registry = node.getNodeRegistry();
1817
+ const { formMeta } = registry;
1818
+ const meta = node.getNodeMeta();
1819
+ const formData = getFlowNodeFormData(node);
1820
+ const transform = node.getData(FlowNodeTransformData5);
1821
+ const freeLayout = this.layout;
1822
+ if (!isExistedNode) {
1823
+ transform.onDataChange(() => {
1824
+ freeLayout.syncTransform(node);
1825
+ });
1826
+ }
1827
+ let { position } = meta;
1828
+ if (!position) {
1829
+ position = this.getNodeDefaultPosition(json.type);
1830
+ }
1831
+ node.getData(TransformData7).update({
1832
+ position
1833
+ });
1834
+ if (formMeta && formData && !formData.formModel.initialized) {
1835
+ formData.createForm(formMeta, json.data);
1836
+ formData.onDataChange(() => {
1837
+ this.fireContentChange({
1838
+ type: "NODE_DATA_CHANGE" /* NODE_DATA_CHANGE */,
1839
+ toJSON: () => formData.toJSON(),
1840
+ entity: node
1841
+ });
1842
+ });
1843
+ }
1844
+ const positionData = node.getData(PositionData);
1845
+ if (!isExistedNode) {
1846
+ positionData.onDataChange(() => {
1847
+ this.fireContentChange({
1848
+ type: "MOVE_NODE" /* MOVE_NODE */,
1849
+ toJSON: () => positionData.toJSON(),
1850
+ entity: node
1851
+ });
1852
+ });
1853
+ }
1854
+ const subCanvas = this.getNodeSubCanvas(node);
1855
+ if (!isExistedNode && !subCanvas?.isCanvas) {
1856
+ this.fireContentChange({
1857
+ type: "ADD_NODE" /* ADD_NODE */,
1858
+ entity: node,
1859
+ toJSON: () => this.toNodeJSON(node)
1860
+ });
1861
+ node.onDispose(() => {
1862
+ if (!node.parent || node.parent.flowNodeType === FlowNodeBaseType.ROOT) {
1863
+ return;
1864
+ }
1865
+ const parentTransform = node.parent.getData(FlowNodeTransformData5);
1866
+ parentTransform.fireChange();
1867
+ });
1868
+ let lastDeleteNodeData;
1869
+ node.preDispose.onDispose(() => {
1870
+ lastDeleteNodeData = this.toNodeJSON(node);
1871
+ });
1872
+ node.onDispose(() => {
1873
+ this.fireContentChange({
1874
+ type: "DELETE_NODE" /* DELETE_NODE */,
1875
+ entity: node,
1876
+ toJSON: () => lastDeleteNodeData
1877
+ });
1878
+ });
1879
+ }
1880
+ if (json.blocks) {
1881
+ this.renderJSON(
1882
+ { nodes: json.blocks, edges: json.edges ?? [] },
1883
+ {
1884
+ parent: node,
1885
+ isClone
1886
+ }
1887
+ );
1888
+ }
1889
+ if (subCanvas) {
1890
+ const canvasTransform = subCanvas.canvasNode.getData(TransformData7);
1891
+ canvasTransform.update({
1892
+ position: subCanvas.parentNode.getNodeMeta()?.canvasPosition
1893
+ });
1894
+ if (!isExistedNode) {
1895
+ subCanvas.parentNode.onDispose(() => {
1896
+ subCanvas.canvasNode.dispose();
1897
+ });
1898
+ subCanvas.canvasNode.onDispose(() => {
1899
+ subCanvas.parentNode.dispose();
1900
+ });
1901
+ }
1902
+ }
1903
+ if (!isExistedNode) {
1904
+ this.onNodeCreateEmitter.fire({
1905
+ node,
1906
+ data: json,
1907
+ json
1908
+ });
1909
+ } else {
1910
+ this.onNodeUpdateEmitter.fire({
1911
+ node,
1912
+ data: json,
1913
+ json
1914
+ });
1915
+ }
1916
+ return node;
1917
+ }
1918
+ /**
1919
+ * 添加节点,如果节点已经存在则不会重复创建
1920
+ * @param data
1921
+ * @param addedNodes
1922
+ */
1923
+ addNode(data, addedNodes, ignoreCreateAndUpdateEvent) {
1924
+ const { id, type = "block", originParent, parent, meta, hidden, index } = data;
1925
+ let node = this.getNode(id);
1926
+ let isNew = false;
1927
+ const register = this.getNodeRegistry(type, data.originParent);
1928
+ if (node && node.flowNodeType !== data.type) {
1929
+ node.dispose();
1930
+ node = void 0;
1931
+ }
1932
+ if (!node) {
1933
+ const { dataRegistries } = register;
1934
+ node = this.entityManager.createEntity(WorkflowNodeEntity, {
1935
+ id,
1936
+ document: this,
1937
+ flowNodeType: type,
1938
+ originParent,
1939
+ meta
1940
+ });
1941
+ const datas = dataRegistries ? this.nodeDataRegistries.concat(...dataRegistries) : this.nodeDataRegistries;
1942
+ node.addInitializeData(datas);
1943
+ node.onDispose(() => this.onNodeDisposeEmitter.fire({ node }));
1944
+ this.options.fromNodeJSON?.(node, data, true);
1945
+ isNew = true;
1946
+ } else {
1947
+ this.options.fromNodeJSON?.(node, data, false);
1948
+ }
1949
+ node.initData({
1950
+ originParent,
1951
+ parent,
1952
+ meta,
1953
+ hidden,
1954
+ index
1955
+ });
1956
+ addedNodes?.push(node);
1957
+ if (register.onCreate) {
1958
+ const extendNodes = register.onCreate(node, data);
1959
+ if (extendNodes && addedNodes) {
1960
+ addedNodes.push(...extendNodes);
1961
+ }
1962
+ }
1963
+ if (!ignoreCreateAndUpdateEvent) {
1964
+ if (isNew) {
1965
+ this.onNodeCreateEmitter.fire({
1966
+ node,
1967
+ data,
1968
+ json: data
1969
+ });
1970
+ } else {
1971
+ this.onNodeUpdateEmitter.fire({ node, data, json: data });
1972
+ }
1973
+ }
1974
+ return node;
1975
+ }
1976
+ get layout() {
1977
+ const layout = this.layouts.find((layout2) => layout2.name == this.currentLayoutKey);
1978
+ if (!layout) {
1979
+ throw new Error(`Unknown flow layout: ${this.currentLayoutKey}`);
1980
+ }
1981
+ return layout;
1982
+ }
1983
+ /**
1984
+ * 获取默认的 x y 坐标, 默认为当前画布可视区域中心
1985
+ * @param type
1986
+ * @protected
1987
+ */
1988
+ getNodeDefaultPosition(type) {
1989
+ const { size } = this.getNodeRegistry(type).meta || {};
1990
+ let position = this.playgroundConfig.getViewport(true).center;
1991
+ if (size) {
1992
+ position = {
1993
+ x: position.x,
1994
+ y: position.y - size.height / 2
1995
+ };
1996
+ }
1997
+ return getAntiOverlapPosition(this, position);
1998
+ }
1999
+ /**
2000
+ * 通过类型创建节点, 如果没有提供position 则直接放在画布中间
2001
+ * @param type
2002
+ */
2003
+ createWorkflowNodeByType(type, position, json = {}, parentID) {
2004
+ let id = json.id;
2005
+ if (id === void 0) {
2006
+ do {
2007
+ id = `1${nanoid2()}`;
2008
+ } while (this.entityManager.getEntityById(id));
2009
+ } else {
2010
+ if (this.entityManager.getEntityById(id)) {
2011
+ throw new Error(`[WorkflowDocument.createWorkflowNodeByType] Node Id "${id}" duplicated.`);
2012
+ }
2013
+ }
2014
+ return this.createWorkflowNode(
2015
+ {
2016
+ ...json,
2017
+ id,
2018
+ type,
2019
+ meta: { position, ...json?.meta },
2020
+ // TODO title 和 meta 要从注册数据去拿
2021
+ data: json?.data,
2022
+ blocks: json?.blocks,
2023
+ edges: json?.edges
2024
+ },
2025
+ false,
2026
+ parentID
2027
+ );
2028
+ }
2029
+ getAllNodes() {
2030
+ return this.entityManager.getEntities(WorkflowNodeEntity).filter((n) => n.id !== FlowNodeBaseType.ROOT);
2031
+ }
2032
+ getAllPorts() {
2033
+ return this.entityManager.getEntities(WorkflowPortEntity).filter((p) => p.node.id !== FlowNodeBaseType.ROOT);
2034
+ }
2035
+ /**
2036
+ * 获取画布中的非游离节点
2037
+ * 1. 开始节点
2038
+ * 2. 从开始节点出发能走到的节点
2039
+ * 3. 结束节点
2040
+ * 4. 默认所有子画布内节点为游离节点
2041
+ */
2042
+ getAssociatedNodes() {
2043
+ const allNode = this.getAllNodes();
2044
+ const allLines = this.linesManager.getAllLines().filter((line) => line.from && line.to).map((line) => ({
2045
+ from: line.from.id,
2046
+ to: line.to.id
2047
+ }));
2048
+ const startNodeId = allNode.find((node) => node.isStart).id;
2049
+ const endNodeId = allNode.find((node) => node.isNodeEnd).id;
2050
+ const nodeInContainer = allNode.filter((node) => node.parent?.getNodeMeta().isContainer).map((node) => node.id);
2051
+ const associatedCache = /* @__PURE__ */ new Set([endNodeId, ...nodeInContainer]);
2052
+ const bfs = (nodeId) => {
2053
+ if (associatedCache.has(nodeId)) {
2054
+ return;
2055
+ }
2056
+ associatedCache.add(nodeId);
2057
+ const nextNodes = allLines.reduce((ids, { from, to }) => {
2058
+ if (from === nodeId && !associatedCache.has(to)) {
2059
+ ids.push(to);
2060
+ }
2061
+ return ids;
2062
+ }, []);
2063
+ nextNodes.forEach(bfs);
2064
+ };
2065
+ bfs(startNodeId);
2066
+ const associatedNodes = allNode.filter((node) => associatedCache.has(node.id));
2067
+ return associatedNodes;
2068
+ }
2069
+ /**
2070
+ * 触发渲染
2071
+ */
2072
+ fireRender() {
2073
+ this.entityManager.fireEntityChanged(WorkflowNodeEntity.type);
2074
+ this.entityManager.fireEntityChanged(WorkflowLineEntity.type);
2075
+ this.entityManager.fireEntityChanged(WorkflowPortEntity.type);
2076
+ }
2077
+ fireContentChange(event) {
2078
+ if (this._loading || this.disposed || this.entityManager.changeEntityLocked) {
2079
+ return;
2080
+ }
2081
+ this._onContentChangeEmitter.fire(event);
2082
+ }
2083
+ toNodeJSON(node) {
2084
+ const subCanvas = this.getNodeSubCanvas(node);
2085
+ if (subCanvas?.isCanvas === true) {
2086
+ return this.toNodeJSON(subCanvas.parentNode);
2087
+ }
2088
+ const json = this.toNodeJSONFromOptions(node);
2089
+ const children = this.getNodeChildren(node);
2090
+ const blocks = children.map((child) => this.toNodeJSON(child));
2091
+ const linesMap = /* @__PURE__ */ new Map();
2092
+ children.forEach((child) => {
2093
+ const childLinesData = child.getData(WorkflowNodeLinesData);
2094
+ [...childLinesData.inputLines, ...childLinesData.outputLines].filter(Boolean).forEach((line) => {
2095
+ const lineJSON = this.toLineJSON(line);
2096
+ if (!lineJSON || linesMap.has(line.id)) {
2097
+ return;
2098
+ }
2099
+ linesMap.set(line.id, lineJSON);
2100
+ });
2101
+ });
2102
+ const edges = Array.from(linesMap.values());
2103
+ if (blocks.length > 0) json.blocks = blocks;
2104
+ if (edges.length > 0) json.edges = edges;
2105
+ return json;
2106
+ }
2107
+ /**
2108
+ * 节点转换为JSON, 没有format的过程
2109
+ * @param node
2110
+ * @returns
2111
+ */
2112
+ toNodeJSONFromOptions(node) {
2113
+ if (this.options.toNodeJSON) {
2114
+ return this.options.toNodeJSON(node);
2115
+ }
2116
+ return WorkflowDocumentOptionsDefault.toNodeJSON(node);
2117
+ }
2118
+ copyNode(node, newNodeId, format, position) {
2119
+ let json = this.toNodeJSON(node);
2120
+ if (format) {
2121
+ json = format(json);
2122
+ }
2123
+ position = position || {
2124
+ x: json.meta.position.x + 30,
2125
+ y: json.meta.position.y + 30
2126
+ };
2127
+ return this.createWorkflowNode(
2128
+ {
2129
+ id: newNodeId || `1${nanoid2()}`,
2130
+ type: node.flowNodeType,
2131
+ meta: {
2132
+ ...json.meta,
2133
+ position
2134
+ },
2135
+ data: json.data,
2136
+ blocks: json.blocks,
2137
+ edges: json.edges
2138
+ },
2139
+ true,
2140
+ node.parent?.id
2141
+ );
2142
+ }
2143
+ copyNodeFromJSON(flowNodeType, nodeJSON, newNodeId, position, parentId) {
2144
+ position = position || {
2145
+ x: nodeJSON.meta.position.x + 30,
2146
+ y: nodeJSON.meta.position.y + 30
2147
+ };
2148
+ return this.createWorkflowNode(
2149
+ {
2150
+ id: newNodeId || `1${nanoid2()}`,
2151
+ type: flowNodeType,
2152
+ meta: {
2153
+ ...nodeJSON.meta,
2154
+ position
2155
+ },
2156
+ data: nodeJSON.data,
2157
+ blocks: nodeJSON.blocks,
2158
+ edges: nodeJSON.edges
2159
+ },
2160
+ true,
2161
+ parentId
2162
+ );
2163
+ }
2164
+ canRemove(node, silent) {
2165
+ const meta = node.getNodeMeta();
2166
+ if (meta.deleteDisable) {
2167
+ return false;
2168
+ }
2169
+ if (this.options.canDeleteNode && !this.options.canDeleteNode(node, silent)) {
2170
+ return false;
2171
+ }
2172
+ return true;
2173
+ }
2174
+ /**
2175
+ * 判断端口是否为错误态
2176
+ */
2177
+ isErrorPort(port) {
2178
+ if (typeof this.options.isErrorPort === "function") {
2179
+ return this.options.isErrorPort(port);
2180
+ }
2181
+ return false;
2182
+ }
2183
+ /**
2184
+ * 导出数据
2185
+ */
2186
+ toJSON() {
2187
+ const rootJSON = this.toNodeJSON(this.root);
2188
+ return {
2189
+ nodes: rootJSON.blocks ?? [],
2190
+ edges: rootJSON.edges ?? []
2191
+ };
2192
+ }
2193
+ dispose() {
2194
+ super.dispose();
2195
+ this._onReloadEmitter.dispose();
2196
+ }
2197
+ /**
2198
+ * 逐层创建节点和线条
2199
+ */
2200
+ renderJSON(json, options) {
2201
+ const { parent = this.root, isClone = false } = options ?? {};
2202
+ const containerID = this.getNodeSubCanvas(parent)?.canvasNode.id ?? parent.id;
2203
+ const nodes = json.nodes.map(
2204
+ (nodeJSON) => this.createWorkflowNode(nodeJSON, isClone, containerID)
2205
+ );
2206
+ const edges = json.edges.map((edge) => this.createWorkflowLine(edge, containerID)).filter(Boolean);
2207
+ return { nodes, edges };
2208
+ }
2209
+ getNodeSubCanvas(node) {
2210
+ if (!node) return;
2211
+ const nodeMeta = node.getNodeMeta();
2212
+ const subCanvas = nodeMeta.subCanvas?.(node);
2213
+ return subCanvas;
2214
+ }
2215
+ getNodeChildren(node) {
2216
+ if (!node) return [];
2217
+ const subCanvas = this.getNodeSubCanvas(node);
2218
+ const childrenWithCanvas = subCanvas ? subCanvas.canvasNode.collapsedChildren : node.collapsedChildren;
2219
+ const children = childrenWithCanvas.filter((child) => {
2220
+ const childMeta = child.getNodeMeta();
2221
+ return !childMeta.subCanvas?.(node)?.isCanvas;
2222
+ }).filter(Boolean);
2223
+ return children;
2224
+ }
2225
+ toLineJSON(line) {
2226
+ const lineJSON = line.toJSON();
2227
+ if (!line.from || !line.info.from || !line.fromPort || !line.to || !line.info.to || !line.toPort) {
2228
+ return;
2229
+ }
2230
+ const fromSubCanvas = this.getNodeSubCanvas(line.from);
2231
+ const toSubCanvas = this.getNodeSubCanvas(line.to);
2232
+ if (fromSubCanvas && !fromSubCanvas.isCanvas && toSubCanvas && toSubCanvas.isCanvas) {
2233
+ return;
2234
+ }
2235
+ if (line.from === line.to.parent && fromSubCanvas) {
2236
+ return {
2237
+ ...lineJSON,
2238
+ sourceNodeID: fromSubCanvas.parentNode.id
2239
+ };
2240
+ }
2241
+ if (line.to === line.from.parent && toSubCanvas) {
2242
+ return {
2243
+ ...lineJSON,
2244
+ targetNodeID: toSubCanvas.parentNode.id
2245
+ };
2246
+ }
2247
+ return lineJSON;
2248
+ }
2249
+ createWorkflowLine(json, parentId) {
2250
+ const fromNode = this.getNode(json.sourceNodeID);
2251
+ const toNode = this.getNode(json.targetNodeID);
2252
+ if (!fromNode || !toNode) {
2253
+ return;
2254
+ }
2255
+ const lineInfo = {
2256
+ from: json.sourceNodeID,
2257
+ fromPort: json.sourcePortID,
2258
+ to: json.targetNodeID,
2259
+ toPort: json.targetPortID
2260
+ };
2261
+ if (!parentId) {
2262
+ return this.linesManager.createLine(lineInfo);
2263
+ }
2264
+ const canvasNode = this.getNode(parentId);
2265
+ if (!canvasNode) {
2266
+ return this.linesManager.createLine(lineInfo);
2267
+ }
2268
+ const parentSubCanvas = this.getNodeSubCanvas(canvasNode);
2269
+ if (!parentSubCanvas) {
2270
+ return this.linesManager.createLine(lineInfo);
2271
+ }
2272
+ if (lineInfo.from === parentSubCanvas.parentNode.id) {
2273
+ return this.linesManager.createLine({
2274
+ ...lineInfo,
2275
+ from: parentSubCanvas.canvasNode.id
2276
+ });
2277
+ }
2278
+ if (lineInfo.to === parentSubCanvas.parentNode.id) {
2279
+ return this.linesManager.createLine({
2280
+ ...lineInfo,
2281
+ to: parentSubCanvas.canvasNode.id
2282
+ });
2283
+ }
2284
+ return this.linesManager.createLine(lineInfo);
2285
+ }
2286
+ };
2287
+ __decorateClass([
2288
+ inject5(WorkflowLinesManager)
2289
+ ], WorkflowDocument.prototype, "linesManager", 2);
2290
+ __decorateClass([
2291
+ inject5(PlaygroundConfigEntity4)
2292
+ ], WorkflowDocument.prototype, "playgroundConfig", 2);
2293
+ __decorateClass([
2294
+ injectPlaygroundContext()
2295
+ ], WorkflowDocument.prototype, "playgroundContext", 2);
2296
+ __decorateClass([
2297
+ inject5(WorkflowDocumentOptions)
2298
+ ], WorkflowDocument.prototype, "options", 2);
2299
+ __decorateClass([
2300
+ inject5(NodeEngineContext),
2301
+ optional()
2302
+ ], WorkflowDocument.prototype, "nodeEngineContext", 2);
2303
+ __decorateClass([
2304
+ inject5(WorkflowSelectService)
2305
+ ], WorkflowDocument.prototype, "selectServices", 2);
2306
+ __decorateClass([
2307
+ postConstruct()
2308
+ ], WorkflowDocument.prototype, "init", 1);
2309
+ WorkflowDocument = __decorateClass([
2310
+ injectable5()
2311
+ ], WorkflowDocument);
2312
+
2313
+ // src/service/workflow-drag-service.ts
2314
+ var DRAG_TIMEOUT = 100;
2315
+ var DRAG_MIN_DELTA = 5;
2316
+ function checkDragSuccess(time, e, originLine) {
2317
+ if (!originLine || time > DRAG_TIMEOUT || Math.abs(e.endPos.x - e.startPos.x) >= DRAG_MIN_DELTA || Math.abs(e.endPos.y - e.startPos.y) >= DRAG_MIN_DELTA) {
2318
+ return true;
2319
+ }
2320
+ return false;
2321
+ }
2322
+ var WorkflowDragService = class {
2323
+ constructor() {
2324
+ this._onDragLineEventEmitter = new Emitter5();
2325
+ this.onDragLineEventChange = this._onDragLineEventEmitter.event;
2326
+ this.isDragging = false;
2327
+ this._nodesDragEmitter = new Emitter5();
2328
+ this.onNodesDrag = this._nodesDragEmitter.event;
2329
+ this._toDispose = new DisposableCollection2();
2330
+ this._droppableTransforms = [];
2331
+ this.posAdjusters = /* @__PURE__ */ new Set();
2332
+ this._onDragLineEndCallbacks = /* @__PURE__ */ new Map();
2333
+ }
2334
+ init() {
2335
+ this._toDispose.pushAll([this._onDragLineEventEmitter, this._nodesDragEmitter]);
2336
+ if (this.options.onDragLineEnd) {
2337
+ this._toDispose.push(this.onDragLineEnd(this.options.onDragLineEnd));
2338
+ }
2339
+ }
2340
+ dispose() {
2341
+ this._toDispose.dispose();
2342
+ }
2343
+ /**
2344
+ * 拖拽选中节点
2345
+ * @param triggerEvent
2346
+ */
2347
+ async startDragSelectedNodes(triggerEvent) {
2348
+ let { selectedNodes } = this.selectService;
2349
+ if (selectedNodes.length === 0 || this.playgroundConfig.readonly || this.playgroundConfig.disabled || this.isDragging) {
2350
+ return Promise.resolve(false);
2351
+ }
2352
+ this.isDragging = true;
2353
+ const sameParent = this.childrenOfContainer(selectedNodes);
2354
+ if (sameParent && sameParent.flowNodeType !== FlowNodeBaseType2.ROOT) {
2355
+ selectedNodes = [sameParent];
2356
+ }
2357
+ let startPosition = this.getNodesPosition(selectedNodes);
2358
+ let startPositions = selectedNodes.map((node) => {
2359
+ const transform = node.getData(TransformData8);
2360
+ return { x: transform.position.x, y: transform.position.y };
2361
+ });
2362
+ let dragSuccess = false;
2363
+ const startTime = Date.now();
2364
+ const dragger = new PlaygroundDrag({
2365
+ onDragStart: (dragEvent) => {
2366
+ this._nodesDragEmitter.fire({
2367
+ type: "onDragStart",
2368
+ nodes: selectedNodes,
2369
+ startPositions,
2370
+ dragEvent,
2371
+ triggerEvent,
2372
+ dragger
2373
+ });
2374
+ },
2375
+ onDrag: (dragEvent) => {
2376
+ if (!dragSuccess && checkDragSuccess(Date.now() - startTime, dragEvent)) {
2377
+ dragSuccess = true;
2378
+ }
2379
+ const offset = this.getDragPosOffset({
2380
+ event: dragEvent,
2381
+ selectedNodes,
2382
+ startPosition
2383
+ });
2384
+ const positions = [];
2385
+ selectedNodes.forEach((node, index) => {
2386
+ const transform = node.getData(TransformData8);
2387
+ const nodeStartPosition = startPositions[index];
2388
+ const newPosition = {
2389
+ x: nodeStartPosition.x + offset.x,
2390
+ y: nodeStartPosition.y + offset.y
2391
+ };
2392
+ transform.update({
2393
+ position: newPosition
2394
+ });
2395
+ this.document.layout.updateAffectedTransform(node);
2396
+ positions.push(newPosition);
2397
+ });
2398
+ this._nodesDragEmitter.fire({
2399
+ type: "onDragging",
2400
+ nodes: selectedNodes,
2401
+ startPositions,
2402
+ positions,
2403
+ dragEvent,
2404
+ triggerEvent,
2405
+ dragger
2406
+ });
2407
+ },
2408
+ onDragEnd: (dragEvent) => {
2409
+ this.isDragging = false;
2410
+ this._nodesDragEmitter.fire({
2411
+ type: "onDragEnd",
2412
+ nodes: selectedNodes,
2413
+ startPositions,
2414
+ dragEvent,
2415
+ triggerEvent,
2416
+ dragger
2417
+ });
2418
+ }
2419
+ });
2420
+ const { clientX, clientY } = MouseTouchEvent.getEventCoord(triggerEvent);
2421
+ return dragger.start(clientX, clientY, this.playgroundConfig)?.then(() => dragSuccess);
2422
+ }
2423
+ /**
2424
+ * 通过拖入卡片添加
2425
+ * @param type
2426
+ * @param event
2427
+ * @param data 节点数据
2428
+ */
2429
+ async dropCard(type, event, data, parent) {
2430
+ const mousePos = this.playgroundConfig.getPosFromMouseEvent(event);
2431
+ if (!this.playgroundConfig.getViewport().contains(mousePos.x, mousePos.y)) {
2432
+ return;
2433
+ }
2434
+ const position = this.adjustSubNodePosition(type, parent, mousePos);
2435
+ const node = await this.document.createWorkflowNodeByType(
2436
+ type,
2437
+ position,
2438
+ data,
2439
+ parent?.id
2440
+ );
2441
+ return node;
2442
+ }
2443
+ /**
2444
+ * 拖拽卡片到画布
2445
+ * 返回创建结果
2446
+ * @param type
2447
+ * @param event
2448
+ */
2449
+ async startDragCard(type, event, data, cloneNode) {
2450
+ let domNode;
2451
+ let startPos = { x: 0, y: 0 };
2452
+ const deferred = new PromiseDeferred();
2453
+ const dragger = new PlaygroundDrag({
2454
+ onDragStart: (e) => {
2455
+ const targetNode = event.currentTarget;
2456
+ domNode = cloneNode ? cloneNode(e) : targetNode.cloneNode(true);
2457
+ const bounds = targetNode.getBoundingClientRect();
2458
+ startPos = { x: bounds.left, y: bounds.top };
2459
+ domUtils2.setStyle(domNode, {
2460
+ zIndex: 1e3,
2461
+ position: "absolute",
2462
+ left: startPos.x,
2463
+ top: startPos.y,
2464
+ boxShadow: "0 6px 8px 0 rgba(28, 31, 35, .2)"
2465
+ });
2466
+ document.body.appendChild(domNode);
2467
+ this.updateDroppableTransforms();
2468
+ },
2469
+ onDrag: (e) => {
2470
+ const deltaX = e.endPos.x - e.startPos.x;
2471
+ const deltaY = e.endPos.y - e.startPos.y;
2472
+ const left = startPos.x + deltaX;
2473
+ const right = startPos.y + deltaY;
2474
+ domNode.style.left = `${left}px`;
2475
+ domNode.style.top = `${right}px`;
2476
+ const { x, y } = this.playgroundConfig.getPosFromMouseEvent(e);
2477
+ const draggingRect = new Rectangle8(x, y, 170, 90);
2478
+ const collisionTransform = this._droppableTransforms.find((transform) => {
2479
+ const { bounds, entity } = transform;
2480
+ const padding = this.document.layout.getPadding(entity);
2481
+ const transformRect = new Rectangle8(
2482
+ bounds.x + padding.left + padding.right,
2483
+ bounds.y,
2484
+ bounds.width,
2485
+ bounds.height
2486
+ );
2487
+ return Rectangle8.intersects(draggingRect, transformRect);
2488
+ });
2489
+ this.updateDropNode(collisionTransform?.entity);
2490
+ },
2491
+ onDragEnd: async (e) => {
2492
+ const dropNode = this._dropNode;
2493
+ const { allowDrop } = this.canDropToNode({
2494
+ dragNodeType: type,
2495
+ dropNodeType: dropNode?.flowNodeType,
2496
+ dropNode
2497
+ });
2498
+ const dragNode = allowDrop ? await this.dropCard(type, e, data, dropNode) : void 0;
2499
+ this.clearDrop();
2500
+ if (dragNode) {
2501
+ domNode.remove();
2502
+ deferred.resolve(dragNode);
2503
+ } else {
2504
+ domNode.style.transition = "all ease .2s";
2505
+ domNode.style.left = `${startPos.x}px`;
2506
+ domNode.style.top = `${startPos.y}px`;
2507
+ const TIMEOUT = 200;
2508
+ await delay2(TIMEOUT);
2509
+ domNode.remove();
2510
+ deferred.resolve();
2511
+ }
2512
+ }
2513
+ });
2514
+ await dragger.start(event.clientX, event.clientY);
2515
+ return deferred.promise;
2516
+ }
2517
+ /**
2518
+ * 如果存在容器节点,且传入鼠标坐标,需要用容器的坐标减去传入的鼠标坐标
2519
+ */
2520
+ adjustSubNodePosition(subNodeType, containerNode, mousePos) {
2521
+ if (!mousePos) {
2522
+ return { x: 0, y: 0 };
2523
+ }
2524
+ if (!subNodeType || !containerNode || containerNode.flowNodeType === FlowNodeBaseType2.ROOT) {
2525
+ return mousePos;
2526
+ }
2527
+ const isParentEmpty = !containerNode.children || containerNode.children.length === 0;
2528
+ const parentPadding = this.document.layout.getPadding(containerNode);
2529
+ const containerWorldTransform = containerNode.transform.transform.worldTransform;
2530
+ if (isParentEmpty) {
2531
+ return {
2532
+ x: 0,
2533
+ y: parentPadding.top
2534
+ };
2535
+ } else {
2536
+ return {
2537
+ x: mousePos.x - containerWorldTransform.tx,
2538
+ y: mousePos.y - containerWorldTransform.ty
2539
+ };
2540
+ }
2541
+ }
2542
+ /**
2543
+ * 注册位置调整
2544
+ */
2545
+ registerPosAdjuster(adjuster) {
2546
+ this.posAdjusters.add(adjuster);
2547
+ return {
2548
+ dispose: () => this.posAdjusters.delete(adjuster)
2549
+ };
2550
+ }
2551
+ /**
2552
+ * 判断是否可以放置节点
2553
+ */
2554
+ canDropToNode(params) {
2555
+ const { canDropToNode } = this.document.options;
2556
+ const { dragNodeType, dropNode } = params;
2557
+ if (canDropToNode) {
2558
+ const result = canDropToNode(params);
2559
+ if (result) {
2560
+ return {
2561
+ allowDrop: true,
2562
+ dropNode
2563
+ };
2564
+ }
2565
+ return {
2566
+ allowDrop: false
2567
+ };
2568
+ }
2569
+ if (!dragNodeType) {
2570
+ return {
2571
+ allowDrop: false,
2572
+ message: "Please select a node to drop"
2573
+ };
2574
+ }
2575
+ return {
2576
+ allowDrop: true,
2577
+ dropNode
2578
+ };
2579
+ }
2580
+ /**
2581
+ * 获取拖拽偏移
2582
+ */
2583
+ getDragPosOffset(params) {
2584
+ const { event, selectedNodes, startPosition } = params;
2585
+ const { finalScale } = this.playgroundConfig;
2586
+ const mouseOffset = {
2587
+ x: (event.endPos.x - event.startPos.x) / finalScale,
2588
+ y: (event.endPos.y - event.startPos.y) / finalScale
2589
+ };
2590
+ const wholePosition = {
2591
+ x: startPosition.x + mouseOffset.x,
2592
+ y: startPosition.y + mouseOffset.y
2593
+ };
2594
+ const adjustedOffsets = Array.from(this.posAdjusters.values()).map(
2595
+ (adjuster) => adjuster({
2596
+ selectedNodes,
2597
+ position: wholePosition
2598
+ })
2599
+ );
2600
+ const offset = adjustedOffsets.reduce(
2601
+ (offset2, adjustOffset) => ({
2602
+ x: offset2.x + adjustOffset.x,
2603
+ y: offset2.y + adjustOffset.y
2604
+ }),
2605
+ mouseOffset
2606
+ );
2607
+ return offset;
2608
+ }
2609
+ updateDroppableTransforms() {
2610
+ this._droppableTransforms = this.document.getRenderDatas(FlowNodeTransformData6, false).filter((transform) => {
2611
+ const { entity } = transform;
2612
+ if (entity.originParent) {
2613
+ return this.nodeSelectable(entity) && this.nodeSelectable(entity.originParent);
2614
+ }
2615
+ return this.nodeSelectable(entity);
2616
+ }).filter((transform) => this.isContainer(transform.entity));
2617
+ }
2618
+ /** 是否容器节点 */
2619
+ isContainer(node) {
2620
+ return node?.getNodeMeta().isContainer ?? false;
2621
+ }
2622
+ /**
2623
+ * 获取节点整体位置
2624
+ */
2625
+ getNodesPosition(nodes) {
2626
+ const selectedBounds = Rectangle8.enlarge(
2627
+ nodes.map((n) => n.getData(FlowNodeTransformData6).bounds)
2628
+ );
2629
+ const position = {
2630
+ x: selectedBounds.x,
2631
+ y: selectedBounds.y
2632
+ };
2633
+ return position;
2634
+ }
2635
+ nodeSelectable(node) {
2636
+ const selectable = node.getNodeMeta().selectable;
2637
+ if (typeof selectable === "function") {
2638
+ return selectable(node);
2639
+ } else {
2640
+ return selectable;
2641
+ }
2642
+ }
2643
+ updateDropNode(node) {
2644
+ if (this._dropNode) {
2645
+ if (this._dropNode.id === node?.id) {
2646
+ return;
2647
+ }
2648
+ this.selectService.clear();
2649
+ }
2650
+ if (node) {
2651
+ this.selectService.selectNode(node);
2652
+ }
2653
+ this._dropNode = node;
2654
+ }
2655
+ clearDrop() {
2656
+ if (this._dropNode) {
2657
+ this.selectService.clear();
2658
+ }
2659
+ this._dropNode = void 0;
2660
+ this._droppableTransforms = [];
2661
+ }
2662
+ setLineColor(line, color) {
2663
+ line.highlightColor = color;
2664
+ this.hoverService.clearHovered();
2665
+ }
2666
+ handleDragOnNode(toNode, fromPort, line, toPort, originLine) {
2667
+ if (toPort && (originLine?.toPort === toPort || toPort.portType === "input" && this.linesManager.canAddLine(fromPort, toPort, true))) {
2668
+ this.hoverService.updateHoveredKey(toPort.id);
2669
+ line.setToPort(toPort);
2670
+ this._onDragLineEventEmitter.fire({
2671
+ type: "onDrag",
2672
+ onDragNodeId: toNode.id
2673
+ });
2674
+ return {
2675
+ hasError: false
2676
+ };
2677
+ } else if (this.isContainer(toNode)) {
2678
+ return {
2679
+ hasError: false
2680
+ };
2681
+ } else {
2682
+ this.setLineColor(line, this.linesManager.lineColor.error);
2683
+ return {
2684
+ hasError: true
2685
+ };
2686
+ }
2687
+ }
2688
+ childrenOfContainer(nodes) {
2689
+ if (nodes.length === 0) {
2690
+ return;
2691
+ }
2692
+ const sourceContainer = nodes[0]?.parent;
2693
+ if (!sourceContainer || sourceContainer.collapsedChildren.length !== nodes.length) {
2694
+ return;
2695
+ }
2696
+ const valid = nodes.every((node) => node?.parent === sourceContainer);
2697
+ if (!valid) {
2698
+ return;
2699
+ }
2700
+ return sourceContainer;
2701
+ }
2702
+ /**
2703
+ * 绘制线条
2704
+ * @param opts
2705
+ * @param event
2706
+ */
2707
+ async startDrawingLine(fromPort, event, originLine) {
2708
+ const isFromInActivePort = !originLine && fromPort.isErrorPort() && fromPort.disabled;
2709
+ if (originLine?.disabled || isFromInActivePort || this.playgroundConfig.readonly || this.playgroundConfig.disabled) {
2710
+ return { dragSuccess: false, newLine: void 0 };
2711
+ }
2712
+ this.selectService.clear();
2713
+ const config = this.playgroundConfig;
2714
+ const deferred = new PromiseDeferred();
2715
+ const preCursor = config.cursor;
2716
+ let line, toPort, toNode, lineErrorReset = false;
2717
+ const startTime = Date.now();
2718
+ let dragSuccess = false;
2719
+ const dragger = new PlaygroundDrag({
2720
+ onDrag: (e) => {
2721
+ if (!line && checkDragSuccess(Date.now() - startTime, e, originLine)) {
2722
+ if (originLine) {
2723
+ originLine.highlightColor = this.linesManager.lineColor.hidden;
2724
+ }
2725
+ dragSuccess = true;
2726
+ line = this.linesManager.createLine({
2727
+ from: fromPort.node.id,
2728
+ fromPort: fromPort.portID,
2729
+ drawingTo: config.getPosFromMouseEvent(event)
2730
+ });
2731
+ if (!line) {
2732
+ return;
2733
+ }
2734
+ config.updateCursor("grab");
2735
+ line.highlightColor = this.linesManager.lineColor.drawing;
2736
+ this.hoverService.updateHoveredKey("");
2737
+ }
2738
+ if (!line) {
2739
+ return;
2740
+ }
2741
+ lineErrorReset = false;
2742
+ const dragPos = config.getPosFromMouseEvent(e);
2743
+ toNode = this.linesManager.getNodeFromMousePos(dragPos);
2744
+ toPort = this.linesManager.getPortFromMousePos(dragPos);
2745
+ if (!toPort) {
2746
+ line.setToPort(void 0);
2747
+ } else if (!this.linesManager.canAddLine(fromPort, toPort, true)) {
2748
+ line.highlightColor = this.linesManager.lineColor.error;
2749
+ lineErrorReset = true;
2750
+ line.setToPort(void 0);
2751
+ } else {
2752
+ line.setToPort(toPort);
2753
+ }
2754
+ this._onDragLineEventEmitter.fire({
2755
+ type: "onDrag"
2756
+ });
2757
+ this.setLineColor(line, this.linesManager.lineColor.drawing);
2758
+ if (toNode && this.canBuildContainerLine(toNode, dragPos)) {
2759
+ toPort = this.getNearestPort(toNode, dragPos);
2760
+ const { hasError } = this.handleDragOnNode(toNode, fromPort, line, toPort, originLine);
2761
+ lineErrorReset = hasError;
2762
+ }
2763
+ if (line.toPort) {
2764
+ line.drawingTo = { x: line.toPort.point.x, y: line.toPort.point.y };
2765
+ } else {
2766
+ line.drawingTo = { x: dragPos.x, y: dragPos.y };
2767
+ }
2768
+ originLine?.validate();
2769
+ line.validate();
2770
+ },
2771
+ // eslint-disable-next-line complexity
2772
+ onDragEnd: async (e) => {
2773
+ const dragPos = config.getPosFromMouseEvent(e);
2774
+ const onDragLineEndCallbacks = Array.from(this._onDragLineEndCallbacks.values());
2775
+ config.updateCursor(preCursor);
2776
+ await Promise.all(
2777
+ onDragLineEndCallbacks.map(
2778
+ (callback) => callback({
2779
+ fromPort,
2780
+ toPort,
2781
+ mousePos: dragPos,
2782
+ line,
2783
+ originLine,
2784
+ event: e
2785
+ })
2786
+ )
2787
+ );
2788
+ line?.dispose();
2789
+ this._onDragLineEventEmitter.fire({
2790
+ type: "onDragEnd"
2791
+ });
2792
+ if (originLine) {
2793
+ originLine.highlightColor = "";
2794
+ }
2795
+ const end = () => {
2796
+ originLine?.validate();
2797
+ deferred.resolve({ dragSuccess });
2798
+ };
2799
+ if (dragSuccess) {
2800
+ if (originLine && originLine.toPort === toPort) {
2801
+ return end();
2802
+ }
2803
+ if (toPort && toPort.portType !== "input") {
2804
+ return end();
2805
+ }
2806
+ const newLineInfo = toPort ? {
2807
+ from: fromPort.node.id,
2808
+ fromPort: fromPort.portID,
2809
+ to: toPort.node.id,
2810
+ toPort: toPort.portID
2811
+ } : void 0;
2812
+ const isReset = originLine && toPort;
2813
+ if (isReset && !this.linesManager.canReset(
2814
+ originLine.fromPort,
2815
+ originLine.toPort,
2816
+ toPort
2817
+ )) {
2818
+ return end();
2819
+ }
2820
+ if (originLine && (!this.linesManager.canRemove(originLine, newLineInfo, false) || lineErrorReset)) {
2821
+ return end();
2822
+ } else {
2823
+ originLine?.dispose();
2824
+ }
2825
+ if (!toPort || !this.linesManager.canAddLine(fromPort, toPort, false)) {
2826
+ return end();
2827
+ }
2828
+ const newLine = this.linesManager.createLine(newLineInfo);
2829
+ if (!newLine) {
2830
+ end();
2831
+ }
2832
+ deferred.resolve({
2833
+ dragSuccess,
2834
+ newLine
2835
+ });
2836
+ } else {
2837
+ end();
2838
+ }
2839
+ }
2840
+ });
2841
+ const { clientX, clientY } = MouseTouchEvent.getEventCoord(event);
2842
+ await dragger.start(clientX, clientY, config);
2843
+ return deferred.promise;
2844
+ }
2845
+ /**
2846
+ * 重新连接线条
2847
+ * @param line
2848
+ * @param e
2849
+ */
2850
+ async resetLine(line, e) {
2851
+ const { fromPort } = line;
2852
+ const { dragSuccess } = await this.startDrawingLine(fromPort, e, line);
2853
+ if (!dragSuccess) {
2854
+ this.selectService.select(line);
2855
+ }
2856
+ }
2857
+ /** 线条拖拽结束 */
2858
+ onDragLineEnd(callback) {
2859
+ const id = nanoid3();
2860
+ this._onDragLineEndCallbacks.set(id, callback);
2861
+ return {
2862
+ dispose: () => {
2863
+ this._onDragLineEndCallbacks.delete(id);
2864
+ }
2865
+ };
2866
+ }
2867
+ /** 能否建立容器连线 */
2868
+ canBuildContainerLine(node, mousePos) {
2869
+ const isContainer = this.isContainer(node);
2870
+ if (!isContainer) {
2871
+ return true;
2872
+ }
2873
+ const { padding, bounds } = node.transform;
2874
+ const contentRect = new Rectangle8(bounds.x, bounds.y, padding.left * 2 / 3, bounds.height);
2875
+ return contentRect.contains(mousePos.x, mousePos.y);
2876
+ }
2877
+ /** 获取最近的 port */
2878
+ getNearestPort(node, mousePos) {
2879
+ const portsData = node.getData(WorkflowNodePortsData);
2880
+ const distanceSortedPorts = portsData.inputPorts.sort((a, b) => {
2881
+ const aDistance = Math.abs(mousePos.y - a.point.y);
2882
+ const bDistance = Math.abs(mousePos.y - b.point.y);
2883
+ return aDistance - bDistance;
2884
+ });
2885
+ return distanceSortedPorts[0];
2886
+ }
2887
+ };
2888
+ __decorateClass([
2889
+ inject6(PlaygroundConfigEntity5)
2890
+ ], WorkflowDragService.prototype, "playgroundConfig", 2);
2891
+ __decorateClass([
2892
+ inject6(WorkflowHoverService)
2893
+ ], WorkflowDragService.prototype, "hoverService", 2);
2894
+ __decorateClass([
2895
+ inject6(WorkflowDocument)
2896
+ ], WorkflowDragService.prototype, "document", 2);
2897
+ __decorateClass([
2898
+ inject6(WorkflowLinesManager)
2899
+ ], WorkflowDragService.prototype, "linesManager", 2);
2900
+ __decorateClass([
2901
+ inject6(CommandService)
2902
+ ], WorkflowDragService.prototype, "commandService", 2);
2903
+ __decorateClass([
2904
+ inject6(WorkflowSelectService)
2905
+ ], WorkflowDragService.prototype, "selectService", 2);
2906
+ __decorateClass([
2907
+ inject6(FlowOperationBaseService)
2908
+ ], WorkflowDragService.prototype, "operationService", 2);
2909
+ __decorateClass([
2910
+ inject6(WorkflowDocumentOptions)
2911
+ ], WorkflowDragService.prototype, "options", 2);
2912
+ __decorateClass([
2913
+ postConstruct2()
2914
+ ], WorkflowDragService.prototype, "init", 1);
2915
+ WorkflowDragService = __decorateClass([
2916
+ injectable6()
2917
+ ], WorkflowDragService);
2918
+
2919
+ // src/service/workflow-reset-layout-service.ts
2920
+ import { inject as inject7, injectable as injectable7, postConstruct as postConstruct3 } from "inversify";
2921
+ import { PlaygroundConfigEntity as PlaygroundConfigEntity6 } from "@flowgram.ai/core";
2922
+ import { EntityManager as EntityManager3 } from "@flowgram.ai/core";
2923
+ import { DisposableCollection as DisposableCollection3, Emitter as Emitter6 } from "@flowgram.ai/utils";
2924
+
2925
+ // src/utils/layout-to-positions.ts
2926
+ import { FlowNodeTransformData as FlowNodeTransformData7 } from "@flowgram.ai/document";
2927
+ import { TransformData as TransformData9, startTween } from "@flowgram.ai/core";
2928
+ var layoutToPositions = async (nodes, nodePositionMap) => {
2929
+ const newNodePositionMap = {};
2930
+ nodes.forEach((node) => {
2931
+ const transform = node.getData(TransformData9);
2932
+ const nodeTransform = node.getData(FlowNodeTransformData7);
2933
+ newNodePositionMap[node.id] = {
2934
+ x: transform.position.x,
2935
+ y: transform.position.y + nodeTransform.bounds.height / 2
2936
+ };
2937
+ });
2938
+ return new Promise((resolve) => {
2939
+ startTween({
2940
+ from: { d: 0 },
2941
+ to: { d: 100 },
2942
+ duration: 300,
2943
+ onUpdate: (v) => {
2944
+ nodes.forEach((node) => {
2945
+ const transform = node.getData(TransformData9);
2946
+ const deltaX = (nodePositionMap[node.id].x - transform.position.x) * v.d / 100;
2947
+ const deltaY = (nodePositionMap[node.id].y - transform.bounds.height / 2 - transform.position.y) * v.d / 100;
2948
+ transform.update({
2949
+ position: {
2950
+ x: transform.position.x + deltaX,
2951
+ y: transform.position.y + deltaY
2952
+ }
2953
+ });
2954
+ const document2 = node.document;
2955
+ document2.layout.updateAffectedTransform(node);
2956
+ });
2957
+ },
2958
+ onComplete: () => {
2959
+ resolve(newNodePositionMap);
2960
+ }
2961
+ });
2962
+ });
2963
+ };
2964
+
2965
+ // src/service/workflow-reset-layout-service.ts
2966
+ var WorkflowResetLayoutService = class {
2967
+ constructor() {
2968
+ this._resetLayoutEmitter = new Emitter6();
2969
+ /**
2970
+ * reset layout事件
2971
+ */
2972
+ this.onResetLayout = this._resetLayoutEmitter.event;
2973
+ this._toDispose = new DisposableCollection3();
2974
+ }
2975
+ init() {
2976
+ this._toDispose.push(this._resetLayoutEmitter);
2977
+ }
2978
+ /**
2979
+ * 触发重置布局
2980
+ * @param nodeIds 节点id
2981
+ * @param positionMap 新布局数据
2982
+ * @param oldPositionMap 老布局数据
2983
+ */
2984
+ fireResetLayout(nodeIds, positionMap, oldPositionMap) {
2985
+ this._resetLayoutEmitter.fire({
2986
+ nodeIds,
2987
+ positionMap,
2988
+ oldPositionMap
2989
+ });
2990
+ }
2991
+ /**
2992
+ * 根据数据重新布局
2993
+ * @param positionMap
2994
+ * @returns
2995
+ */
2996
+ async layoutToPositions(nodeIds, positionMap) {
2997
+ const nodes = nodeIds.map((id) => this._entityManager.getEntityById(id)).filter(Boolean);
2998
+ const positions = await layoutToPositions(nodes, positionMap);
2999
+ fitView(this._document, this._config, true);
3000
+ return positions;
3001
+ }
3002
+ /**
3003
+ * 销毁
3004
+ */
3005
+ dispose() {
3006
+ this._toDispose.dispose();
3007
+ }
3008
+ };
3009
+ __decorateClass([
3010
+ inject7(PlaygroundConfigEntity6)
3011
+ ], WorkflowResetLayoutService.prototype, "_config", 2);
3012
+ __decorateClass([
3013
+ inject7(WorkflowDocument)
3014
+ ], WorkflowResetLayoutService.prototype, "_document", 2);
3015
+ __decorateClass([
3016
+ inject7(EntityManager3)
3017
+ ], WorkflowResetLayoutService.prototype, "_entityManager", 2);
3018
+ __decorateClass([
3019
+ postConstruct3()
3020
+ ], WorkflowResetLayoutService.prototype, "init", 1);
3021
+ WorkflowResetLayoutService = __decorateClass([
3022
+ injectable7()
3023
+ ], WorkflowResetLayoutService);
3024
+
3025
+ // src/service/workflow-operation-base-service.ts
3026
+ import { inject as inject8 } from "inversify";
3027
+ import { Emitter as Emitter7 } from "@flowgram.ai/utils";
3028
+ import { FlowOperationBaseServiceImpl } from "@flowgram.ai/document";
3029
+ import { TransformData as TransformData10 } from "@flowgram.ai/core";
3030
+ var WorkflowOperationBaseServiceImpl = class extends FlowOperationBaseServiceImpl {
3031
+ constructor() {
3032
+ super(...arguments);
3033
+ this.onNodePostionUpdateEmitter = new Emitter7();
3034
+ this.onNodePostionUpdate = this.onNodePostionUpdateEmitter.event;
3035
+ }
3036
+ updateNodePosition(nodeOrId, position) {
3037
+ const node = this.toNodeEntity(nodeOrId);
3038
+ if (!node) {
3039
+ return;
3040
+ }
3041
+ const transformData = node.getData(TransformData10);
3042
+ const oldPosition = {
3043
+ x: transformData.position.x,
3044
+ y: transformData.position.y
3045
+ };
3046
+ transformData.update({
3047
+ position
3048
+ });
3049
+ this.onNodePostionUpdateEmitter.fire({
3050
+ node,
3051
+ oldPosition,
3052
+ newPosition: position
3053
+ });
3054
+ }
3055
+ };
3056
+ __decorateClass([
3057
+ inject8(WorkflowDocument)
3058
+ ], WorkflowOperationBaseServiceImpl.prototype, "document", 2);
3059
+
3060
+ // src/hooks/use-playground-readonly-state.ts
3061
+ import { useEffect } from "react";
3062
+ import { usePlayground, useRefresh } from "@flowgram.ai/core";
3063
+ function usePlaygroundReadonlyState(listenChange) {
3064
+ const playground = usePlayground();
3065
+ const refresh = useRefresh();
3066
+ useEffect(() => {
3067
+ let dispose = void 0;
3068
+ if (listenChange) {
3069
+ dispose = playground.config.onReadonlyOrDisabledChange(() => refresh());
3070
+ }
3071
+ return () => dispose?.dispose();
3072
+ }, [listenChange]);
3073
+ return playground.config.readonly;
3074
+ }
3075
+
3076
+ // src/hooks/use-node-render.tsx
3077
+ function checkTargetDraggable(el) {
3078
+ return el && el.tagName !== "INPUT" && el.tagName !== "TEXTAREA" && !el.closest(".flow-canvas-not-draggable");
3079
+ }
3080
+ function useNodeRender(nodeFromProps) {
3081
+ const node = nodeFromProps || useContext(PlaygroundEntityContext);
3082
+ const renderData = node.getData(FlowNodeRenderData3);
3083
+ const portsData = node.getData(WorkflowNodePortsData);
3084
+ const readonly = usePlaygroundReadonlyState();
3085
+ const dragService = useService(WorkflowDragService);
3086
+ const selectionService = useService(WorkflowSelectService);
3087
+ const isDragging = useRef(false);
3088
+ const [formValueVersion, updateFormValueVersion] = useState(0);
3089
+ const formValueDependRef = useRef(false);
3090
+ formValueDependRef.current = false;
3091
+ const nodeRef = useRef(null);
3092
+ const [linkingNodeId, setLinkingNodeId] = useState("");
3093
+ useEffect2(() => {
3094
+ const disposable = dragService.onDragLineEventChange(({ type, onDragNodeId }) => {
3095
+ if (type === "onDrag") {
3096
+ setLinkingNodeId(onDragNodeId || "");
3097
+ } else {
3098
+ setLinkingNodeId("");
3099
+ }
3100
+ });
3101
+ return () => {
3102
+ disposable.dispose();
3103
+ };
3104
+ }, []);
3105
+ const startDrag = useCallback(
3106
+ (e) => {
3107
+ MouseTouchEvent2.preventDefault(e);
3108
+ if (!selectionService.isSelected(node.id)) {
3109
+ selectNode(e);
3110
+ }
3111
+ if (!MouseTouchEvent2.isTouchEvent(e)) {
3112
+ if (!checkTargetDraggable(e.target) || !checkTargetDraggable(document.activeElement)) {
3113
+ return;
3114
+ }
3115
+ }
3116
+ isDragging.current = true;
3117
+ dragService.startDragSelectedNodes(e)?.finally(
3118
+ () => setTimeout(() => {
3119
+ isDragging.current = false;
3120
+ })
3121
+ );
3122
+ },
3123
+ [dragService, node]
3124
+ );
3125
+ const selectNode = useCallback(
3126
+ (e) => {
3127
+ if (isDragging.current) {
3128
+ return;
3129
+ }
3130
+ if (e.shiftKey) {
3131
+ selectionService.toggleSelect(node);
3132
+ } else {
3133
+ selectionService.selectNode(node);
3134
+ }
3135
+ if (e.target) {
3136
+ e.target.focus();
3137
+ }
3138
+ },
3139
+ [node]
3140
+ );
3141
+ const deleteNode = useCallback(() => node.dispose(), [node]);
3142
+ useListenEvents(portsData.onDataChange);
3143
+ const isFirefox = navigator?.userAgent?.includes?.("Firefox");
3144
+ const onFocus = useCallback(() => {
3145
+ if (isFirefox) {
3146
+ nodeRef.current?.setAttribute("draggable", "false");
3147
+ }
3148
+ }, []);
3149
+ const onBlur = useCallback(() => {
3150
+ if (isFirefox) {
3151
+ nodeRef.current?.setAttribute("draggable", "true");
3152
+ }
3153
+ }, []);
3154
+ const getExtInfo = useCallback(() => node.getExtInfo(), [node]);
3155
+ const updateExtInfo = useCallback(
3156
+ (data) => {
3157
+ node.updateExtInfo(data);
3158
+ },
3159
+ [node]
3160
+ );
3161
+ const form = useMemo(() => getNodeForm(node), [node]);
3162
+ const formState = useObserve(form?.state);
3163
+ const toggleExpand = useCallback(() => {
3164
+ renderData.toggleExpand();
3165
+ }, [renderData]);
3166
+ const selected = selectionService.isSelected(node.id);
3167
+ const activated = selectionService.isActivated(node.id);
3168
+ const expanded = renderData.expanded;
3169
+ useEffect2(() => {
3170
+ const toDispose = form?.onFormValuesChange(() => {
3171
+ if (formValueDependRef.current) {
3172
+ updateFormValueVersion((v) => v + 1);
3173
+ }
3174
+ });
3175
+ return () => toDispose?.dispose();
3176
+ }, [form]);
3177
+ return useMemo(
3178
+ () => ({
3179
+ id: node.id,
3180
+ type: node.flowNodeType,
3181
+ get data() {
3182
+ if (form) {
3183
+ formValueDependRef.current = true;
3184
+ return form.values;
3185
+ }
3186
+ return getExtInfo();
3187
+ },
3188
+ updateData(values) {
3189
+ if (form) {
3190
+ form.updateFormValues(values);
3191
+ } else {
3192
+ updateExtInfo(values);
3193
+ }
3194
+ },
3195
+ node,
3196
+ selected,
3197
+ activated,
3198
+ expanded,
3199
+ startDrag,
3200
+ get ports() {
3201
+ return portsData.allPorts;
3202
+ },
3203
+ deleteNode,
3204
+ selectNode,
3205
+ readonly,
3206
+ linkingNodeId,
3207
+ nodeRef,
3208
+ onFocus,
3209
+ onBlur,
3210
+ getExtInfo,
3211
+ updateExtInfo,
3212
+ toggleExpand,
3213
+ get form() {
3214
+ if (!form) return void 0;
3215
+ return {
3216
+ ...form,
3217
+ get values() {
3218
+ formValueDependRef.current = true;
3219
+ return form.values;
3220
+ },
3221
+ get state() {
3222
+ return formState;
3223
+ }
3224
+ };
3225
+ }
3226
+ }),
3227
+ [
3228
+ node,
3229
+ selected,
3230
+ activated,
3231
+ expanded,
3232
+ startDrag,
3233
+ deleteNode,
3234
+ selectNode,
3235
+ readonly,
3236
+ linkingNodeId,
3237
+ nodeRef,
3238
+ onFocus,
3239
+ onBlur,
3240
+ getExtInfo,
3241
+ updateExtInfo,
3242
+ toggleExpand,
3243
+ formValueVersion
3244
+ ]
3245
+ );
3246
+ }
3247
+
3248
+ // src/hooks/use-current-dom-node.ts
3249
+ import { FlowNodeRenderData as FlowNodeRenderData4 } from "@flowgram.ai/document";
3250
+ import { useEntityFromContext } from "@flowgram.ai/core";
3251
+ function useCurrentDomNode() {
3252
+ const entity = useEntityFromContext();
3253
+ const renderData = entity.getData(FlowNodeRenderData4);
3254
+ return renderData.node;
3255
+ }
3256
+
3257
+ // src/hooks/use-current-entity.ts
3258
+ import { useEntityFromContext as useEntityFromContext2 } from "@flowgram.ai/core";
3259
+ function useCurrentEntity() {
3260
+ return useEntityFromContext2();
3261
+ }
3262
+
3263
+ // src/hooks/use-workflow-document.ts
3264
+ import { useService as useService2 } from "@flowgram.ai/core";
3265
+ function useWorkflowDocument() {
3266
+ return useService2(WorkflowDocument);
3267
+ }
3268
+
3269
+ // src/constants.ts
3270
+ var EditorCursorState = /* @__PURE__ */ ((EditorCursorState2) => {
3271
+ EditorCursorState2["GRAB"] = "GRAB";
3272
+ EditorCursorState2["SELECT"] = "SELECT";
3273
+ return EditorCursorState2;
3274
+ })(EditorCursorState || {});
3275
+ var InteractiveType = /* @__PURE__ */ ((InteractiveType2) => {
3276
+ InteractiveType2["MOUSE"] = "MOUSE";
3277
+ InteractiveType2["PAD"] = "PAD";
3278
+ return InteractiveType2;
3279
+ })(InteractiveType || {});
3280
+
3281
+ // src/workflow-document-container-module.ts
3282
+ import { ContainerModule } from "inversify";
3283
+ import { bindContributions } from "@flowgram.ai/utils";
3284
+ import { FlowDocument as FlowDocument2, FlowDocumentContribution } from "@flowgram.ai/document";
3285
+
3286
+ // src/workflow-document-contribution.ts
3287
+ import { injectable as injectable8, inject as inject9 } from "inversify";
3288
+ import {
3289
+ FlowNodeRenderData as FlowNodeRenderData5,
3290
+ FlowNodeTransformData as FlowNodeTransformData8
3291
+ } from "@flowgram.ai/document";
3292
+ var WorkflowDocumentContribution = class {
3293
+ registerDocument(document2) {
3294
+ document2.registerNodeDatas(
3295
+ FlowNodeTransformData8,
3296
+ FlowNodeRenderData5,
3297
+ WorkflowNodePortsData,
3298
+ WorkflowNodeLinesData
3299
+ );
3300
+ document2.registerLayout(this.freeLayout);
3301
+ }
3302
+ };
3303
+ __decorateClass([
3304
+ inject9(FreeLayout)
3305
+ ], WorkflowDocumentContribution.prototype, "freeLayout", 2);
3306
+ WorkflowDocumentContribution = __decorateClass([
3307
+ injectable8()
3308
+ ], WorkflowDocumentContribution);
3309
+
3310
+ // src/utils/get-url-params.ts
3311
+ function getUrlParams() {
3312
+ return location.search.replace(/^\?/, "").split("&").reduce((res, key) => {
3313
+ const [k, v] = key.split("=");
3314
+ res[k] = v;
3315
+ return res;
3316
+ }, {});
3317
+ }
3318
+
3319
+ // src/workflow-document-container-module.ts
3320
+ var WorkflowDocumentContainerModule = new ContainerModule(
3321
+ (bind, unbind, isBound, rebind) => {
3322
+ bind(WorkflowDocument).toSelf().inSingletonScope();
3323
+ bind(WorkflowLinesManager).toSelf().inSingletonScope();
3324
+ bind(FreeLayout).toSelf().inSingletonScope();
3325
+ bind(WorkflowDragService).toSelf().inSingletonScope();
3326
+ bind(WorkflowSelectService).toSelf().inSingletonScope();
3327
+ bind(WorkflowHoverService).toSelf().inSingletonScope();
3328
+ bind(WorkflowResetLayoutService).toSelf().inSingletonScope();
3329
+ bind(WorkflowOperationBaseService).to(WorkflowOperationBaseServiceImpl).inSingletonScope();
3330
+ bind(URLParams).toDynamicValue(() => getUrlParams()).inSingletonScope();
3331
+ bindContributions(bind, WorkflowDocumentContribution, [FlowDocumentContribution]);
3332
+ bind(WorkflowDocumentOptions).toConstantValue({
3333
+ ...WorkflowDocumentOptionsDefault
3334
+ });
3335
+ rebind(FlowDocument2).toService(WorkflowDocument);
3336
+ bind(WorkflowDocumentProvider).toDynamicValue((ctx) => () => ctx.container.get(WorkflowDocument)).inSingletonScope();
3337
+ }
3338
+ );
3339
+
3340
+ // src/utils/simple-line.ts
3341
+ import { Point, Rectangle as Rectangle9 } from "@flowgram.ai/utils";
3342
+ var LINE_PADDING = 12;
3343
+ var WorkflowSimpleLineContribution = class {
3344
+ constructor(entity) {
3345
+ this.entity = entity;
3346
+ }
3347
+ get path() {
3348
+ return this.data?.path ?? "";
3349
+ }
3350
+ calcDistance(pos) {
3351
+ if (!this.data) {
3352
+ return Number.MAX_SAFE_INTEGER;
3353
+ }
3354
+ const [start, end] = this.data.points;
3355
+ return Point.getDistance(pos, this.projectPointOnLine(pos, start, end));
3356
+ }
3357
+ get bounds() {
3358
+ if (!this.data) {
3359
+ return new Rectangle9();
3360
+ }
3361
+ return this.data.bbox;
3362
+ }
3363
+ update(params) {
3364
+ const { fromPos, toPos } = params;
3365
+ const { vertical } = this.entity;
3366
+ const sourceOffset = {
3367
+ x: vertical ? 0 : POINT_RADIUS,
3368
+ y: vertical ? POINT_RADIUS : 0
3369
+ };
3370
+ const targetOffset = {
3371
+ x: vertical ? 0 : -POINT_RADIUS,
3372
+ y: vertical ? -POINT_RADIUS : 0
3373
+ };
3374
+ const points = [
3375
+ {
3376
+ x: fromPos.x + sourceOffset.x,
3377
+ y: fromPos.y + sourceOffset.y
3378
+ },
3379
+ {
3380
+ x: toPos.x + targetOffset.x,
3381
+ y: toPos.y + targetOffset.y
3382
+ }
3383
+ ];
3384
+ const bbox = Rectangle9.createRectangleWithTwoPoints(points[0], points[1]);
3385
+ const adjustedPoints = points.map((p) => ({
3386
+ x: p.x - bbox.x + LINE_PADDING,
3387
+ y: p.y - bbox.y + LINE_PADDING
3388
+ }));
3389
+ const path = `M ${adjustedPoints[0].x} ${adjustedPoints[0].y} L ${adjustedPoints[1].x} ${adjustedPoints[1].y}`;
3390
+ this.data = {
3391
+ points,
3392
+ path,
3393
+ bbox
3394
+ };
3395
+ }
3396
+ projectPointOnLine(point, lineStart, lineEnd) {
3397
+ const dx = lineEnd.x - lineStart.x;
3398
+ const dy = lineEnd.y - lineStart.y;
3399
+ if (dx === 0) {
3400
+ return { x: lineStart.x, y: point.y };
3401
+ }
3402
+ if (dy === 0) {
3403
+ return { x: point.x, y: lineStart.y };
3404
+ }
3405
+ const t = ((point.x - lineStart.x) * dx + (point.y - lineStart.y) * dy) / (dx * dx + dy * dy);
3406
+ const clampedT = Math.max(0, Math.min(1, t));
3407
+ return {
3408
+ x: lineStart.x + clampedT * dx,
3409
+ y: lineStart.y + clampedT * dy
3410
+ };
3411
+ }
3412
+ };
3413
+ WorkflowSimpleLineContribution.type = "WorkflowSimpleLineContribution";
3414
+ export {
3415
+ EditorCursorState,
3416
+ InteractiveType,
3417
+ LINE_HOVER_DISTANCE,
3418
+ LineColors,
3419
+ LineType,
3420
+ POINT_RADIUS,
3421
+ PORT_SIZE,
3422
+ URLParams,
3423
+ WORKFLOW_LINE_ENTITY,
3424
+ WorkflowCommands,
3425
+ WorkflowContentChangeType,
3426
+ WorkflowDocument,
3427
+ WorkflowDocumentContainerModule,
3428
+ WorkflowDocumentOptions,
3429
+ WorkflowDocumentOptionsDefault,
3430
+ WorkflowDocumentProvider,
3431
+ WorkflowDragService,
3432
+ WorkflowHoverService,
3433
+ WorkflowLineEntity,
3434
+ WorkflowLineRenderData,
3435
+ WorkflowLinesManager,
3436
+ WorkflowNodeEntity,
3437
+ WorkflowNodeLinesData,
3438
+ WorkflowNodePortsData,
3439
+ WorkflowOperationBaseService,
3440
+ WorkflowOperationBaseServiceImpl,
3441
+ WorkflowPortEntity,
3442
+ WorkflowResetLayoutService,
3443
+ WorkflowSelectService,
3444
+ WorkflowSimpleLineContribution,
3445
+ bindConfigEntity,
3446
+ compose,
3447
+ composeAsync,
3448
+ delay,
3449
+ domReactToBounds,
3450
+ fitView,
3451
+ getAntiOverlapPosition,
3452
+ getPortEntityId,
3453
+ nanoid,
3454
+ useConfigEntity,
3455
+ useCurrentDomNode,
3456
+ useCurrentEntity,
3457
+ useEntities,
3458
+ useEntityDataFromContext,
3459
+ useEntityFromContext3 as useEntityFromContext,
3460
+ useListenEvents2 as useListenEvents,
3461
+ useNodeRender,
3462
+ usePlayground2 as usePlayground,
3463
+ usePlaygroundContainer,
3464
+ usePlaygroundContext,
3465
+ usePlaygroundLatest,
3466
+ usePlaygroundReadonlyState,
3467
+ useRefresh2 as useRefresh,
3468
+ useService3 as useService,
3469
+ useWorkflowDocument
3470
+ };
3471
+ //# sourceMappingURL=index.js.map