@flowgram.ai/free-node-panel-plugin 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/index.js +513 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/index.d.mts +103 -0
- package/dist/index.d.ts +103 -0
- package/dist/index.js +541 -0
- package/dist/index.js.map +1 -0
- package/package.json +58 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import * as _flowgram_ai_core from '@flowgram.ai/core';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { WorkflowNodeJSON, WorkflowNodeEntity, WorkflowPortEntity } from '@flowgram.ai/free-layout-core';
|
|
4
|
+
import { PositionSchema } from '@flowgram.ai/utils';
|
|
5
|
+
|
|
6
|
+
interface NodePanelCallParams {
|
|
7
|
+
/** 唤起节点面板的位置 */
|
|
8
|
+
panelPosition: PositionSchema;
|
|
9
|
+
/** 自定义传给面板组件的props */
|
|
10
|
+
panelProps?: Record<string, any>;
|
|
11
|
+
/** 指定父节点 */
|
|
12
|
+
containerNode?: WorkflowNodeEntity;
|
|
13
|
+
/** 创建节点后需连接的前序端口 */
|
|
14
|
+
fromPort?: WorkflowPortEntity;
|
|
15
|
+
/** 创建节点后需连接的后序端口 */
|
|
16
|
+
toPort?: WorkflowPortEntity;
|
|
17
|
+
/** 偏移后续节点默认间距 */
|
|
18
|
+
autoOffsetPadding?: PositionSchema;
|
|
19
|
+
/** 自定义节点位置 */
|
|
20
|
+
customPosition?: (params: {
|
|
21
|
+
nodeType: string;
|
|
22
|
+
selectPosition: PositionSchema;
|
|
23
|
+
}) => PositionSchema;
|
|
24
|
+
/** 是否可以添加节点 */
|
|
25
|
+
canAddNode?: (params: {
|
|
26
|
+
nodeType: string;
|
|
27
|
+
containerNode?: WorkflowNodeEntity;
|
|
28
|
+
}) => boolean;
|
|
29
|
+
/** 创建节点后 */
|
|
30
|
+
afterAddNode?: (node?: WorkflowNodeEntity) => void;
|
|
31
|
+
/** 是否创建线条 */
|
|
32
|
+
enableBuildLine?: boolean;
|
|
33
|
+
/** 是否使用选中位置作为节点位置 */
|
|
34
|
+
enableSelectPosition?: boolean;
|
|
35
|
+
/** 是否偏移后续节点 */
|
|
36
|
+
enableAutoOffset?: boolean;
|
|
37
|
+
/** 是否触发节点拖拽 */
|
|
38
|
+
enableDragNode?: boolean;
|
|
39
|
+
/** 是否可以添加多个节点 */
|
|
40
|
+
enableMultiAdd?: boolean;
|
|
41
|
+
}
|
|
42
|
+
type NodePanelResult = {
|
|
43
|
+
nodeType: string;
|
|
44
|
+
nodeJSON?: WorkflowNodeJSON;
|
|
45
|
+
selectEvent: React.MouseEvent;
|
|
46
|
+
} | undefined;
|
|
47
|
+
interface CallNodePanelParams {
|
|
48
|
+
onSelect: (params?: NodePanelResult) => void;
|
|
49
|
+
position: PositionSchema;
|
|
50
|
+
onClose: () => void;
|
|
51
|
+
enableMultiAdd: boolean;
|
|
52
|
+
panelProps: Record<string, any>;
|
|
53
|
+
containerNode?: WorkflowNodeEntity;
|
|
54
|
+
}
|
|
55
|
+
type CallNodePanel = (params: CallNodePanelParams) => Promise<void>;
|
|
56
|
+
interface NodePanelRenderProps extends CallNodePanelParams {
|
|
57
|
+
}
|
|
58
|
+
type NodePanelRender = React.FC<NodePanelRenderProps>;
|
|
59
|
+
interface NodePanelLayerOptions {
|
|
60
|
+
renderer: NodePanelRender;
|
|
61
|
+
}
|
|
62
|
+
interface NodePanelPluginOptions extends NodePanelLayerOptions {
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
declare const createFreeNodePanelPlugin: _flowgram_ai_core.PluginCreator<NodePanelPluginOptions>;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* 添加节点面板服务
|
|
69
|
+
*/
|
|
70
|
+
declare class WorkflowNodePanelService {
|
|
71
|
+
private readonly document;
|
|
72
|
+
private readonly dragService;
|
|
73
|
+
private readonly selectService;
|
|
74
|
+
private readonly linesManager;
|
|
75
|
+
private readonly playgroundConfig;
|
|
76
|
+
private readonly historyService;
|
|
77
|
+
private readonly toDispose;
|
|
78
|
+
private callNodePanel;
|
|
79
|
+
/** 销毁 */
|
|
80
|
+
dispose(): void;
|
|
81
|
+
setCallNodePanel(callNodePanel: CallNodePanel): void;
|
|
82
|
+
/** 唤起节点面板 */
|
|
83
|
+
call(callParams: NodePanelCallParams): Promise<WorkflowNodeEntity | WorkflowNodeEntity[] | undefined>;
|
|
84
|
+
/** 添加节点 */
|
|
85
|
+
private addNode;
|
|
86
|
+
/** 建立连线 */
|
|
87
|
+
private buildLine;
|
|
88
|
+
/** 调整节点坐标 */
|
|
89
|
+
private adjustNodePosition;
|
|
90
|
+
private getContainerNode;
|
|
91
|
+
/** 获取端口矩形 */
|
|
92
|
+
private getPortBox;
|
|
93
|
+
/** 后续节点位置偏移 */
|
|
94
|
+
private subPositionOffset;
|
|
95
|
+
/** 矩形间距 */
|
|
96
|
+
private rectDistance;
|
|
97
|
+
/** 获取后续节点 */
|
|
98
|
+
private getSubsequentNodes;
|
|
99
|
+
/** 更新后续节点位置 */
|
|
100
|
+
private updateSubSequentNodesPosition;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export { type NodePanelPluginOptions, type NodePanelRender, type NodePanelRenderProps, type NodePanelResult, type NodePanelLayerOptions as NodePanelServiceOptions, WorkflowNodePanelService, createFreeNodePanelPlugin };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,541 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
30
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
31
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
32
|
+
if (decorator = decorators[i])
|
|
33
|
+
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
34
|
+
if (kind && result) __defProp(target, key, result);
|
|
35
|
+
return result;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
// src/index.ts
|
|
39
|
+
var src_exports = {};
|
|
40
|
+
__export(src_exports, {
|
|
41
|
+
WorkflowNodePanelService: () => WorkflowNodePanelService,
|
|
42
|
+
createFreeNodePanelPlugin: () => createFreeNodePanelPlugin
|
|
43
|
+
});
|
|
44
|
+
module.exports = __toCommonJS(src_exports);
|
|
45
|
+
|
|
46
|
+
// src/create-plugin.ts
|
|
47
|
+
var import_core4 = require("@flowgram.ai/core");
|
|
48
|
+
|
|
49
|
+
// src/service.ts
|
|
50
|
+
var import_inversify = require("inversify");
|
|
51
|
+
var import_utils = require("@flowgram.ai/utils");
|
|
52
|
+
var import_free_layout_core = require("@flowgram.ai/free-layout-core");
|
|
53
|
+
var import_free_layout_core2 = require("@flowgram.ai/free-layout-core");
|
|
54
|
+
var import_free_history_plugin = require("@flowgram.ai/free-history-plugin");
|
|
55
|
+
var import_document = require("@flowgram.ai/document");
|
|
56
|
+
var import_document2 = require("@flowgram.ai/document");
|
|
57
|
+
var import_core = require("@flowgram.ai/core");
|
|
58
|
+
var import_core2 = require("@flowgram.ai/core");
|
|
59
|
+
|
|
60
|
+
// src/utils.ts
|
|
61
|
+
var isGreaterThan = (a, b) => {
|
|
62
|
+
if (a === void 0 || b === void 0) {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
const EPSILON = 1e-5;
|
|
66
|
+
return a - b > EPSILON;
|
|
67
|
+
};
|
|
68
|
+
var isLessThan = (a, b) => {
|
|
69
|
+
if (a === void 0 || b === void 0) {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
const EPSILON = 1e-5;
|
|
73
|
+
return b - a > EPSILON;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// src/service.ts
|
|
77
|
+
var WorkflowNodePanelService = class {
|
|
78
|
+
constructor() {
|
|
79
|
+
this.toDispose = new import_utils.DisposableCollection();
|
|
80
|
+
this.callNodePanel = async () => void 0;
|
|
81
|
+
}
|
|
82
|
+
/** 销毁 */
|
|
83
|
+
dispose() {
|
|
84
|
+
this.toDispose.dispose();
|
|
85
|
+
}
|
|
86
|
+
setCallNodePanel(callNodePanel) {
|
|
87
|
+
this.callNodePanel = callNodePanel;
|
|
88
|
+
}
|
|
89
|
+
/** 唤起节点面板 */
|
|
90
|
+
async call(callParams) {
|
|
91
|
+
const {
|
|
92
|
+
panelPosition,
|
|
93
|
+
fromPort,
|
|
94
|
+
enableMultiAdd = false,
|
|
95
|
+
panelProps = {},
|
|
96
|
+
containerNode,
|
|
97
|
+
afterAddNode
|
|
98
|
+
} = callParams;
|
|
99
|
+
if (!panelPosition || this.playgroundConfig.readonly) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const nodes = [];
|
|
103
|
+
return new Promise((resolve) => {
|
|
104
|
+
this.callNodePanel({
|
|
105
|
+
position: panelPosition,
|
|
106
|
+
enableMultiAdd,
|
|
107
|
+
panelProps,
|
|
108
|
+
containerNode: this.getContainerNode({
|
|
109
|
+
fromPort,
|
|
110
|
+
containerNode
|
|
111
|
+
}),
|
|
112
|
+
onSelect: async (panelParams) => {
|
|
113
|
+
const node = await this.addNode(callParams, panelParams);
|
|
114
|
+
afterAddNode?.(node);
|
|
115
|
+
if (!enableMultiAdd) {
|
|
116
|
+
resolve(node);
|
|
117
|
+
} else if (node) {
|
|
118
|
+
nodes.push(node);
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
onClose: () => {
|
|
122
|
+
resolve(enableMultiAdd ? nodes : void 0);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
/** 添加节点 */
|
|
128
|
+
async addNode(callParams, panelParams) {
|
|
129
|
+
const {
|
|
130
|
+
panelPosition,
|
|
131
|
+
fromPort,
|
|
132
|
+
toPort,
|
|
133
|
+
canAddNode,
|
|
134
|
+
autoOffsetPadding = {
|
|
135
|
+
x: 100,
|
|
136
|
+
y: 100
|
|
137
|
+
},
|
|
138
|
+
enableBuildLine = false,
|
|
139
|
+
enableSelectPosition = false,
|
|
140
|
+
enableAutoOffset = false,
|
|
141
|
+
enableDragNode = false
|
|
142
|
+
} = callParams;
|
|
143
|
+
if (!panelPosition || !panelParams) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const { nodeType, selectEvent, nodeJSON } = panelParams;
|
|
147
|
+
const containerNode = this.getContainerNode({
|
|
148
|
+
fromPort,
|
|
149
|
+
containerNode: callParams.containerNode
|
|
150
|
+
});
|
|
151
|
+
if (canAddNode) {
|
|
152
|
+
const canAdd = canAddNode({ nodeType, containerNode });
|
|
153
|
+
if (!canAdd) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
const selectPosition = this.playgroundConfig.getPosFromMouseEvent(selectEvent);
|
|
158
|
+
const nodePosition = callParams.customPosition ? callParams.customPosition({ nodeType, selectPosition }) : this.adjustNodePosition({
|
|
159
|
+
nodeType,
|
|
160
|
+
position: enableSelectPosition ? selectPosition : panelPosition,
|
|
161
|
+
fromPort,
|
|
162
|
+
toPort,
|
|
163
|
+
containerNode
|
|
164
|
+
});
|
|
165
|
+
const node = await this.document.createWorkflowNodeByType(
|
|
166
|
+
nodeType,
|
|
167
|
+
nodePosition,
|
|
168
|
+
nodeJSON ?? {},
|
|
169
|
+
containerNode?.id
|
|
170
|
+
);
|
|
171
|
+
if (!node) {
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
if (enableAutoOffset && fromPort && toPort) {
|
|
175
|
+
const subOffset = this.subPositionOffset({
|
|
176
|
+
node,
|
|
177
|
+
fromPort,
|
|
178
|
+
toPort,
|
|
179
|
+
padding: autoOffsetPadding
|
|
180
|
+
});
|
|
181
|
+
const subsequentNodes = this.getSubsequentNodes(toPort.node);
|
|
182
|
+
this.updateSubSequentNodesPosition({
|
|
183
|
+
node,
|
|
184
|
+
subsequentNodes,
|
|
185
|
+
fromPort,
|
|
186
|
+
toPort,
|
|
187
|
+
containerNode,
|
|
188
|
+
offset: subOffset
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
if (!enableBuildLine && !enableDragNode) {
|
|
192
|
+
return node;
|
|
193
|
+
}
|
|
194
|
+
await (0, import_utils.delay)(20);
|
|
195
|
+
if (enableBuildLine) {
|
|
196
|
+
this.buildLine({
|
|
197
|
+
fromPort,
|
|
198
|
+
node,
|
|
199
|
+
toPort
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
if (enableDragNode) {
|
|
203
|
+
this.selectService.selectNode(node);
|
|
204
|
+
this.dragService.startDragSelectedNodes(selectEvent);
|
|
205
|
+
}
|
|
206
|
+
return node;
|
|
207
|
+
}
|
|
208
|
+
/** 建立连线 */
|
|
209
|
+
buildLine(params) {
|
|
210
|
+
const { fromPort, node, toPort } = params;
|
|
211
|
+
const portsData = node.getData(import_free_layout_core.WorkflowNodePortsData);
|
|
212
|
+
if (!portsData) {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
const shouldBuildFromLine = portsData.inputPorts?.length > 0;
|
|
216
|
+
if (fromPort && shouldBuildFromLine) {
|
|
217
|
+
const toTargetPort = portsData.inputPorts[0];
|
|
218
|
+
const isSingleInput = portsData.inputPorts.length === 1;
|
|
219
|
+
this.linesManager.createLine({
|
|
220
|
+
from: fromPort.node.id,
|
|
221
|
+
fromPort: fromPort.portID,
|
|
222
|
+
to: node.id,
|
|
223
|
+
toPort: isSingleInput ? void 0 : toTargetPort.id
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
const shouldBuildToLine = portsData.outputPorts?.length > 0;
|
|
227
|
+
if (toPort && shouldBuildToLine) {
|
|
228
|
+
const fromTargetPort = portsData.outputPorts[0];
|
|
229
|
+
this.linesManager.createLine({
|
|
230
|
+
from: node.id,
|
|
231
|
+
fromPort: fromTargetPort.portID,
|
|
232
|
+
to: toPort.node.id,
|
|
233
|
+
toPort: toPort.portID
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
/** 调整节点坐标 */
|
|
238
|
+
adjustNodePosition(params) {
|
|
239
|
+
const { nodeType, position, fromPort, toPort, containerNode } = params;
|
|
240
|
+
const register = this.document.getNodeRegistry(nodeType);
|
|
241
|
+
const size = register?.meta?.size;
|
|
242
|
+
let adjustedPosition = position;
|
|
243
|
+
if (!size) {
|
|
244
|
+
adjustedPosition = position;
|
|
245
|
+
} else if (fromPort && toPort) {
|
|
246
|
+
adjustedPosition = {
|
|
247
|
+
x: position.x,
|
|
248
|
+
y: position.y - size.height / 2
|
|
249
|
+
};
|
|
250
|
+
} else if (fromPort && !toPort) {
|
|
251
|
+
adjustedPosition = {
|
|
252
|
+
x: position.x + size.width / 2,
|
|
253
|
+
y: position.y - size.height / 2
|
|
254
|
+
};
|
|
255
|
+
} else if (!fromPort && toPort) {
|
|
256
|
+
adjustedPosition = {
|
|
257
|
+
x: position.x - size.width / 2,
|
|
258
|
+
y: position.y - size.height / 2
|
|
259
|
+
};
|
|
260
|
+
} else {
|
|
261
|
+
adjustedPosition = position;
|
|
262
|
+
}
|
|
263
|
+
return this.dragService.adjustSubNodePosition(nodeType, containerNode, adjustedPosition);
|
|
264
|
+
}
|
|
265
|
+
getContainerNode(params) {
|
|
266
|
+
const { fromPort, containerNode } = params;
|
|
267
|
+
if (containerNode) {
|
|
268
|
+
return containerNode;
|
|
269
|
+
}
|
|
270
|
+
const fromNode = fromPort?.node;
|
|
271
|
+
const fromContainer = fromNode?.parent;
|
|
272
|
+
if (fromNode?.flowNodeType === import_document2.FlowNodeBaseType.SUB_CANVAS) {
|
|
273
|
+
return fromNode;
|
|
274
|
+
}
|
|
275
|
+
return fromContainer;
|
|
276
|
+
}
|
|
277
|
+
/** 获取端口矩形 */
|
|
278
|
+
getPortBox(port, offset = { x: 0, y: 0 }) {
|
|
279
|
+
const node = port.node;
|
|
280
|
+
if (node.flowNodeType === import_document2.FlowNodeBaseType.SUB_CANVAS) {
|
|
281
|
+
const { point } = port;
|
|
282
|
+
if (port.portType === "input") {
|
|
283
|
+
return new import_utils.Rectangle(point.x + offset.x, point.y - 50 + offset.y, 300, 100);
|
|
284
|
+
}
|
|
285
|
+
return new import_utils.Rectangle(point.x - 300, point.y - 50, 300, 100);
|
|
286
|
+
}
|
|
287
|
+
const box = node.getData(import_document.FlowNodeTransformData).bounds;
|
|
288
|
+
return box;
|
|
289
|
+
}
|
|
290
|
+
/** 后续节点位置偏移 */
|
|
291
|
+
subPositionOffset(params) {
|
|
292
|
+
const { node, fromPort, toPort, padding } = params;
|
|
293
|
+
const fromBox = this.getPortBox(fromPort);
|
|
294
|
+
const toBox = this.getPortBox(toPort);
|
|
295
|
+
const nodeTrans = node.getData(import_document.FlowNodeTransformData);
|
|
296
|
+
const nodeSize = node.getNodeMeta()?.size ?? {
|
|
297
|
+
width: nodeTrans.bounds.width,
|
|
298
|
+
height: nodeTrans.bounds.height
|
|
299
|
+
};
|
|
300
|
+
const minDistance = {
|
|
301
|
+
x: nodeSize.width + padding.x,
|
|
302
|
+
y: nodeSize.height + padding.y
|
|
303
|
+
};
|
|
304
|
+
const boxDistance = this.rectDistance(fromBox, toBox);
|
|
305
|
+
const neededOffset = {
|
|
306
|
+
x: isGreaterThan(boxDistance.x, minDistance.x) ? 0 : minDistance.x - boxDistance.x,
|
|
307
|
+
y: isGreaterThan(boxDistance.y, minDistance.y) ? 0 : minDistance.y - boxDistance.y
|
|
308
|
+
};
|
|
309
|
+
if (neededOffset.x === 0 || neededOffset.y === 0) {
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
const intersection = {
|
|
313
|
+
// 这里没有写反,Rectangle内置的算法是反的
|
|
314
|
+
vertical: import_utils.Rectangle.intersects(fromBox, toBox, "horizontal"),
|
|
315
|
+
horizontal: import_utils.Rectangle.intersects(fromBox, toBox, "vertical")
|
|
316
|
+
};
|
|
317
|
+
let offsetX = 0;
|
|
318
|
+
let offsetY = 0;
|
|
319
|
+
if (!intersection.horizontal) {
|
|
320
|
+
if (isGreaterThan(toBox.center.y, fromBox.center.y)) {
|
|
321
|
+
offsetY = neededOffset.y;
|
|
322
|
+
} else if (isLessThan(toBox.center.y, fromBox.center.y)) {
|
|
323
|
+
offsetY = -neededOffset.y;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
if (!intersection.vertical) {
|
|
327
|
+
if (isGreaterThan(toBox.center.x, fromBox.center.x)) {
|
|
328
|
+
offsetX = neededOffset.x;
|
|
329
|
+
} else if (isLessThan(toBox.center.x, fromBox.center.x)) {
|
|
330
|
+
offsetX = -neededOffset.x;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return {
|
|
334
|
+
x: offsetX,
|
|
335
|
+
y: offsetY
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
/** 矩形间距 */
|
|
339
|
+
rectDistance(rectA, rectB) {
|
|
340
|
+
const distanceX = Math.abs(
|
|
341
|
+
Math.min(rectA.right, rectB.right) - Math.max(rectA.left, rectB.left)
|
|
342
|
+
);
|
|
343
|
+
const distanceY = Math.abs(
|
|
344
|
+
Math.min(rectA.bottom, rectB.bottom) - Math.max(rectA.top, rectB.top)
|
|
345
|
+
);
|
|
346
|
+
if (import_utils.Rectangle.intersects(rectA, rectB)) {
|
|
347
|
+
return {
|
|
348
|
+
x: -distanceX,
|
|
349
|
+
y: -distanceY
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
return {
|
|
353
|
+
x: distanceX,
|
|
354
|
+
y: distanceY
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
/** 获取后续节点 */
|
|
358
|
+
getSubsequentNodes(node) {
|
|
359
|
+
if (node.flowNodeType === import_document2.FlowNodeBaseType.SUB_CANVAS) {
|
|
360
|
+
return [];
|
|
361
|
+
}
|
|
362
|
+
const brothers = node.parent?.collapsedChildren ?? [];
|
|
363
|
+
const linkedBrothers = /* @__PURE__ */ new Set();
|
|
364
|
+
const linesMap = /* @__PURE__ */ new Map();
|
|
365
|
+
this.linesManager.getAllLines().forEach((line) => {
|
|
366
|
+
if (!linesMap.has(line.from.id)) {
|
|
367
|
+
linesMap.set(line.from.id, []);
|
|
368
|
+
}
|
|
369
|
+
if (!line.to?.id || line.to.flowNodeType === import_document2.FlowNodeBaseType.SUB_CANVAS) {
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
linesMap.get(line.from.id)?.push(line.to.id);
|
|
373
|
+
});
|
|
374
|
+
const bfs = (nodeId) => {
|
|
375
|
+
if (linkedBrothers.has(nodeId)) {
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
linkedBrothers.add(nodeId);
|
|
379
|
+
const nextNodes = linesMap.get(nodeId) ?? [];
|
|
380
|
+
nextNodes.forEach(bfs);
|
|
381
|
+
};
|
|
382
|
+
bfs(node.id);
|
|
383
|
+
const subsequentNodes = brothers.filter((node2) => linkedBrothers.has(node2.id));
|
|
384
|
+
return subsequentNodes;
|
|
385
|
+
}
|
|
386
|
+
/** 更新后续节点位置 */
|
|
387
|
+
updateSubSequentNodesPosition(params) {
|
|
388
|
+
const { node, subsequentNodes, fromPort, toPort, containerNode, offset } = params;
|
|
389
|
+
if (!offset || !toPort) {
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
const subsequentNodesPositions = subsequentNodes.map((node2) => {
|
|
393
|
+
const nodeTrans2 = node2.getData(import_core2.TransformData);
|
|
394
|
+
return {
|
|
395
|
+
x: nodeTrans2.position.x,
|
|
396
|
+
y: nodeTrans2.position.y
|
|
397
|
+
};
|
|
398
|
+
});
|
|
399
|
+
this.historyService.pushOperation({
|
|
400
|
+
type: import_free_history_plugin.FreeOperationType.dragNodes,
|
|
401
|
+
value: {
|
|
402
|
+
ids: subsequentNodes.map((node2) => node2.id),
|
|
403
|
+
value: subsequentNodesPositions.map((position) => ({
|
|
404
|
+
x: position.x + offset.x,
|
|
405
|
+
y: position.y + offset.y
|
|
406
|
+
})),
|
|
407
|
+
oldValue: subsequentNodesPositions
|
|
408
|
+
}
|
|
409
|
+
});
|
|
410
|
+
const fromBox = this.getPortBox(fromPort);
|
|
411
|
+
const toBox = this.getPortBox(toPort, offset);
|
|
412
|
+
const nodeTrans = node.getData(import_core2.TransformData);
|
|
413
|
+
let nodePos = {
|
|
414
|
+
x: (fromBox.center.x + toBox.center.x) / 2,
|
|
415
|
+
y: (fromBox.y + toBox.y) / 2
|
|
416
|
+
};
|
|
417
|
+
if (containerNode) {
|
|
418
|
+
nodePos = this.dragService.adjustSubNodePosition(
|
|
419
|
+
node.flowNodeType,
|
|
420
|
+
containerNode,
|
|
421
|
+
nodePos
|
|
422
|
+
);
|
|
423
|
+
}
|
|
424
|
+
this.historyService.pushOperation({
|
|
425
|
+
type: import_free_history_plugin.FreeOperationType.dragNodes,
|
|
426
|
+
value: {
|
|
427
|
+
ids: [node.id],
|
|
428
|
+
value: [nodePos],
|
|
429
|
+
oldValue: [
|
|
430
|
+
{
|
|
431
|
+
x: nodeTrans.position.x,
|
|
432
|
+
y: nodeTrans.position.y
|
|
433
|
+
}
|
|
434
|
+
]
|
|
435
|
+
}
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
};
|
|
439
|
+
__decorateClass([
|
|
440
|
+
(0, import_inversify.inject)(import_free_layout_core.WorkflowDocument)
|
|
441
|
+
], WorkflowNodePanelService.prototype, "document", 2);
|
|
442
|
+
__decorateClass([
|
|
443
|
+
(0, import_inversify.inject)(import_free_layout_core.WorkflowDragService)
|
|
444
|
+
], WorkflowNodePanelService.prototype, "dragService", 2);
|
|
445
|
+
__decorateClass([
|
|
446
|
+
(0, import_inversify.inject)(import_free_layout_core2.WorkflowSelectService)
|
|
447
|
+
], WorkflowNodePanelService.prototype, "selectService", 2);
|
|
448
|
+
__decorateClass([
|
|
449
|
+
(0, import_inversify.inject)(import_free_layout_core.WorkflowLinesManager)
|
|
450
|
+
], WorkflowNodePanelService.prototype, "linesManager", 2);
|
|
451
|
+
__decorateClass([
|
|
452
|
+
(0, import_inversify.inject)(import_core.PlaygroundConfigEntity)
|
|
453
|
+
], WorkflowNodePanelService.prototype, "playgroundConfig", 2);
|
|
454
|
+
__decorateClass([
|
|
455
|
+
(0, import_inversify.inject)(import_free_history_plugin.HistoryService)
|
|
456
|
+
], WorkflowNodePanelService.prototype, "historyService", 2);
|
|
457
|
+
WorkflowNodePanelService = __decorateClass([
|
|
458
|
+
(0, import_inversify.injectable)()
|
|
459
|
+
], WorkflowNodePanelService);
|
|
460
|
+
|
|
461
|
+
// src/layer.tsx
|
|
462
|
+
var import_react = __toESM(require("react"));
|
|
463
|
+
var import_inversify2 = require("inversify");
|
|
464
|
+
var import_core3 = require("@flowgram.ai/core");
|
|
465
|
+
var import_free_layout_core3 = require("@flowgram.ai/free-layout-core");
|
|
466
|
+
var import_utils3 = require("@flowgram.ai/utils");
|
|
467
|
+
var WorkflowNodePanelLayer = class extends import_core3.Layer {
|
|
468
|
+
constructor() {
|
|
469
|
+
super();
|
|
470
|
+
this.node = import_utils3.domUtils.createDivWithClass("gedit-playground-layer gedit-node-panel-layer");
|
|
471
|
+
this.node.style.zIndex = "9999";
|
|
472
|
+
this.renderList = /* @__PURE__ */ new Map();
|
|
473
|
+
}
|
|
474
|
+
onReady() {
|
|
475
|
+
this.service.setCallNodePanel(this.call.bind(this));
|
|
476
|
+
}
|
|
477
|
+
onZoom(zoom) {
|
|
478
|
+
this.node.style.transform = `scale(${zoom})`;
|
|
479
|
+
}
|
|
480
|
+
render() {
|
|
481
|
+
const NodePanelRender = this.options.renderer;
|
|
482
|
+
return /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, Array.from(this.renderList.keys()).map((taskId) => {
|
|
483
|
+
const renderProps = this.renderList.get(taskId);
|
|
484
|
+
return /* @__PURE__ */ import_react.default.createElement(NodePanelRender, { key: taskId, ...renderProps });
|
|
485
|
+
}));
|
|
486
|
+
}
|
|
487
|
+
async call(params) {
|
|
488
|
+
const taskId = (0, import_free_layout_core3.nanoid)();
|
|
489
|
+
const { enableMultiAdd, onSelect, onClose } = params;
|
|
490
|
+
return new Promise((resolve) => {
|
|
491
|
+
const unmount = () => {
|
|
492
|
+
this.renderList.delete(taskId);
|
|
493
|
+
this.render();
|
|
494
|
+
resolve();
|
|
495
|
+
};
|
|
496
|
+
const handleClose = () => {
|
|
497
|
+
unmount();
|
|
498
|
+
onClose();
|
|
499
|
+
};
|
|
500
|
+
const handleSelect = (params2) => {
|
|
501
|
+
onSelect(params2);
|
|
502
|
+
if (!enableMultiAdd) {
|
|
503
|
+
unmount();
|
|
504
|
+
}
|
|
505
|
+
};
|
|
506
|
+
const renderProps = {
|
|
507
|
+
...params,
|
|
508
|
+
onSelect: handleSelect,
|
|
509
|
+
onClose: handleClose
|
|
510
|
+
};
|
|
511
|
+
this.renderList.set(taskId, renderProps);
|
|
512
|
+
this.render();
|
|
513
|
+
});
|
|
514
|
+
}
|
|
515
|
+
};
|
|
516
|
+
WorkflowNodePanelLayer.type = "WorkflowNodePanelLayer";
|
|
517
|
+
__decorateClass([
|
|
518
|
+
(0, import_inversify2.inject)(WorkflowNodePanelService)
|
|
519
|
+
], WorkflowNodePanelLayer.prototype, "service", 2);
|
|
520
|
+
|
|
521
|
+
// src/create-plugin.ts
|
|
522
|
+
var createFreeNodePanelPlugin = (0, import_core4.definePluginCreator)({
|
|
523
|
+
onBind({ bind }) {
|
|
524
|
+
bind(WorkflowNodePanelService).toSelf().inSingletonScope();
|
|
525
|
+
},
|
|
526
|
+
onInit: (ctx, opts) => {
|
|
527
|
+
ctx.playground.registerLayer(WorkflowNodePanelLayer, {
|
|
528
|
+
renderer: opts.renderer
|
|
529
|
+
});
|
|
530
|
+
},
|
|
531
|
+
onDispose: (ctx) => {
|
|
532
|
+
const nodePanelService = ctx.get(WorkflowNodePanelService);
|
|
533
|
+
nodePanelService.dispose();
|
|
534
|
+
}
|
|
535
|
+
});
|
|
536
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
537
|
+
0 && (module.exports = {
|
|
538
|
+
WorkflowNodePanelService,
|
|
539
|
+
createFreeNodePanelPlugin
|
|
540
|
+
});
|
|
541
|
+
//# sourceMappingURL=index.js.map
|