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

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