@flowgram.ai/free-group-plugin 0.1.0-alpha.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/index.js +289 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/index.d.mts +51 -0
- package/dist/index.d.ts +51 -0
- package/dist/index.js +308 -0
- package/dist/index.js.map +1 -0
- package/package.json +68 -0
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
4
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
5
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
6
|
+
if (decorator = decorators[i])
|
|
7
|
+
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
8
|
+
if (kind && result) __defProp(target, key, result);
|
|
9
|
+
return result;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// src/create-free-group-plugin.tsx
|
|
13
|
+
import { ShortcutsRegistry } from "@flowgram.ai/shortcuts-plugin";
|
|
14
|
+
import { FlowRendererRegistry } from "@flowgram.ai/renderer";
|
|
15
|
+
import { WorkflowDocument as WorkflowDocument2 } from "@flowgram.ai/free-layout-core";
|
|
16
|
+
import { FlowGroupService as FlowGroupService2, FlowNodeBaseType as FlowNodeBaseType5 } from "@flowgram.ai/document";
|
|
17
|
+
import { definePluginCreator } from "@flowgram.ai/core";
|
|
18
|
+
|
|
19
|
+
// src/workflow-group-service.ts
|
|
20
|
+
import { injectable, inject } from "inversify";
|
|
21
|
+
import { DisposableCollection } from "@flowgram.ai/utils";
|
|
22
|
+
import {
|
|
23
|
+
WorkflowDocument,
|
|
24
|
+
WorkflowOperationBaseService,
|
|
25
|
+
nanoid
|
|
26
|
+
} from "@flowgram.ai/free-layout-core";
|
|
27
|
+
import { HistoryService } from "@flowgram.ai/free-history-plugin";
|
|
28
|
+
import {
|
|
29
|
+
NodeIntoContainerService,
|
|
30
|
+
NodeIntoContainerType
|
|
31
|
+
} from "@flowgram.ai/free-container-plugin";
|
|
32
|
+
import { FlowGroupService, FlowNodeBaseType as FlowNodeBaseType2 } from "@flowgram.ai/document";
|
|
33
|
+
import { TransformData } from "@flowgram.ai/core";
|
|
34
|
+
|
|
35
|
+
// src/utils.ts
|
|
36
|
+
import { FlowNodeBaseType } from "@flowgram.ai/document";
|
|
37
|
+
var WorkflowGroupUtils;
|
|
38
|
+
((WorkflowGroupUtils2) => {
|
|
39
|
+
const isNodeInGroup = (node) => {
|
|
40
|
+
if (node?.parent?.flowNodeType === FlowNodeBaseType.GROUP) {
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
return false;
|
|
44
|
+
};
|
|
45
|
+
const isGroupNode = (group) => group.flowNodeType === FlowNodeBaseType.GROUP;
|
|
46
|
+
WorkflowGroupUtils2.validate = (nodes) => {
|
|
47
|
+
if (!nodes || !Array.isArray(nodes) || nodes.length === 0) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
const isGroupRelatedNode = nodes.some((node) => isGroupNode(node));
|
|
51
|
+
if (isGroupRelatedNode) return false;
|
|
52
|
+
const hasGroup = nodes.some((node) => node && isNodeInGroup(node));
|
|
53
|
+
if (hasGroup) return false;
|
|
54
|
+
const parent = nodes[0].parent;
|
|
55
|
+
const isSameParent = nodes.every((node) => node.parent === parent);
|
|
56
|
+
if (!isSameParent) return false;
|
|
57
|
+
return true;
|
|
58
|
+
};
|
|
59
|
+
})(WorkflowGroupUtils || (WorkflowGroupUtils = {}));
|
|
60
|
+
|
|
61
|
+
// src/type.ts
|
|
62
|
+
var WorkflowGroupPluginOptions = Symbol("WorkflowGroupPluginOptions");
|
|
63
|
+
|
|
64
|
+
// src/workflow-group-service.ts
|
|
65
|
+
var WorkflowGroupService = class extends FlowGroupService {
|
|
66
|
+
constructor() {
|
|
67
|
+
super(...arguments);
|
|
68
|
+
this.toDispose = new DisposableCollection();
|
|
69
|
+
}
|
|
70
|
+
ready() {
|
|
71
|
+
this.toDispose.push(this.listenContainer());
|
|
72
|
+
}
|
|
73
|
+
dispose() {
|
|
74
|
+
this.toDispose.dispose();
|
|
75
|
+
}
|
|
76
|
+
/** 创建分组节点 */
|
|
77
|
+
createGroup(nodes) {
|
|
78
|
+
if (!WorkflowGroupUtils.validate(nodes)) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const parent = nodes[0].parent ?? this.document.root;
|
|
82
|
+
let groupJSON = {
|
|
83
|
+
type: FlowNodeBaseType2.GROUP,
|
|
84
|
+
id: `group_${nanoid(5)}`,
|
|
85
|
+
meta: {
|
|
86
|
+
position: {
|
|
87
|
+
x: 0,
|
|
88
|
+
y: 0
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
data: {}
|
|
92
|
+
};
|
|
93
|
+
if (this.opts.initGroupJSON) {
|
|
94
|
+
groupJSON = this.opts.initGroupJSON(groupJSON, nodes);
|
|
95
|
+
}
|
|
96
|
+
this.historyService.startTransaction();
|
|
97
|
+
this.document.createWorkflowNodeByType(
|
|
98
|
+
FlowNodeBaseType2.GROUP,
|
|
99
|
+
{
|
|
100
|
+
x: 0,
|
|
101
|
+
y: 0
|
|
102
|
+
},
|
|
103
|
+
groupJSON,
|
|
104
|
+
parent.id
|
|
105
|
+
);
|
|
106
|
+
nodes.forEach((node) => {
|
|
107
|
+
this.freeOperationService.moveNode(node, {
|
|
108
|
+
parent: groupJSON.id
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
this.historyService.endTransaction();
|
|
112
|
+
}
|
|
113
|
+
/** 取消分组 */
|
|
114
|
+
ungroup(groupNode) {
|
|
115
|
+
const groupBlocks = groupNode.blocks.slice();
|
|
116
|
+
if (!groupNode.parent) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
const groupPosition = groupNode.transform.position;
|
|
120
|
+
this.historyService.startTransaction();
|
|
121
|
+
groupBlocks.forEach((node) => {
|
|
122
|
+
this.freeOperationService.moveNode(node, {
|
|
123
|
+
parent: groupNode.parent?.id
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
groupNode.dispose();
|
|
127
|
+
groupBlocks.forEach((node) => {
|
|
128
|
+
const transform = node.getData(TransformData);
|
|
129
|
+
const position = {
|
|
130
|
+
x: transform.position.x + groupPosition.x,
|
|
131
|
+
y: transform.position.y + groupPosition.y
|
|
132
|
+
};
|
|
133
|
+
this.freeOperationService.updateNodePosition(node, position);
|
|
134
|
+
});
|
|
135
|
+
this.historyService.endTransaction();
|
|
136
|
+
}
|
|
137
|
+
listenContainer() {
|
|
138
|
+
return this.nodeIntoContainerService.on((e) => {
|
|
139
|
+
if (e.type !== NodeIntoContainerType.Out || e.sourceContainer?.flowNodeType !== FlowNodeBaseType2.GROUP) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
if (e.sourceContainer?.blocks.length === 0) {
|
|
143
|
+
e.sourceContainer.dispose();
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
__decorateClass([
|
|
149
|
+
inject(WorkflowDocument)
|
|
150
|
+
], WorkflowGroupService.prototype, "document", 2);
|
|
151
|
+
__decorateClass([
|
|
152
|
+
inject(WorkflowOperationBaseService)
|
|
153
|
+
], WorkflowGroupService.prototype, "freeOperationService", 2);
|
|
154
|
+
__decorateClass([
|
|
155
|
+
inject(HistoryService)
|
|
156
|
+
], WorkflowGroupService.prototype, "historyService", 2);
|
|
157
|
+
__decorateClass([
|
|
158
|
+
inject(NodeIntoContainerService)
|
|
159
|
+
], WorkflowGroupService.prototype, "nodeIntoContainerService", 2);
|
|
160
|
+
__decorateClass([
|
|
161
|
+
inject(WorkflowGroupPluginOptions)
|
|
162
|
+
], WorkflowGroupService.prototype, "opts", 2);
|
|
163
|
+
WorkflowGroupService = __decorateClass([
|
|
164
|
+
injectable()
|
|
165
|
+
], WorkflowGroupService);
|
|
166
|
+
|
|
167
|
+
// src/shortcuts/group.ts
|
|
168
|
+
import { WorkflowSelectService } from "@flowgram.ai/free-layout-core";
|
|
169
|
+
|
|
170
|
+
// src/constant.ts
|
|
171
|
+
var WorkflowGroupCommand = /* @__PURE__ */ ((WorkflowGroupCommand2) => {
|
|
172
|
+
WorkflowGroupCommand2["Group"] = "group";
|
|
173
|
+
WorkflowGroupCommand2["Ungroup"] = "ungroup";
|
|
174
|
+
return WorkflowGroupCommand2;
|
|
175
|
+
})(WorkflowGroupCommand || {});
|
|
176
|
+
|
|
177
|
+
// src/shortcuts/group.ts
|
|
178
|
+
var GroupShortcut = class {
|
|
179
|
+
constructor(context) {
|
|
180
|
+
this.commandId = "group" /* Group */;
|
|
181
|
+
this.commandDetail = {
|
|
182
|
+
label: "Group"
|
|
183
|
+
};
|
|
184
|
+
this.shortcuts = ["meta g", "ctrl g"];
|
|
185
|
+
this.selectService = context.get(WorkflowSelectService);
|
|
186
|
+
this.groupService = context.get(WorkflowGroupService);
|
|
187
|
+
this.execute = this.execute.bind(this);
|
|
188
|
+
}
|
|
189
|
+
async execute() {
|
|
190
|
+
this.groupService.createGroup(this.selectService.selectedNodes);
|
|
191
|
+
this.selectService.clear();
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
// src/shortcuts/ungroup.ts
|
|
196
|
+
import { WorkflowSelectService as WorkflowSelectService2 } from "@flowgram.ai/free-layout-core";
|
|
197
|
+
import { FlowNodeBaseType as FlowNodeBaseType3 } from "@flowgram.ai/document";
|
|
198
|
+
var UngroupShortcut = class {
|
|
199
|
+
constructor(context) {
|
|
200
|
+
this.commandId = "ungroup" /* Ungroup */;
|
|
201
|
+
this.commandDetail = {
|
|
202
|
+
label: "Ungroup"
|
|
203
|
+
};
|
|
204
|
+
this.shortcuts = ["meta shift g", "ctrl shift g"];
|
|
205
|
+
this.selectService = context.get(WorkflowSelectService2);
|
|
206
|
+
this.groupService = context.get(WorkflowGroupService);
|
|
207
|
+
this.execute = this.execute.bind(this);
|
|
208
|
+
}
|
|
209
|
+
async execute(_groupNode) {
|
|
210
|
+
const groupNode = _groupNode || this.selectService.activatedNode;
|
|
211
|
+
if (!groupNode || groupNode.flowNodeType !== FlowNodeBaseType3.GROUP) {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
this.groupService.ungroup(groupNode);
|
|
215
|
+
this.selectService.clear();
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
// src/group-node.tsx
|
|
220
|
+
import { FlowNodeBaseType as FlowNodeBaseType4, FlowNodeTransformData } from "@flowgram.ai/document";
|
|
221
|
+
var GroupNodeRegistry = {
|
|
222
|
+
type: FlowNodeBaseType4.GROUP,
|
|
223
|
+
meta: {
|
|
224
|
+
renderKey: FlowNodeBaseType4.GROUP,
|
|
225
|
+
defaultPorts: [],
|
|
226
|
+
isContainer: true,
|
|
227
|
+
disableSideBar: true,
|
|
228
|
+
size: {
|
|
229
|
+
width: 560,
|
|
230
|
+
height: 400
|
|
231
|
+
},
|
|
232
|
+
padding: () => ({
|
|
233
|
+
top: 80,
|
|
234
|
+
bottom: 40,
|
|
235
|
+
left: 65,
|
|
236
|
+
right: 65
|
|
237
|
+
}),
|
|
238
|
+
selectable(node, mousePos) {
|
|
239
|
+
if (!mousePos) {
|
|
240
|
+
return true;
|
|
241
|
+
}
|
|
242
|
+
const transform = node.getData(FlowNodeTransformData);
|
|
243
|
+
return !transform.bounds.contains(mousePos.x, mousePos.y);
|
|
244
|
+
},
|
|
245
|
+
expandable: false
|
|
246
|
+
},
|
|
247
|
+
formMeta: {
|
|
248
|
+
render: () => /* @__PURE__ */ React.createElement(React.Fragment, null)
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
// src/create-free-group-plugin.tsx
|
|
253
|
+
var createFreeGroupPlugin = definePluginCreator(
|
|
254
|
+
{
|
|
255
|
+
onBind({ bind, rebind }, opts) {
|
|
256
|
+
bind(WorkflowGroupService).toSelf().inSingletonScope();
|
|
257
|
+
bind(WorkflowGroupPluginOptions).toConstantValue(opts);
|
|
258
|
+
rebind(FlowGroupService2).toService(WorkflowGroupService);
|
|
259
|
+
},
|
|
260
|
+
onInit(ctx, { groupNodeRender, disableGroupShortcuts = false, disableGroupNodeRegister = false }) {
|
|
261
|
+
if (groupNodeRender) {
|
|
262
|
+
const renderRegistry = ctx.get(FlowRendererRegistry);
|
|
263
|
+
renderRegistry.registerReactComponent(FlowNodeBaseType5.GROUP, groupNodeRender);
|
|
264
|
+
}
|
|
265
|
+
if (!disableGroupShortcuts) {
|
|
266
|
+
const shortcutsRegistry = ctx.get(ShortcutsRegistry);
|
|
267
|
+
shortcutsRegistry.addHandlers(new GroupShortcut(ctx), new UngroupShortcut(ctx));
|
|
268
|
+
}
|
|
269
|
+
if (!disableGroupNodeRegister) {
|
|
270
|
+
const document = ctx.get(WorkflowDocument2);
|
|
271
|
+
document.registerFlowNodes(GroupNodeRegistry);
|
|
272
|
+
}
|
|
273
|
+
},
|
|
274
|
+
onReady(ctx) {
|
|
275
|
+
const groupService = ctx.get(WorkflowGroupService);
|
|
276
|
+
groupService.ready();
|
|
277
|
+
},
|
|
278
|
+
onDispose(ctx) {
|
|
279
|
+
const groupService = ctx.get(WorkflowGroupService);
|
|
280
|
+
groupService.dispose();
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
);
|
|
284
|
+
export {
|
|
285
|
+
WorkflowGroupCommand,
|
|
286
|
+
WorkflowGroupService,
|
|
287
|
+
createFreeGroupPlugin
|
|
288
|
+
};
|
|
289
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/create-free-group-plugin.tsx","../../src/workflow-group-service.ts","../../src/utils.ts","../../src/type.ts","../../src/shortcuts/group.ts","../../src/constant.ts","../../src/shortcuts/ungroup.ts","../../src/group-node.tsx"],"sourcesContent":["/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { ShortcutsRegistry } from '@flowgram.ai/shortcuts-plugin';\nimport { FlowRendererRegistry } from '@flowgram.ai/renderer';\nimport { WorkflowDocument } from '@flowgram.ai/free-layout-core';\nimport { FlowGroupService, FlowNodeBaseType } from '@flowgram.ai/document';\nimport { definePluginCreator, PluginContext } from '@flowgram.ai/core';\n\nimport { WorkflowGroupService } from './workflow-group-service';\nimport { WorkflowGroupPluginOptions } from './type';\nimport { GroupShortcut, UngroupShortcut } from './shortcuts';\nimport { GroupNodeRegistry } from './group-node';\n\nexport const createFreeGroupPlugin = definePluginCreator<WorkflowGroupPluginOptions, PluginContext>(\n {\n onBind({ bind, rebind }, opts) {\n bind(WorkflowGroupService).toSelf().inSingletonScope();\n bind(WorkflowGroupPluginOptions).toConstantValue(opts);\n rebind(FlowGroupService).toService(WorkflowGroupService);\n },\n onInit(\n ctx,\n { groupNodeRender, disableGroupShortcuts = false, disableGroupNodeRegister = false }\n ) {\n // register node render\n if (groupNodeRender) {\n const renderRegistry = ctx.get<FlowRendererRegistry>(FlowRendererRegistry);\n renderRegistry.registerReactComponent(FlowNodeBaseType.GROUP, groupNodeRender);\n }\n // register shortcuts\n if (!disableGroupShortcuts) {\n const shortcutsRegistry = ctx.get(ShortcutsRegistry);\n shortcutsRegistry.addHandlers(new GroupShortcut(ctx), new UngroupShortcut(ctx));\n }\n if (!disableGroupNodeRegister) {\n const document = ctx.get(WorkflowDocument);\n document.registerFlowNodes(GroupNodeRegistry);\n }\n },\n onReady(ctx) {\n const groupService = ctx.get(WorkflowGroupService);\n groupService.ready();\n },\n onDispose(ctx) {\n const groupService = ctx.get(WorkflowGroupService);\n groupService.dispose();\n },\n }\n);\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { injectable, inject } from 'inversify';\nimport { DisposableCollection, Disposable } from '@flowgram.ai/utils';\nimport {\n WorkflowDocument,\n WorkflowOperationBaseService,\n WorkflowNodeEntity,\n nanoid,\n WorkflowNodeJSON,\n} from '@flowgram.ai/free-layout-core';\nimport { HistoryService } from '@flowgram.ai/free-history-plugin';\nimport {\n NodeIntoContainerService,\n NodeIntoContainerType,\n} from '@flowgram.ai/free-container-plugin';\nimport { FlowGroupService, FlowNodeBaseType } from '@flowgram.ai/document';\nimport { TransformData } from '@flowgram.ai/core';\n\nimport { WorkflowGroupUtils } from './utils';\nimport { WorkflowGroupPluginOptions } from './type';\n\n@injectable()\n/** 分组服务 */\nexport class WorkflowGroupService extends FlowGroupService {\n @inject(WorkflowDocument) private document: WorkflowDocument;\n\n @inject(WorkflowOperationBaseService) freeOperationService: WorkflowOperationBaseService;\n\n @inject(HistoryService) private historyService: HistoryService;\n\n @inject(NodeIntoContainerService) private nodeIntoContainerService: NodeIntoContainerService;\n\n @inject(WorkflowGroupPluginOptions) private opts: WorkflowGroupPluginOptions;\n\n private toDispose = new DisposableCollection();\n\n public ready(): void {\n this.toDispose.push(this.listenContainer());\n }\n\n public dispose(): void {\n this.toDispose.dispose();\n }\n\n /** 创建分组节点 */\n public createGroup(nodes: WorkflowNodeEntity[]): WorkflowNodeEntity | undefined {\n if (!WorkflowGroupUtils.validate(nodes)) {\n return;\n }\n const parent = nodes[0].parent ?? this.document.root;\n let groupJSON: WorkflowNodeJSON = {\n type: FlowNodeBaseType.GROUP,\n id: `group_${nanoid(5)}`,\n meta: {\n position: {\n x: 0,\n y: 0,\n },\n },\n data: {},\n };\n if (this.opts.initGroupJSON) {\n groupJSON = this.opts.initGroupJSON(groupJSON, nodes);\n }\n this.historyService.startTransaction();\n this.document.createWorkflowNodeByType(\n FlowNodeBaseType.GROUP,\n {\n x: 0,\n y: 0,\n },\n groupJSON,\n parent.id\n );\n nodes.forEach((node) => {\n this.freeOperationService.moveNode(node, {\n parent: groupJSON.id,\n });\n });\n this.historyService.endTransaction();\n }\n\n /** 取消分组 */\n public ungroup(groupNode: WorkflowNodeEntity): void {\n const groupBlocks = groupNode.blocks.slice();\n if (!groupNode.parent) {\n return;\n }\n const groupPosition = groupNode.transform.position;\n\n this.historyService.startTransaction();\n groupBlocks.forEach((node) => {\n this.freeOperationService.moveNode(node, {\n parent: groupNode.parent?.id,\n });\n });\n groupNode.dispose();\n groupBlocks.forEach((node) => {\n const transform = node.getData(TransformData);\n const position = {\n x: transform.position.x + groupPosition.x,\n y: transform.position.y + groupPosition.y,\n };\n this.freeOperationService.updateNodePosition(node, position);\n });\n this.historyService.endTransaction();\n }\n\n private listenContainer(): Disposable {\n return this.nodeIntoContainerService.on((e) => {\n if (\n e.type !== NodeIntoContainerType.Out ||\n e.sourceContainer?.flowNodeType !== FlowNodeBaseType.GROUP\n ) {\n return;\n }\n if (e.sourceContainer?.blocks.length === 0) {\n e.sourceContainer.dispose();\n }\n });\n }\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { WorkflowNodeEntity } from '@flowgram.ai/free-layout-core';\nimport { FlowNodeBaseType } from '@flowgram.ai/document';\n\nexport namespace WorkflowGroupUtils {\n /** 找到节点所有上级 */\n // const findNodeParents = (node: WorkflowNodeEntity): WorkflowNodeEntity[] => {\n // const parents = [];\n // let parent = node.parent;\n // while (parent) {\n // parents.push(parent);\n // parent = parent.parent;\n // }\n // return parents;\n // };\n\n /** 节点是否处于分组中 */\n const isNodeInGroup = (node: WorkflowNodeEntity): boolean => {\n // 处于分组中\n if (node?.parent?.flowNodeType === FlowNodeBaseType.GROUP) {\n return true;\n }\n return false;\n };\n\n /** 是否分组节点 */\n const isGroupNode = (group: WorkflowNodeEntity): boolean =>\n group.flowNodeType === FlowNodeBaseType.GROUP;\n\n /** 判断节点能否组成分组 */\n export const validate = (nodes: WorkflowNodeEntity[]): boolean => {\n if (!nodes || !Array.isArray(nodes) || nodes.length === 0) {\n // 参数不合法\n return false;\n }\n\n // 判断是否有分组节点\n const isGroupRelatedNode = nodes.some((node) => isGroupNode(node));\n if (isGroupRelatedNode) return false;\n\n // 判断是否有节点已经处于分组中\n const hasGroup = nodes.some((node) => node && isNodeInGroup(node));\n if (hasGroup) return false;\n\n // 判断是否来自同一个父亲\n const parent = nodes[0].parent;\n const isSameParent = nodes.every((node) => node.parent === parent);\n if (!isSameParent) return false;\n\n // 判断节点父亲是否已经在分组中\n // const parents = findNodeParents(nodes[0]);\n // const parentsInGroup = parents.some((parent) => isNodeInGroup(parent));\n // if (parentsInGroup) return false;\n\n // 参数正确\n return true;\n };\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { FC } from 'react';\n\nimport { WorkflowNodeEntity, WorkflowNodeJSON } from '@flowgram.ai/free-layout-core';\n\nexport interface WorkflowGroupPluginOptions {\n groupNodeRender: FC;\n disableGroupShortcuts?: boolean;\n disableGroupNodeRegister?: boolean;\n initGroupJSON?: (json: WorkflowNodeJSON, nodes: WorkflowNodeEntity[]) => WorkflowNodeJSON;\n}\n\nexport const WorkflowGroupPluginOptions = Symbol('WorkflowGroupPluginOptions');\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { ShortcutsHandler } from '@flowgram.ai/shortcuts-plugin';\nimport { WorkflowSelectService } from '@flowgram.ai/free-layout-core';\nimport { PluginContext } from '@flowgram.ai/core';\n\nimport { WorkflowGroupService } from '../workflow-group-service';\nimport { WorkflowGroupCommand } from '../constant';\n\nexport class GroupShortcut implements ShortcutsHandler {\n public commandId = WorkflowGroupCommand.Group;\n\n public commandDetail: ShortcutsHandler['commandDetail'] = {\n label: 'Group',\n };\n\n public shortcuts = ['meta g', 'ctrl g'];\n\n private selectService: WorkflowSelectService;\n\n private groupService: WorkflowGroupService;\n\n constructor(context: PluginContext) {\n this.selectService = context.get(WorkflowSelectService);\n this.groupService = context.get(WorkflowGroupService);\n this.execute = this.execute.bind(this);\n }\n\n public async execute(): Promise<void> {\n this.groupService.createGroup(this.selectService.selectedNodes);\n this.selectService.clear();\n }\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nexport enum WorkflowGroupCommand {\n Group = 'group',\n Ungroup = 'ungroup',\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { ShortcutsHandler } from '@flowgram.ai/shortcuts-plugin';\nimport { WorkflowSelectService, WorkflowNodeEntity } from '@flowgram.ai/free-layout-core';\nimport { FlowNodeBaseType } from '@flowgram.ai/document';\nimport { PluginContext } from '@flowgram.ai/core';\n\nimport { WorkflowGroupService } from '../workflow-group-service';\nimport { WorkflowGroupCommand } from '../constant';\n\nexport class UngroupShortcut implements ShortcutsHandler {\n public commandId = WorkflowGroupCommand.Ungroup;\n\n public commandDetail: ShortcutsHandler['commandDetail'] = {\n label: 'Ungroup',\n };\n\n public shortcuts = ['meta shift g', 'ctrl shift g'];\n\n private selectService: WorkflowSelectService;\n\n private groupService: WorkflowGroupService;\n\n constructor(context: PluginContext) {\n this.selectService = context.get(WorkflowSelectService);\n this.groupService = context.get(WorkflowGroupService);\n this.execute = this.execute.bind(this);\n }\n\n public async execute(_groupNode?: WorkflowNodeEntity): Promise<void> {\n const groupNode = _groupNode || this.selectService.activatedNode;\n if (!groupNode || groupNode.flowNodeType !== FlowNodeBaseType.GROUP) {\n return;\n }\n this.groupService.ungroup(groupNode);\n this.selectService.clear();\n }\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { PositionSchema } from '@flowgram.ai/utils';\nimport { WorkflowNodeEntity } from '@flowgram.ai/free-layout-core';\nimport { FlowNodeRegistry, FlowNodeBaseType, FlowNodeTransformData } from '@flowgram.ai/document';\n\nexport const GroupNodeRegistry: FlowNodeRegistry = {\n type: FlowNodeBaseType.GROUP,\n meta: {\n renderKey: FlowNodeBaseType.GROUP,\n defaultPorts: [],\n isContainer: true,\n disableSideBar: true,\n size: {\n width: 560,\n height: 400,\n },\n padding: () => ({\n top: 80,\n bottom: 40,\n left: 65,\n right: 65,\n }),\n selectable(node: WorkflowNodeEntity, mousePos?: PositionSchema): boolean {\n if (!mousePos) {\n return true;\n }\n const transform = node.getData<FlowNodeTransformData>(FlowNodeTransformData);\n return !transform.bounds.contains(mousePos.x, mousePos.y);\n },\n expandable: false,\n },\n formMeta: {\n render: () => <></>,\n },\n};\n"],"mappings":"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","names":["WorkflowDocument","FlowGroupService","FlowNodeBaseType","FlowNodeBaseType","WorkflowGroupUtils","FlowNodeBaseType","WorkflowGroupCommand","WorkflowSelectService","FlowNodeBaseType","WorkflowSelectService","FlowNodeBaseType","FlowNodeBaseType","FlowGroupService","FlowNodeBaseType","WorkflowDocument"]}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import * as _flowgram_ai_core from '@flowgram.ai/core';
|
|
2
|
+
import { FC } from 'react';
|
|
3
|
+
import { WorkflowNodeJSON, WorkflowNodeEntity, WorkflowOperationBaseService } from '@flowgram.ai/free-layout-core';
|
|
4
|
+
import { FlowGroupService } from '@flowgram.ai/document';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
|
8
|
+
* SPDX-License-Identifier: MIT
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
interface WorkflowGroupPluginOptions {
|
|
12
|
+
groupNodeRender: FC;
|
|
13
|
+
disableGroupShortcuts?: boolean;
|
|
14
|
+
disableGroupNodeRegister?: boolean;
|
|
15
|
+
initGroupJSON?: (json: WorkflowNodeJSON, nodes: WorkflowNodeEntity[]) => WorkflowNodeJSON;
|
|
16
|
+
}
|
|
17
|
+
declare const WorkflowGroupPluginOptions: unique symbol;
|
|
18
|
+
|
|
19
|
+
declare const createFreeGroupPlugin: _flowgram_ai_core.PluginCreator<WorkflowGroupPluginOptions>;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
|
23
|
+
* SPDX-License-Identifier: MIT
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
declare class WorkflowGroupService extends FlowGroupService {
|
|
27
|
+
private document;
|
|
28
|
+
freeOperationService: WorkflowOperationBaseService;
|
|
29
|
+
private historyService;
|
|
30
|
+
private nodeIntoContainerService;
|
|
31
|
+
private opts;
|
|
32
|
+
private toDispose;
|
|
33
|
+
ready(): void;
|
|
34
|
+
dispose(): void;
|
|
35
|
+
/** 创建分组节点 */
|
|
36
|
+
createGroup(nodes: WorkflowNodeEntity[]): WorkflowNodeEntity | undefined;
|
|
37
|
+
/** 取消分组 */
|
|
38
|
+
ungroup(groupNode: WorkflowNodeEntity): void;
|
|
39
|
+
private listenContainer;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
|
44
|
+
* SPDX-License-Identifier: MIT
|
|
45
|
+
*/
|
|
46
|
+
declare enum WorkflowGroupCommand {
|
|
47
|
+
Group = "group",
|
|
48
|
+
Ungroup = "ungroup"
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export { WorkflowGroupCommand, WorkflowGroupService, createFreeGroupPlugin };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import * as _flowgram_ai_core from '@flowgram.ai/core';
|
|
2
|
+
import { FC } from 'react';
|
|
3
|
+
import { WorkflowNodeJSON, WorkflowNodeEntity, WorkflowOperationBaseService } from '@flowgram.ai/free-layout-core';
|
|
4
|
+
import { FlowGroupService } from '@flowgram.ai/document';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
|
8
|
+
* SPDX-License-Identifier: MIT
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
interface WorkflowGroupPluginOptions {
|
|
12
|
+
groupNodeRender: FC;
|
|
13
|
+
disableGroupShortcuts?: boolean;
|
|
14
|
+
disableGroupNodeRegister?: boolean;
|
|
15
|
+
initGroupJSON?: (json: WorkflowNodeJSON, nodes: WorkflowNodeEntity[]) => WorkflowNodeJSON;
|
|
16
|
+
}
|
|
17
|
+
declare const WorkflowGroupPluginOptions: unique symbol;
|
|
18
|
+
|
|
19
|
+
declare const createFreeGroupPlugin: _flowgram_ai_core.PluginCreator<WorkflowGroupPluginOptions>;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
|
23
|
+
* SPDX-License-Identifier: MIT
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
declare class WorkflowGroupService extends FlowGroupService {
|
|
27
|
+
private document;
|
|
28
|
+
freeOperationService: WorkflowOperationBaseService;
|
|
29
|
+
private historyService;
|
|
30
|
+
private nodeIntoContainerService;
|
|
31
|
+
private opts;
|
|
32
|
+
private toDispose;
|
|
33
|
+
ready(): void;
|
|
34
|
+
dispose(): void;
|
|
35
|
+
/** 创建分组节点 */
|
|
36
|
+
createGroup(nodes: WorkflowNodeEntity[]): WorkflowNodeEntity | undefined;
|
|
37
|
+
/** 取消分组 */
|
|
38
|
+
ungroup(groupNode: WorkflowNodeEntity): void;
|
|
39
|
+
private listenContainer;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
|
44
|
+
* SPDX-License-Identifier: MIT
|
|
45
|
+
*/
|
|
46
|
+
declare enum WorkflowGroupCommand {
|
|
47
|
+
Group = "group",
|
|
48
|
+
Ungroup = "ungroup"
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export { WorkflowGroupCommand, WorkflowGroupService, createFreeGroupPlugin };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
20
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
21
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
22
|
+
if (decorator = decorators[i])
|
|
23
|
+
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
24
|
+
if (kind && result) __defProp(target, key, result);
|
|
25
|
+
return result;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// src/index.ts
|
|
29
|
+
var src_exports = {};
|
|
30
|
+
__export(src_exports, {
|
|
31
|
+
WorkflowGroupCommand: () => WorkflowGroupCommand,
|
|
32
|
+
WorkflowGroupService: () => WorkflowGroupService,
|
|
33
|
+
createFreeGroupPlugin: () => createFreeGroupPlugin
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(src_exports);
|
|
36
|
+
|
|
37
|
+
// src/create-free-group-plugin.tsx
|
|
38
|
+
var import_shortcuts_plugin = require("@flowgram.ai/shortcuts-plugin");
|
|
39
|
+
var import_renderer = require("@flowgram.ai/renderer");
|
|
40
|
+
var import_free_layout_core4 = require("@flowgram.ai/free-layout-core");
|
|
41
|
+
var import_document5 = require("@flowgram.ai/document");
|
|
42
|
+
var import_core2 = require("@flowgram.ai/core");
|
|
43
|
+
|
|
44
|
+
// src/workflow-group-service.ts
|
|
45
|
+
var import_inversify = require("inversify");
|
|
46
|
+
var import_utils = require("@flowgram.ai/utils");
|
|
47
|
+
var import_free_layout_core = require("@flowgram.ai/free-layout-core");
|
|
48
|
+
var import_free_history_plugin = require("@flowgram.ai/free-history-plugin");
|
|
49
|
+
var import_free_container_plugin = require("@flowgram.ai/free-container-plugin");
|
|
50
|
+
var import_document2 = require("@flowgram.ai/document");
|
|
51
|
+
var import_core = require("@flowgram.ai/core");
|
|
52
|
+
|
|
53
|
+
// src/utils.ts
|
|
54
|
+
var import_document = require("@flowgram.ai/document");
|
|
55
|
+
var WorkflowGroupUtils;
|
|
56
|
+
((WorkflowGroupUtils2) => {
|
|
57
|
+
const isNodeInGroup = (node) => {
|
|
58
|
+
if (node?.parent?.flowNodeType === import_document.FlowNodeBaseType.GROUP) {
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
return false;
|
|
62
|
+
};
|
|
63
|
+
const isGroupNode = (group) => group.flowNodeType === import_document.FlowNodeBaseType.GROUP;
|
|
64
|
+
WorkflowGroupUtils2.validate = (nodes) => {
|
|
65
|
+
if (!nodes || !Array.isArray(nodes) || nodes.length === 0) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
const isGroupRelatedNode = nodes.some((node) => isGroupNode(node));
|
|
69
|
+
if (isGroupRelatedNode) return false;
|
|
70
|
+
const hasGroup = nodes.some((node) => node && isNodeInGroup(node));
|
|
71
|
+
if (hasGroup) return false;
|
|
72
|
+
const parent = nodes[0].parent;
|
|
73
|
+
const isSameParent = nodes.every((node) => node.parent === parent);
|
|
74
|
+
if (!isSameParent) return false;
|
|
75
|
+
return true;
|
|
76
|
+
};
|
|
77
|
+
})(WorkflowGroupUtils || (WorkflowGroupUtils = {}));
|
|
78
|
+
|
|
79
|
+
// src/type.ts
|
|
80
|
+
var WorkflowGroupPluginOptions = Symbol("WorkflowGroupPluginOptions");
|
|
81
|
+
|
|
82
|
+
// src/workflow-group-service.ts
|
|
83
|
+
var WorkflowGroupService = class extends import_document2.FlowGroupService {
|
|
84
|
+
constructor() {
|
|
85
|
+
super(...arguments);
|
|
86
|
+
this.toDispose = new import_utils.DisposableCollection();
|
|
87
|
+
}
|
|
88
|
+
ready() {
|
|
89
|
+
this.toDispose.push(this.listenContainer());
|
|
90
|
+
}
|
|
91
|
+
dispose() {
|
|
92
|
+
this.toDispose.dispose();
|
|
93
|
+
}
|
|
94
|
+
/** 创建分组节点 */
|
|
95
|
+
createGroup(nodes) {
|
|
96
|
+
if (!WorkflowGroupUtils.validate(nodes)) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const parent = nodes[0].parent ?? this.document.root;
|
|
100
|
+
let groupJSON = {
|
|
101
|
+
type: import_document2.FlowNodeBaseType.GROUP,
|
|
102
|
+
id: `group_${(0, import_free_layout_core.nanoid)(5)}`,
|
|
103
|
+
meta: {
|
|
104
|
+
position: {
|
|
105
|
+
x: 0,
|
|
106
|
+
y: 0
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
data: {}
|
|
110
|
+
};
|
|
111
|
+
if (this.opts.initGroupJSON) {
|
|
112
|
+
groupJSON = this.opts.initGroupJSON(groupJSON, nodes);
|
|
113
|
+
}
|
|
114
|
+
this.historyService.startTransaction();
|
|
115
|
+
this.document.createWorkflowNodeByType(
|
|
116
|
+
import_document2.FlowNodeBaseType.GROUP,
|
|
117
|
+
{
|
|
118
|
+
x: 0,
|
|
119
|
+
y: 0
|
|
120
|
+
},
|
|
121
|
+
groupJSON,
|
|
122
|
+
parent.id
|
|
123
|
+
);
|
|
124
|
+
nodes.forEach((node) => {
|
|
125
|
+
this.freeOperationService.moveNode(node, {
|
|
126
|
+
parent: groupJSON.id
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
this.historyService.endTransaction();
|
|
130
|
+
}
|
|
131
|
+
/** 取消分组 */
|
|
132
|
+
ungroup(groupNode) {
|
|
133
|
+
const groupBlocks = groupNode.blocks.slice();
|
|
134
|
+
if (!groupNode.parent) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
const groupPosition = groupNode.transform.position;
|
|
138
|
+
this.historyService.startTransaction();
|
|
139
|
+
groupBlocks.forEach((node) => {
|
|
140
|
+
this.freeOperationService.moveNode(node, {
|
|
141
|
+
parent: groupNode.parent?.id
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
groupNode.dispose();
|
|
145
|
+
groupBlocks.forEach((node) => {
|
|
146
|
+
const transform = node.getData(import_core.TransformData);
|
|
147
|
+
const position = {
|
|
148
|
+
x: transform.position.x + groupPosition.x,
|
|
149
|
+
y: transform.position.y + groupPosition.y
|
|
150
|
+
};
|
|
151
|
+
this.freeOperationService.updateNodePosition(node, position);
|
|
152
|
+
});
|
|
153
|
+
this.historyService.endTransaction();
|
|
154
|
+
}
|
|
155
|
+
listenContainer() {
|
|
156
|
+
return this.nodeIntoContainerService.on((e) => {
|
|
157
|
+
if (e.type !== import_free_container_plugin.NodeIntoContainerType.Out || e.sourceContainer?.flowNodeType !== import_document2.FlowNodeBaseType.GROUP) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
if (e.sourceContainer?.blocks.length === 0) {
|
|
161
|
+
e.sourceContainer.dispose();
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
__decorateClass([
|
|
167
|
+
(0, import_inversify.inject)(import_free_layout_core.WorkflowDocument)
|
|
168
|
+
], WorkflowGroupService.prototype, "document", 2);
|
|
169
|
+
__decorateClass([
|
|
170
|
+
(0, import_inversify.inject)(import_free_layout_core.WorkflowOperationBaseService)
|
|
171
|
+
], WorkflowGroupService.prototype, "freeOperationService", 2);
|
|
172
|
+
__decorateClass([
|
|
173
|
+
(0, import_inversify.inject)(import_free_history_plugin.HistoryService)
|
|
174
|
+
], WorkflowGroupService.prototype, "historyService", 2);
|
|
175
|
+
__decorateClass([
|
|
176
|
+
(0, import_inversify.inject)(import_free_container_plugin.NodeIntoContainerService)
|
|
177
|
+
], WorkflowGroupService.prototype, "nodeIntoContainerService", 2);
|
|
178
|
+
__decorateClass([
|
|
179
|
+
(0, import_inversify.inject)(WorkflowGroupPluginOptions)
|
|
180
|
+
], WorkflowGroupService.prototype, "opts", 2);
|
|
181
|
+
WorkflowGroupService = __decorateClass([
|
|
182
|
+
(0, import_inversify.injectable)()
|
|
183
|
+
], WorkflowGroupService);
|
|
184
|
+
|
|
185
|
+
// src/shortcuts/group.ts
|
|
186
|
+
var import_free_layout_core2 = require("@flowgram.ai/free-layout-core");
|
|
187
|
+
|
|
188
|
+
// src/constant.ts
|
|
189
|
+
var WorkflowGroupCommand = /* @__PURE__ */ ((WorkflowGroupCommand2) => {
|
|
190
|
+
WorkflowGroupCommand2["Group"] = "group";
|
|
191
|
+
WorkflowGroupCommand2["Ungroup"] = "ungroup";
|
|
192
|
+
return WorkflowGroupCommand2;
|
|
193
|
+
})(WorkflowGroupCommand || {});
|
|
194
|
+
|
|
195
|
+
// src/shortcuts/group.ts
|
|
196
|
+
var GroupShortcut = class {
|
|
197
|
+
constructor(context) {
|
|
198
|
+
this.commandId = "group" /* Group */;
|
|
199
|
+
this.commandDetail = {
|
|
200
|
+
label: "Group"
|
|
201
|
+
};
|
|
202
|
+
this.shortcuts = ["meta g", "ctrl g"];
|
|
203
|
+
this.selectService = context.get(import_free_layout_core2.WorkflowSelectService);
|
|
204
|
+
this.groupService = context.get(WorkflowGroupService);
|
|
205
|
+
this.execute = this.execute.bind(this);
|
|
206
|
+
}
|
|
207
|
+
async execute() {
|
|
208
|
+
this.groupService.createGroup(this.selectService.selectedNodes);
|
|
209
|
+
this.selectService.clear();
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
// src/shortcuts/ungroup.ts
|
|
214
|
+
var import_free_layout_core3 = require("@flowgram.ai/free-layout-core");
|
|
215
|
+
var import_document3 = require("@flowgram.ai/document");
|
|
216
|
+
var UngroupShortcut = class {
|
|
217
|
+
constructor(context) {
|
|
218
|
+
this.commandId = "ungroup" /* Ungroup */;
|
|
219
|
+
this.commandDetail = {
|
|
220
|
+
label: "Ungroup"
|
|
221
|
+
};
|
|
222
|
+
this.shortcuts = ["meta shift g", "ctrl shift g"];
|
|
223
|
+
this.selectService = context.get(import_free_layout_core3.WorkflowSelectService);
|
|
224
|
+
this.groupService = context.get(WorkflowGroupService);
|
|
225
|
+
this.execute = this.execute.bind(this);
|
|
226
|
+
}
|
|
227
|
+
async execute(_groupNode) {
|
|
228
|
+
const groupNode = _groupNode || this.selectService.activatedNode;
|
|
229
|
+
if (!groupNode || groupNode.flowNodeType !== import_document3.FlowNodeBaseType.GROUP) {
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
this.groupService.ungroup(groupNode);
|
|
233
|
+
this.selectService.clear();
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
// src/group-node.tsx
|
|
238
|
+
var import_document4 = require("@flowgram.ai/document");
|
|
239
|
+
var GroupNodeRegistry = {
|
|
240
|
+
type: import_document4.FlowNodeBaseType.GROUP,
|
|
241
|
+
meta: {
|
|
242
|
+
renderKey: import_document4.FlowNodeBaseType.GROUP,
|
|
243
|
+
defaultPorts: [],
|
|
244
|
+
isContainer: true,
|
|
245
|
+
disableSideBar: true,
|
|
246
|
+
size: {
|
|
247
|
+
width: 560,
|
|
248
|
+
height: 400
|
|
249
|
+
},
|
|
250
|
+
padding: () => ({
|
|
251
|
+
top: 80,
|
|
252
|
+
bottom: 40,
|
|
253
|
+
left: 65,
|
|
254
|
+
right: 65
|
|
255
|
+
}),
|
|
256
|
+
selectable(node, mousePos) {
|
|
257
|
+
if (!mousePos) {
|
|
258
|
+
return true;
|
|
259
|
+
}
|
|
260
|
+
const transform = node.getData(import_document4.FlowNodeTransformData);
|
|
261
|
+
return !transform.bounds.contains(mousePos.x, mousePos.y);
|
|
262
|
+
},
|
|
263
|
+
expandable: false
|
|
264
|
+
},
|
|
265
|
+
formMeta: {
|
|
266
|
+
render: () => /* @__PURE__ */ React.createElement(React.Fragment, null)
|
|
267
|
+
}
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
// src/create-free-group-plugin.tsx
|
|
271
|
+
var createFreeGroupPlugin = (0, import_core2.definePluginCreator)(
|
|
272
|
+
{
|
|
273
|
+
onBind({ bind, rebind }, opts) {
|
|
274
|
+
bind(WorkflowGroupService).toSelf().inSingletonScope();
|
|
275
|
+
bind(WorkflowGroupPluginOptions).toConstantValue(opts);
|
|
276
|
+
rebind(import_document5.FlowGroupService).toService(WorkflowGroupService);
|
|
277
|
+
},
|
|
278
|
+
onInit(ctx, { groupNodeRender, disableGroupShortcuts = false, disableGroupNodeRegister = false }) {
|
|
279
|
+
if (groupNodeRender) {
|
|
280
|
+
const renderRegistry = ctx.get(import_renderer.FlowRendererRegistry);
|
|
281
|
+
renderRegistry.registerReactComponent(import_document5.FlowNodeBaseType.GROUP, groupNodeRender);
|
|
282
|
+
}
|
|
283
|
+
if (!disableGroupShortcuts) {
|
|
284
|
+
const shortcutsRegistry = ctx.get(import_shortcuts_plugin.ShortcutsRegistry);
|
|
285
|
+
shortcutsRegistry.addHandlers(new GroupShortcut(ctx), new UngroupShortcut(ctx));
|
|
286
|
+
}
|
|
287
|
+
if (!disableGroupNodeRegister) {
|
|
288
|
+
const document = ctx.get(import_free_layout_core4.WorkflowDocument);
|
|
289
|
+
document.registerFlowNodes(GroupNodeRegistry);
|
|
290
|
+
}
|
|
291
|
+
},
|
|
292
|
+
onReady(ctx) {
|
|
293
|
+
const groupService = ctx.get(WorkflowGroupService);
|
|
294
|
+
groupService.ready();
|
|
295
|
+
},
|
|
296
|
+
onDispose(ctx) {
|
|
297
|
+
const groupService = ctx.get(WorkflowGroupService);
|
|
298
|
+
groupService.dispose();
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
);
|
|
302
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
303
|
+
0 && (module.exports = {
|
|
304
|
+
WorkflowGroupCommand,
|
|
305
|
+
WorkflowGroupService,
|
|
306
|
+
createFreeGroupPlugin
|
|
307
|
+
});
|
|
308
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/create-free-group-plugin.tsx","../src/workflow-group-service.ts","../src/utils.ts","../src/type.ts","../src/shortcuts/group.ts","../src/constant.ts","../src/shortcuts/ungroup.ts","../src/group-node.tsx"],"sourcesContent":["/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nexport { createFreeGroupPlugin } from './create-free-group-plugin';\nexport { WorkflowGroupService } from './workflow-group-service';\nexport { WorkflowGroupCommand } from './constant';\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { ShortcutsRegistry } from '@flowgram.ai/shortcuts-plugin';\nimport { FlowRendererRegistry } from '@flowgram.ai/renderer';\nimport { WorkflowDocument } from '@flowgram.ai/free-layout-core';\nimport { FlowGroupService, FlowNodeBaseType } from '@flowgram.ai/document';\nimport { definePluginCreator, PluginContext } from '@flowgram.ai/core';\n\nimport { WorkflowGroupService } from './workflow-group-service';\nimport { WorkflowGroupPluginOptions } from './type';\nimport { GroupShortcut, UngroupShortcut } from './shortcuts';\nimport { GroupNodeRegistry } from './group-node';\n\nexport const createFreeGroupPlugin = definePluginCreator<WorkflowGroupPluginOptions, PluginContext>(\n {\n onBind({ bind, rebind }, opts) {\n bind(WorkflowGroupService).toSelf().inSingletonScope();\n bind(WorkflowGroupPluginOptions).toConstantValue(opts);\n rebind(FlowGroupService).toService(WorkflowGroupService);\n },\n onInit(\n ctx,\n { groupNodeRender, disableGroupShortcuts = false, disableGroupNodeRegister = false }\n ) {\n // register node render\n if (groupNodeRender) {\n const renderRegistry = ctx.get<FlowRendererRegistry>(FlowRendererRegistry);\n renderRegistry.registerReactComponent(FlowNodeBaseType.GROUP, groupNodeRender);\n }\n // register shortcuts\n if (!disableGroupShortcuts) {\n const shortcutsRegistry = ctx.get(ShortcutsRegistry);\n shortcutsRegistry.addHandlers(new GroupShortcut(ctx), new UngroupShortcut(ctx));\n }\n if (!disableGroupNodeRegister) {\n const document = ctx.get(WorkflowDocument);\n document.registerFlowNodes(GroupNodeRegistry);\n }\n },\n onReady(ctx) {\n const groupService = ctx.get(WorkflowGroupService);\n groupService.ready();\n },\n onDispose(ctx) {\n const groupService = ctx.get(WorkflowGroupService);\n groupService.dispose();\n },\n }\n);\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { injectable, inject } from 'inversify';\nimport { DisposableCollection, Disposable } from '@flowgram.ai/utils';\nimport {\n WorkflowDocument,\n WorkflowOperationBaseService,\n WorkflowNodeEntity,\n nanoid,\n WorkflowNodeJSON,\n} from '@flowgram.ai/free-layout-core';\nimport { HistoryService } from '@flowgram.ai/free-history-plugin';\nimport {\n NodeIntoContainerService,\n NodeIntoContainerType,\n} from '@flowgram.ai/free-container-plugin';\nimport { FlowGroupService, FlowNodeBaseType } from '@flowgram.ai/document';\nimport { TransformData } from '@flowgram.ai/core';\n\nimport { WorkflowGroupUtils } from './utils';\nimport { WorkflowGroupPluginOptions } from './type';\n\n@injectable()\n/** 分组服务 */\nexport class WorkflowGroupService extends FlowGroupService {\n @inject(WorkflowDocument) private document: WorkflowDocument;\n\n @inject(WorkflowOperationBaseService) freeOperationService: WorkflowOperationBaseService;\n\n @inject(HistoryService) private historyService: HistoryService;\n\n @inject(NodeIntoContainerService) private nodeIntoContainerService: NodeIntoContainerService;\n\n @inject(WorkflowGroupPluginOptions) private opts: WorkflowGroupPluginOptions;\n\n private toDispose = new DisposableCollection();\n\n public ready(): void {\n this.toDispose.push(this.listenContainer());\n }\n\n public dispose(): void {\n this.toDispose.dispose();\n }\n\n /** 创建分组节点 */\n public createGroup(nodes: WorkflowNodeEntity[]): WorkflowNodeEntity | undefined {\n if (!WorkflowGroupUtils.validate(nodes)) {\n return;\n }\n const parent = nodes[0].parent ?? this.document.root;\n let groupJSON: WorkflowNodeJSON = {\n type: FlowNodeBaseType.GROUP,\n id: `group_${nanoid(5)}`,\n meta: {\n position: {\n x: 0,\n y: 0,\n },\n },\n data: {},\n };\n if (this.opts.initGroupJSON) {\n groupJSON = this.opts.initGroupJSON(groupJSON, nodes);\n }\n this.historyService.startTransaction();\n this.document.createWorkflowNodeByType(\n FlowNodeBaseType.GROUP,\n {\n x: 0,\n y: 0,\n },\n groupJSON,\n parent.id\n );\n nodes.forEach((node) => {\n this.freeOperationService.moveNode(node, {\n parent: groupJSON.id,\n });\n });\n this.historyService.endTransaction();\n }\n\n /** 取消分组 */\n public ungroup(groupNode: WorkflowNodeEntity): void {\n const groupBlocks = groupNode.blocks.slice();\n if (!groupNode.parent) {\n return;\n }\n const groupPosition = groupNode.transform.position;\n\n this.historyService.startTransaction();\n groupBlocks.forEach((node) => {\n this.freeOperationService.moveNode(node, {\n parent: groupNode.parent?.id,\n });\n });\n groupNode.dispose();\n groupBlocks.forEach((node) => {\n const transform = node.getData(TransformData);\n const position = {\n x: transform.position.x + groupPosition.x,\n y: transform.position.y + groupPosition.y,\n };\n this.freeOperationService.updateNodePosition(node, position);\n });\n this.historyService.endTransaction();\n }\n\n private listenContainer(): Disposable {\n return this.nodeIntoContainerService.on((e) => {\n if (\n e.type !== NodeIntoContainerType.Out ||\n e.sourceContainer?.flowNodeType !== FlowNodeBaseType.GROUP\n ) {\n return;\n }\n if (e.sourceContainer?.blocks.length === 0) {\n e.sourceContainer.dispose();\n }\n });\n }\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { WorkflowNodeEntity } from '@flowgram.ai/free-layout-core';\nimport { FlowNodeBaseType } from '@flowgram.ai/document';\n\nexport namespace WorkflowGroupUtils {\n /** 找到节点所有上级 */\n // const findNodeParents = (node: WorkflowNodeEntity): WorkflowNodeEntity[] => {\n // const parents = [];\n // let parent = node.parent;\n // while (parent) {\n // parents.push(parent);\n // parent = parent.parent;\n // }\n // return parents;\n // };\n\n /** 节点是否处于分组中 */\n const isNodeInGroup = (node: WorkflowNodeEntity): boolean => {\n // 处于分组中\n if (node?.parent?.flowNodeType === FlowNodeBaseType.GROUP) {\n return true;\n }\n return false;\n };\n\n /** 是否分组节点 */\n const isGroupNode = (group: WorkflowNodeEntity): boolean =>\n group.flowNodeType === FlowNodeBaseType.GROUP;\n\n /** 判断节点能否组成分组 */\n export const validate = (nodes: WorkflowNodeEntity[]): boolean => {\n if (!nodes || !Array.isArray(nodes) || nodes.length === 0) {\n // 参数不合法\n return false;\n }\n\n // 判断是否有分组节点\n const isGroupRelatedNode = nodes.some((node) => isGroupNode(node));\n if (isGroupRelatedNode) return false;\n\n // 判断是否有节点已经处于分组中\n const hasGroup = nodes.some((node) => node && isNodeInGroup(node));\n if (hasGroup) return false;\n\n // 判断是否来自同一个父亲\n const parent = nodes[0].parent;\n const isSameParent = nodes.every((node) => node.parent === parent);\n if (!isSameParent) return false;\n\n // 判断节点父亲是否已经在分组中\n // const parents = findNodeParents(nodes[0]);\n // const parentsInGroup = parents.some((parent) => isNodeInGroup(parent));\n // if (parentsInGroup) return false;\n\n // 参数正确\n return true;\n };\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { FC } from 'react';\n\nimport { WorkflowNodeEntity, WorkflowNodeJSON } from '@flowgram.ai/free-layout-core';\n\nexport interface WorkflowGroupPluginOptions {\n groupNodeRender: FC;\n disableGroupShortcuts?: boolean;\n disableGroupNodeRegister?: boolean;\n initGroupJSON?: (json: WorkflowNodeJSON, nodes: WorkflowNodeEntity[]) => WorkflowNodeJSON;\n}\n\nexport const WorkflowGroupPluginOptions = Symbol('WorkflowGroupPluginOptions');\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { ShortcutsHandler } from '@flowgram.ai/shortcuts-plugin';\nimport { WorkflowSelectService } from '@flowgram.ai/free-layout-core';\nimport { PluginContext } from '@flowgram.ai/core';\n\nimport { WorkflowGroupService } from '../workflow-group-service';\nimport { WorkflowGroupCommand } from '../constant';\n\nexport class GroupShortcut implements ShortcutsHandler {\n public commandId = WorkflowGroupCommand.Group;\n\n public commandDetail: ShortcutsHandler['commandDetail'] = {\n label: 'Group',\n };\n\n public shortcuts = ['meta g', 'ctrl g'];\n\n private selectService: WorkflowSelectService;\n\n private groupService: WorkflowGroupService;\n\n constructor(context: PluginContext) {\n this.selectService = context.get(WorkflowSelectService);\n this.groupService = context.get(WorkflowGroupService);\n this.execute = this.execute.bind(this);\n }\n\n public async execute(): Promise<void> {\n this.groupService.createGroup(this.selectService.selectedNodes);\n this.selectService.clear();\n }\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nexport enum WorkflowGroupCommand {\n Group = 'group',\n Ungroup = 'ungroup',\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { ShortcutsHandler } from '@flowgram.ai/shortcuts-plugin';\nimport { WorkflowSelectService, WorkflowNodeEntity } from '@flowgram.ai/free-layout-core';\nimport { FlowNodeBaseType } from '@flowgram.ai/document';\nimport { PluginContext } from '@flowgram.ai/core';\n\nimport { WorkflowGroupService } from '../workflow-group-service';\nimport { WorkflowGroupCommand } from '../constant';\n\nexport class UngroupShortcut implements ShortcutsHandler {\n public commandId = WorkflowGroupCommand.Ungroup;\n\n public commandDetail: ShortcutsHandler['commandDetail'] = {\n label: 'Ungroup',\n };\n\n public shortcuts = ['meta shift g', 'ctrl shift g'];\n\n private selectService: WorkflowSelectService;\n\n private groupService: WorkflowGroupService;\n\n constructor(context: PluginContext) {\n this.selectService = context.get(WorkflowSelectService);\n this.groupService = context.get(WorkflowGroupService);\n this.execute = this.execute.bind(this);\n }\n\n public async execute(_groupNode?: WorkflowNodeEntity): Promise<void> {\n const groupNode = _groupNode || this.selectService.activatedNode;\n if (!groupNode || groupNode.flowNodeType !== FlowNodeBaseType.GROUP) {\n return;\n }\n this.groupService.ungroup(groupNode);\n this.selectService.clear();\n }\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { PositionSchema } from '@flowgram.ai/utils';\nimport { WorkflowNodeEntity } from '@flowgram.ai/free-layout-core';\nimport { FlowNodeRegistry, FlowNodeBaseType, FlowNodeTransformData } from '@flowgram.ai/document';\n\nexport const GroupNodeRegistry: FlowNodeRegistry = {\n type: FlowNodeBaseType.GROUP,\n meta: {\n renderKey: FlowNodeBaseType.GROUP,\n defaultPorts: [],\n isContainer: true,\n disableSideBar: true,\n size: {\n width: 560,\n height: 400,\n },\n padding: () => ({\n top: 80,\n bottom: 40,\n left: 65,\n right: 65,\n }),\n selectable(node: WorkflowNodeEntity, mousePos?: PositionSchema): boolean {\n if (!mousePos) {\n return true;\n }\n const transform = node.getData<FlowNodeTransformData>(FlowNodeTransformData);\n return !transform.bounds.contains(mousePos.x, mousePos.y);\n },\n expandable: false,\n },\n formMeta: {\n render: () => <></>,\n },\n};\n"],"mappings":"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","names":["import_free_layout_core","import_document","import_core","import_document","WorkflowGroupUtils","import_free_layout_core","WorkflowGroupCommand","import_free_layout_core","import_document","import_document"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@flowgram.ai/free-group-plugin",
|
|
3
|
+
"version": "0.1.0-alpha.10",
|
|
4
|
+
"homepage": "https://flowgram.ai/",
|
|
5
|
+
"repository": "https://github.com/bytedance/flowgram.ai",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"exports": {
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"import": "./dist/esm/index.js",
|
|
10
|
+
"require": "./dist/index.js"
|
|
11
|
+
},
|
|
12
|
+
"main": "./dist/index.js",
|
|
13
|
+
"module": "./dist/esm/index.js",
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"inversify": "^6.0.1",
|
|
20
|
+
"reflect-metadata": "~0.2.2",
|
|
21
|
+
"lodash": "^4.17.21",
|
|
22
|
+
"@flowgram.ai/free-history-plugin": "0.1.0-alpha.10",
|
|
23
|
+
"@flowgram.ai/free-container-plugin": "0.1.0-alpha.10",
|
|
24
|
+
"@flowgram.ai/core": "0.1.0-alpha.10",
|
|
25
|
+
"@flowgram.ai/document": "0.1.0-alpha.10",
|
|
26
|
+
"@flowgram.ai/shortcuts-plugin": "0.1.0-alpha.10",
|
|
27
|
+
"@flowgram.ai/free-layout-core": "0.1.0-alpha.10",
|
|
28
|
+
"@flowgram.ai/free-lines-plugin": "0.1.0-alpha.10",
|
|
29
|
+
"@flowgram.ai/renderer": "0.1.0-alpha.10",
|
|
30
|
+
"@flowgram.ai/utils": "0.1.0-alpha.10"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/bezier-js": "4.1.3",
|
|
34
|
+
"@types/lodash": "^4.14.137",
|
|
35
|
+
"@types/react": "^18",
|
|
36
|
+
"@types/react-dom": "^18",
|
|
37
|
+
"@types/styled-components": "^5",
|
|
38
|
+
"@vitest/coverage-v8": "^0.32.0",
|
|
39
|
+
"eslint": "^8.54.0",
|
|
40
|
+
"react": "^18",
|
|
41
|
+
"react-dom": "^18",
|
|
42
|
+
"styled-components": "^5",
|
|
43
|
+
"tsup": "^8.0.1",
|
|
44
|
+
"typescript": "^5.0.4",
|
|
45
|
+
"vitest": "^0.34.6",
|
|
46
|
+
"@flowgram.ai/eslint-config": "0.1.0-alpha.10",
|
|
47
|
+
"@flowgram.ai/ts-config": "0.1.0-alpha.10"
|
|
48
|
+
},
|
|
49
|
+
"peerDependencies": {
|
|
50
|
+
"react": ">=16.8",
|
|
51
|
+
"react-dom": ">=16.8",
|
|
52
|
+
"styled-components": ">=4"
|
|
53
|
+
},
|
|
54
|
+
"publishConfig": {
|
|
55
|
+
"access": "public",
|
|
56
|
+
"registry": "https://registry.npmjs.org/"
|
|
57
|
+
},
|
|
58
|
+
"scripts": {
|
|
59
|
+
"build": "npm run build:fast -- --dts-resolve",
|
|
60
|
+
"build:fast": "tsup src/index.ts --format cjs,esm --sourcemap --legacy-output",
|
|
61
|
+
"build:watch": "npm run build:fast -- --dts-resolve",
|
|
62
|
+
"clean": "rimraf dist",
|
|
63
|
+
"test": "exit 0",
|
|
64
|
+
"test:cov": "exit 0",
|
|
65
|
+
"ts-check": "tsc --noEmit",
|
|
66
|
+
"watch": "npm run build:fast -- --dts-resolve --watch --ignore-watch dist"
|
|
67
|
+
}
|
|
68
|
+
}
|