@flowgram.ai/free-container-plugin 0.2.26 → 0.2.28
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 +120 -100
- package/dist/esm/index.js.map +1 -1
- package/dist/index.d.mts +25 -15
- package/dist/index.d.ts +25 -15
- package/dist/index.js +125 -100
- package/dist/index.js.map +1 -1
- package/package.json +14 -14
package/dist/esm/index.js
CHANGED
|
@@ -19,11 +19,7 @@ var NodeIntoContainerType = /* @__PURE__ */ ((NodeIntoContainerType2) => {
|
|
|
19
19
|
// src/node-into-container/service.ts
|
|
20
20
|
import { throttle } from "lodash";
|
|
21
21
|
import { inject, injectable } from "inversify";
|
|
22
|
-
import {
|
|
23
|
-
Rectangle,
|
|
24
|
-
DisposableCollection,
|
|
25
|
-
Emitter
|
|
26
|
-
} from "@flowgram.ai/utils";
|
|
22
|
+
import { DisposableCollection, Emitter } from "@flowgram.ai/utils";
|
|
27
23
|
import {
|
|
28
24
|
WorkflowDocument,
|
|
29
25
|
WorkflowDragService,
|
|
@@ -32,8 +28,102 @@ import {
|
|
|
32
28
|
WorkflowSelectService
|
|
33
29
|
} from "@flowgram.ai/free-layout-core";
|
|
34
30
|
import { HistoryService } from "@flowgram.ai/free-history-plugin";
|
|
35
|
-
import { FlowNodeRenderData, FlowNodeBaseType } from "@flowgram.ai/document";
|
|
31
|
+
import { FlowNodeRenderData, FlowNodeBaseType as FlowNodeBaseType2 } from "@flowgram.ai/document";
|
|
36
32
|
import { PlaygroundConfigEntity, TransformData } from "@flowgram.ai/core";
|
|
33
|
+
|
|
34
|
+
// src/utils/next-frame.ts
|
|
35
|
+
var nextFrame = async () => {
|
|
36
|
+
await new Promise((resolve) => requestAnimationFrame(resolve));
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// src/utils/is-container.ts
|
|
40
|
+
var isContainer = (node) => node?.getNodeMeta().isContainer ?? false;
|
|
41
|
+
|
|
42
|
+
// src/utils/get-container-transforms.ts
|
|
43
|
+
var getContainerTransforms = (allNodes) => allNodes.filter((node) => {
|
|
44
|
+
if (node.originParent) {
|
|
45
|
+
return node.getNodeMeta().selectable && node.originParent.getNodeMeta().selectable;
|
|
46
|
+
}
|
|
47
|
+
return node.getNodeMeta().selectable;
|
|
48
|
+
}).filter((node) => isContainer(node)).sort((a, b) => {
|
|
49
|
+
const aIndex = a.renderData.stackIndex;
|
|
50
|
+
const bIndex = b.renderData.stackIndex;
|
|
51
|
+
return bIndex - aIndex;
|
|
52
|
+
}).map((node) => node.transform);
|
|
53
|
+
|
|
54
|
+
// src/utils/get-collision-transform.ts
|
|
55
|
+
import { Rectangle } from "@flowgram.ai/utils";
|
|
56
|
+
|
|
57
|
+
// src/utils/is-rect-intersects.ts
|
|
58
|
+
var isRectIntersects = (rectA, rectB) => {
|
|
59
|
+
const hasHorizontalOverlap = rectA.right > rectB.left && rectA.left < rectB.right;
|
|
60
|
+
const hasVerticalOverlap = rectA.bottom > rectB.top && rectA.top < rectB.bottom;
|
|
61
|
+
return hasHorizontalOverlap && hasVerticalOverlap;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
// src/utils/is-point-in-rect.ts
|
|
65
|
+
var isPointInRect = (point, rect) => point.x >= rect.left && point.x <= rect.right && point.y >= rect.top && point.y <= rect.bottom;
|
|
66
|
+
|
|
67
|
+
// src/utils/get-collision-transform.ts
|
|
68
|
+
var getCollisionTransform = (params) => {
|
|
69
|
+
const { targetRect, targetPoint, transforms, withPadding = false, document } = params;
|
|
70
|
+
const collisionTransform = transforms.find((transform) => {
|
|
71
|
+
const { bounds, entity } = transform;
|
|
72
|
+
const padding = withPadding ? document.layout.getPadding(entity) : { left: 0, right: 0 };
|
|
73
|
+
const transformRect = new Rectangle(
|
|
74
|
+
bounds.x + padding.left + padding.right,
|
|
75
|
+
bounds.y,
|
|
76
|
+
bounds.width,
|
|
77
|
+
bounds.height
|
|
78
|
+
);
|
|
79
|
+
if (targetRect) {
|
|
80
|
+
return isRectIntersects(targetRect, transformRect);
|
|
81
|
+
}
|
|
82
|
+
if (targetPoint) {
|
|
83
|
+
return isPointInRect(targetPoint, transformRect);
|
|
84
|
+
}
|
|
85
|
+
return false;
|
|
86
|
+
});
|
|
87
|
+
return collisionTransform;
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
// src/utils/adjust-sub-node-position.ts
|
|
91
|
+
import { FlowNodeBaseType } from "@flowgram.ai/document";
|
|
92
|
+
var adjustSubNodePosition = (params) => {
|
|
93
|
+
const { targetNode, containerNode, containerPadding } = params;
|
|
94
|
+
if (containerNode.flowNodeType === FlowNodeBaseType.ROOT) {
|
|
95
|
+
return targetNode.transform.position;
|
|
96
|
+
}
|
|
97
|
+
const nodeWorldTransform = targetNode.transform.transform.worldTransform;
|
|
98
|
+
const containerWorldTransform = containerNode.transform.transform.worldTransform;
|
|
99
|
+
const nodePosition = {
|
|
100
|
+
x: nodeWorldTransform.tx,
|
|
101
|
+
y: nodeWorldTransform.ty
|
|
102
|
+
};
|
|
103
|
+
const isParentEmpty = !containerNode.children || containerNode.children.length === 0;
|
|
104
|
+
if (isParentEmpty) {
|
|
105
|
+
return {
|
|
106
|
+
x: 0,
|
|
107
|
+
y: containerPadding.top
|
|
108
|
+
};
|
|
109
|
+
} else {
|
|
110
|
+
return {
|
|
111
|
+
x: nodePosition.x - containerWorldTransform.tx,
|
|
112
|
+
y: nodePosition.y - containerWorldTransform.ty
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
// src/utils/index.ts
|
|
118
|
+
var ContainerUtils = {
|
|
119
|
+
nextFrame,
|
|
120
|
+
isContainer,
|
|
121
|
+
adjustSubNodePosition,
|
|
122
|
+
getContainerTransforms,
|
|
123
|
+
getCollisionTransform
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
// src/node-into-container/service.ts
|
|
37
127
|
var NodeIntoContainerService = class {
|
|
38
128
|
constructor() {
|
|
39
129
|
this.emitter = new Emitter();
|
|
@@ -57,14 +147,14 @@ var NodeIntoContainerService = class {
|
|
|
57
147
|
const parentNode = node.parent;
|
|
58
148
|
const containerNode = parentNode?.parent;
|
|
59
149
|
const nodeJSON = this.document.toNodeJSON(node);
|
|
60
|
-
if (!parentNode || !containerNode || !
|
|
150
|
+
if (!parentNode || !containerNode || !ContainerUtils.isContainer(parentNode) || !nodeJSON.meta?.position) {
|
|
61
151
|
return;
|
|
62
152
|
}
|
|
63
153
|
const parentTransform = parentNode.getData(TransformData);
|
|
64
154
|
this.operationService.moveNode(node, {
|
|
65
155
|
parent: containerNode
|
|
66
156
|
});
|
|
67
|
-
await
|
|
157
|
+
await ContainerUtils.nextFrame();
|
|
68
158
|
parentTransform.fireChange();
|
|
69
159
|
this.operationService.updateNodePosition(node, {
|
|
70
160
|
x: parentTransform.position.x + nodeJSON.meta.position.x,
|
|
@@ -81,7 +171,7 @@ var NodeIntoContainerService = class {
|
|
|
81
171
|
canMoveOutContainer(node) {
|
|
82
172
|
const parentNode = node.parent;
|
|
83
173
|
const containerNode = parentNode?.parent;
|
|
84
|
-
if (!parentNode || !containerNode || !
|
|
174
|
+
if (!parentNode || !containerNode || !ContainerUtils.isContainer(parentNode)) {
|
|
85
175
|
return false;
|
|
86
176
|
}
|
|
87
177
|
const canDrop = this.dragService.canDropToNode({
|
|
@@ -104,7 +194,7 @@ var NodeIntoContainerService = class {
|
|
|
104
194
|
if (dragNode.parent === sourceParent) {
|
|
105
195
|
return;
|
|
106
196
|
}
|
|
107
|
-
if (dragNode.parent?.flowNodeType ===
|
|
197
|
+
if (dragNode.parent?.flowNodeType === FlowNodeBaseType2.GROUP || sourceParent?.flowNodeType === FlowNodeBaseType2.GROUP) {
|
|
108
198
|
return;
|
|
109
199
|
}
|
|
110
200
|
await this.removeNodeLines(dragNode);
|
|
@@ -118,7 +208,7 @@ var NodeIntoContainerService = class {
|
|
|
118
208
|
}
|
|
119
209
|
line.dispose();
|
|
120
210
|
});
|
|
121
|
-
await
|
|
211
|
+
await ContainerUtils.nextFrame();
|
|
122
212
|
}
|
|
123
213
|
/** 初始化状态 */
|
|
124
214
|
initState() {
|
|
@@ -146,7 +236,7 @@ var NodeIntoContainerService = class {
|
|
|
146
236
|
}
|
|
147
237
|
this.historyService.startTransaction();
|
|
148
238
|
this.state.isDraggingNode = true;
|
|
149
|
-
this.state.transforms =
|
|
239
|
+
this.state.transforms = ContainerUtils.getContainerTransforms(this.document.getAllNodes());
|
|
150
240
|
this.state.dragNode = this.selectService.selectedNodes[0];
|
|
151
241
|
this.state.dropNode = void 0;
|
|
152
242
|
this.state.sourceParent = this.state.dragNode?.parent;
|
|
@@ -184,31 +274,9 @@ var NodeIntoContainerService = class {
|
|
|
184
274
|
this.moveOutContainer({ node: dragNode });
|
|
185
275
|
this.state.isSkipEvent = true;
|
|
186
276
|
event.dragger.stop(event.dragEvent.clientX, event.dragEvent.clientY);
|
|
187
|
-
await
|
|
277
|
+
await ContainerUtils.nextFrame();
|
|
188
278
|
this.dragService.startDragSelectedNodes(event.triggerEvent);
|
|
189
279
|
}
|
|
190
|
-
/** 获取重叠位置 */
|
|
191
|
-
getCollisionTransform(params) {
|
|
192
|
-
const { targetRect, targetPoint, transforms, withPadding = false } = params;
|
|
193
|
-
const collisionTransform = transforms.find((transform) => {
|
|
194
|
-
const { bounds, entity } = transform;
|
|
195
|
-
const padding = withPadding ? this.document.layout.getPadding(entity) : { left: 0, right: 0 };
|
|
196
|
-
const transformRect = new Rectangle(
|
|
197
|
-
bounds.x + padding.left + padding.right,
|
|
198
|
-
bounds.y,
|
|
199
|
-
bounds.width,
|
|
200
|
-
bounds.height
|
|
201
|
-
);
|
|
202
|
-
if (targetRect) {
|
|
203
|
-
return this.isRectIntersects(targetRect, transformRect);
|
|
204
|
-
}
|
|
205
|
-
if (targetPoint) {
|
|
206
|
-
return this.isPointInRect(targetPoint, transformRect);
|
|
207
|
-
}
|
|
208
|
-
return false;
|
|
209
|
-
});
|
|
210
|
-
return collisionTransform;
|
|
211
|
-
}
|
|
212
280
|
/** 设置放置节点高亮 */
|
|
213
281
|
setDropNode(dropNode) {
|
|
214
282
|
if (this.state.dropNode === dropNode) {
|
|
@@ -231,19 +299,6 @@ var NodeIntoContainerService = class {
|
|
|
231
299
|
renderDom.classList.add("selected");
|
|
232
300
|
}
|
|
233
301
|
}
|
|
234
|
-
/** 获取容器节点transforms */
|
|
235
|
-
getContainerTransforms() {
|
|
236
|
-
return this.document.getAllNodes().filter((node) => {
|
|
237
|
-
if (node.originParent) {
|
|
238
|
-
return node.getNodeMeta().selectable && node.originParent.getNodeMeta().selectable;
|
|
239
|
-
}
|
|
240
|
-
return node.getNodeMeta().selectable;
|
|
241
|
-
}).filter((node) => this.isContainer(node)).sort((a, b) => {
|
|
242
|
-
const aIndex = a.renderData.stackIndex;
|
|
243
|
-
const bIndex = b.renderData.stackIndex;
|
|
244
|
-
return bIndex - aIndex;
|
|
245
|
-
}).map((node) => node.transform);
|
|
246
|
-
}
|
|
247
302
|
/** 放置节点到容器 */
|
|
248
303
|
async dropNodeToContainer() {
|
|
249
304
|
const { dropNode, dragNode, isDraggingNode } = this.state;
|
|
@@ -265,9 +320,10 @@ var NodeIntoContainerService = class {
|
|
|
265
320
|
const availableTransforms = transforms.filter(
|
|
266
321
|
(transform) => transform.entity.id !== dragNode.id
|
|
267
322
|
);
|
|
268
|
-
const collisionTransform =
|
|
323
|
+
const collisionTransform = ContainerUtils.getCollisionTransform({
|
|
269
324
|
targetPoint: mousePos,
|
|
270
|
-
transforms: availableTransforms
|
|
325
|
+
transforms: availableTransforms,
|
|
326
|
+
document: this.document
|
|
271
327
|
});
|
|
272
328
|
const dropNode = collisionTransform?.entity;
|
|
273
329
|
const canDrop = this.canDropToContainer({
|
|
@@ -286,7 +342,7 @@ var NodeIntoContainerService = class {
|
|
|
286
342
|
if (!dropNode || !isDropContainer || this.isParent(dragNode, dropNode)) {
|
|
287
343
|
return false;
|
|
288
344
|
}
|
|
289
|
-
if (dragNode.flowNodeType ===
|
|
345
|
+
if (dragNode.flowNodeType === FlowNodeBaseType2.GROUP && dropNode.flowNodeType !== FlowNodeBaseType2.GROUP) {
|
|
290
346
|
return false;
|
|
291
347
|
}
|
|
292
348
|
const canDrop = this.dragService.canDropToNode({
|
|
@@ -318,8 +374,14 @@ var NodeIntoContainerService = class {
|
|
|
318
374
|
this.operationService.moveNode(node, {
|
|
319
375
|
parent: containerNode
|
|
320
376
|
});
|
|
321
|
-
this.
|
|
322
|
-
|
|
377
|
+
const containerPadding = this.document.layout.getPadding(containerNode);
|
|
378
|
+
const position = ContainerUtils.adjustSubNodePosition({
|
|
379
|
+
targetNode: node,
|
|
380
|
+
containerNode,
|
|
381
|
+
containerPadding
|
|
382
|
+
});
|
|
383
|
+
this.operationService.updateNodePosition(node, position);
|
|
384
|
+
await ContainerUtils.nextFrame();
|
|
323
385
|
this.emitter.fire({
|
|
324
386
|
type: "in" /* In */,
|
|
325
387
|
node,
|
|
@@ -327,49 +389,6 @@ var NodeIntoContainerService = class {
|
|
|
327
389
|
targetContainer: containerNode
|
|
328
390
|
});
|
|
329
391
|
}
|
|
330
|
-
/**
|
|
331
|
-
* 如果存在容器节点,且传入鼠标坐标,需要用容器的坐标减去传入的鼠标坐标
|
|
332
|
-
*/
|
|
333
|
-
adjustSubNodePosition(targetNode, containerNode) {
|
|
334
|
-
if (containerNode.flowNodeType === FlowNodeBaseType.ROOT) {
|
|
335
|
-
return targetNode.transform.position;
|
|
336
|
-
}
|
|
337
|
-
const nodeWorldTransform = targetNode.transform.transform.worldTransform;
|
|
338
|
-
const containerWorldTransform = containerNode.transform.transform.worldTransform;
|
|
339
|
-
const nodePosition = {
|
|
340
|
-
x: nodeWorldTransform.tx,
|
|
341
|
-
y: nodeWorldTransform.ty
|
|
342
|
-
};
|
|
343
|
-
const isParentEmpty = !containerNode.children || containerNode.children.length === 0;
|
|
344
|
-
const containerPadding = this.document.layout.getPadding(containerNode);
|
|
345
|
-
if (isParentEmpty) {
|
|
346
|
-
return {
|
|
347
|
-
x: 0,
|
|
348
|
-
y: containerPadding.top
|
|
349
|
-
};
|
|
350
|
-
} else {
|
|
351
|
-
return {
|
|
352
|
-
x: nodePosition.x - containerWorldTransform.tx,
|
|
353
|
-
y: nodePosition.y - containerWorldTransform.ty
|
|
354
|
-
};
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
isContainer(node) {
|
|
358
|
-
return node?.getNodeMeta().isContainer ?? false;
|
|
359
|
-
}
|
|
360
|
-
/** 判断点是否在矩形内 */
|
|
361
|
-
isPointInRect(point, rect) {
|
|
362
|
-
return point.x >= rect.left && point.x <= rect.right && point.y >= rect.top && point.y <= rect.bottom;
|
|
363
|
-
}
|
|
364
|
-
/** 判断两个矩形是否相交 */
|
|
365
|
-
isRectIntersects(rectA, rectB) {
|
|
366
|
-
const hasHorizontalOverlap = rectA.right > rectB.left && rectA.left < rectB.right;
|
|
367
|
-
const hasVerticalOverlap = rectA.bottom > rectB.top && rectA.top < rectB.bottom;
|
|
368
|
-
return hasHorizontalOverlap && hasVerticalOverlap;
|
|
369
|
-
}
|
|
370
|
-
async nextFrame() {
|
|
371
|
-
await new Promise((resolve) => requestAnimationFrame(resolve));
|
|
372
|
-
}
|
|
373
392
|
};
|
|
374
393
|
__decorateClass([
|
|
375
394
|
inject(WorkflowDragService)
|
|
@@ -421,12 +440,12 @@ import {
|
|
|
421
440
|
useCurrentEntity,
|
|
422
441
|
WorkflowNodePortsData
|
|
423
442
|
} from "@flowgram.ai/free-layout-core";
|
|
424
|
-
import { FlowNodeTransformData
|
|
443
|
+
import { FlowNodeTransformData } from "@flowgram.ai/document";
|
|
425
444
|
var useNodeSize = () => {
|
|
426
445
|
const node = useCurrentEntity();
|
|
427
446
|
const nodeMeta = node.getNodeMeta();
|
|
428
|
-
const { size = { width: 300, height: 200 }, isContainer } = nodeMeta;
|
|
429
|
-
const transform = node.getData(
|
|
447
|
+
const { size = { width: 300, height: 200 }, isContainer: isContainer2 } = nodeMeta;
|
|
448
|
+
const transform = node.getData(FlowNodeTransformData);
|
|
430
449
|
const [width, setWidth] = useState(size.width);
|
|
431
450
|
const [height, setHeight] = useState(size.height);
|
|
432
451
|
const updatePorts = () => {
|
|
@@ -452,7 +471,7 @@ var useNodeSize = () => {
|
|
|
452
471
|
useEffect(() => {
|
|
453
472
|
updateSize();
|
|
454
473
|
}, []);
|
|
455
|
-
if (!
|
|
474
|
+
if (!isContainer2) {
|
|
456
475
|
return;
|
|
457
476
|
}
|
|
458
477
|
return {
|
|
@@ -827,6 +846,7 @@ var SubCanvasRender = ({
|
|
|
827
846
|
);
|
|
828
847
|
};
|
|
829
848
|
export {
|
|
849
|
+
ContainerUtils,
|
|
830
850
|
NodeIntoContainerService,
|
|
831
851
|
NodeIntoContainerType,
|
|
832
852
|
SubCanvasBackground,
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/node-into-container/constant.ts","../../src/node-into-container/service.ts","../../src/node-into-container/plugin.tsx","../../src/sub-canvas/hooks/use-node-size.ts","../../src/sub-canvas/hooks/use-sync-node-render-size.ts","../../src/sub-canvas/components/background/index.tsx","../../src/sub-canvas/components/background/style.ts","../../src/sub-canvas/components/border/index.tsx","../../src/sub-canvas/components/border/style.ts","../../src/sub-canvas/components/render/index.tsx","../../src/sub-canvas/components/render/style.ts","../../src/sub-canvas/components/tips/index.tsx","../../src/sub-canvas/components/tips/use-control.ts","../../src/sub-canvas/components/tips/global-store.ts","../../src/sub-canvas/components/tips/style.ts","../../src/sub-canvas/components/tips/is-mac-os.ts","../../src/sub-canvas/components/tips/icon-close.tsx"],"sourcesContent":["/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nexport enum NodeIntoContainerType {\n In = 'in',\n Out = 'out',\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\n/* eslint-disable @typescript-eslint/no-non-null-assertion -- no need */\nimport { throttle } from 'lodash';\nimport { inject, injectable } from 'inversify';\nimport {\n type PositionSchema,\n Rectangle,\n type Disposable,\n DisposableCollection,\n Emitter,\n type IPoint,\n} from '@flowgram.ai/utils';\nimport {\n type NodesDragEvent,\n WorkflowDocument,\n WorkflowDragService,\n WorkflowLinesManager,\n type WorkflowNodeEntity,\n WorkflowNodeMeta,\n WorkflowOperationBaseService,\n WorkflowSelectService,\n} from '@flowgram.ai/free-layout-core';\nimport { HistoryService } from '@flowgram.ai/free-history-plugin';\nimport { FlowNodeTransformData, FlowNodeRenderData, FlowNodeBaseType } from '@flowgram.ai/document';\nimport { PlaygroundConfigEntity, TransformData } from '@flowgram.ai/core';\n\nimport type { NodeIntoContainerEvent, NodeIntoContainerState } from './type';\nimport { NodeIntoContainerType } from './constant';\n\n@injectable()\nexport class NodeIntoContainerService {\n public state: NodeIntoContainerState;\n\n @inject(WorkflowDragService)\n private dragService: WorkflowDragService;\n\n @inject(WorkflowDocument)\n private document: WorkflowDocument;\n\n @inject(PlaygroundConfigEntity)\n private playgroundConfig: PlaygroundConfigEntity;\n\n @inject(WorkflowOperationBaseService)\n private operationService: WorkflowOperationBaseService;\n\n @inject(WorkflowLinesManager)\n private linesManager: WorkflowLinesManager;\n\n @inject(HistoryService) private historyService: HistoryService;\n\n @inject(WorkflowSelectService) private selectService: WorkflowSelectService;\n\n private emitter = new Emitter<NodeIntoContainerEvent>();\n\n private toDispose = new DisposableCollection();\n\n public readonly on = this.emitter.event;\n\n public init(): void {\n this.initState();\n this.toDispose.push(this.emitter);\n }\n\n public ready(): void {\n this.toDispose.push(this.listenDragToContainer());\n }\n\n public dispose(): void {\n this.initState();\n this.toDispose.dispose();\n }\n\n /** 将节点移出容器 */\n public async moveOutContainer(params: { node: WorkflowNodeEntity }): Promise<void> {\n const { node } = params;\n const parentNode = node.parent;\n const containerNode = parentNode?.parent;\n const nodeJSON = this.document.toNodeJSON(node);\n if (\n !parentNode ||\n !containerNode ||\n !this.isContainer(parentNode) ||\n !nodeJSON.meta?.position\n ) {\n return;\n }\n const parentTransform = parentNode.getData<TransformData>(TransformData);\n this.operationService.moveNode(node, {\n parent: containerNode,\n });\n await this.nextFrame();\n parentTransform.fireChange();\n this.operationService.updateNodePosition(node, {\n x: parentTransform.position.x + nodeJSON.meta!.position!.x,\n y: parentTransform.position.y + nodeJSON.meta!.position!.y,\n });\n this.emitter.fire({\n type: NodeIntoContainerType.Out,\n node,\n sourceContainer: parentNode,\n targetContainer: containerNode,\n });\n }\n\n /** 能否将节点移出容器 */\n public canMoveOutContainer(node: WorkflowNodeEntity): boolean {\n const parentNode = node.parent;\n const containerNode = parentNode?.parent;\n if (!parentNode || !containerNode || !this.isContainer(parentNode)) {\n return false;\n }\n const canDrop = this.dragService.canDropToNode({\n dragNodeType: node.flowNodeType,\n dragNode: node,\n dropNodeType: containerNode?.flowNodeType,\n dropNode: containerNode,\n });\n if (!canDrop.allowDrop) {\n return false;\n }\n return true;\n }\n\n /** 移除节点所有非法连线 */\n public async clearInvalidLines(params: {\n dragNode?: WorkflowNodeEntity;\n sourceParent?: WorkflowNodeEntity;\n }): Promise<void> {\n const { dragNode, sourceParent } = params;\n if (!dragNode) {\n return;\n }\n if (dragNode.parent === sourceParent) {\n // 容器节点未改变\n return;\n }\n if (\n dragNode.parent?.flowNodeType === FlowNodeBaseType.GROUP ||\n sourceParent?.flowNodeType === FlowNodeBaseType.GROUP\n ) {\n // 移入移出 group 节点无需删除节点\n return;\n }\n await this.removeNodeLines(dragNode);\n }\n\n /** 移除节点连线 */\n public async removeNodeLines(node: WorkflowNodeEntity): Promise<void> {\n const lines = this.linesManager.getAllLines();\n lines.forEach((line) => {\n if (line.from.id !== node.id && line.to?.id !== node.id) {\n return;\n }\n line.dispose();\n });\n await this.nextFrame();\n }\n\n /** 初始化状态 */\n private initState(): void {\n this.state = {\n isDraggingNode: false,\n isSkipEvent: false,\n transforms: undefined,\n dragNode: undefined,\n dropNode: undefined,\n sourceParent: undefined,\n };\n }\n\n /** 监听节点拖拽 */\n private listenDragToContainer(): Disposable {\n const draggingNode = (e: NodesDragEvent) => this.draggingNode(e);\n const throttledDraggingNode = throttle(draggingNode, 200); // 200ms触发一次计算\n return this.dragService.onNodesDrag(async (event) => {\n if (this.selectService.selectedNodes.length !== 1) {\n return;\n }\n if (event.type === 'onDragStart') {\n if (this.state.isSkipEvent) {\n // 拖出容器后重新进入\n this.state.isSkipEvent = false;\n return;\n }\n this.historyService.startTransaction(); // 开始合并历史记录\n this.state.isDraggingNode = true;\n this.state.transforms = this.getContainerTransforms();\n this.state.dragNode = this.selectService.selectedNodes[0];\n this.state.dropNode = undefined;\n this.state.sourceParent = this.state.dragNode?.parent;\n await this.dragOutContainer(event); // 检查是否需拖出容器\n }\n if (event.type === 'onDragging') {\n throttledDraggingNode(event);\n }\n if (event.type === 'onDragEnd') {\n if (this.state.isSkipEvent) {\n // 拖出容器情况下需跳过本次事件\n return;\n }\n throttledDraggingNode.cancel();\n draggingNode(event); // 直接触发一次计算,防止延迟\n await this.dropNodeToContainer(); // 放置节点\n await this.clearInvalidLines({\n dragNode: this.state.dragNode,\n sourceParent: this.state.sourceParent,\n }); // 清除非法线条\n this.setDropNode(undefined);\n this.initState(); // 重置状态\n this.historyService.endTransaction(); // 结束合并历史记录\n }\n });\n }\n\n /** 监听节点拖拽出容器 */\n private async dragOutContainer(event: NodesDragEvent): Promise<void> {\n const { dragNode } = this.state;\n const activated = event.triggerEvent.metaKey || event.triggerEvent.ctrlKey;\n if (\n !activated || // 必须按住指定按键\n !dragNode || // 必须有一个节点\n !this.canMoveOutContainer(dragNode) // 需要能被移出容器\n ) {\n return;\n }\n this.moveOutContainer({ node: dragNode });\n this.state.isSkipEvent = true;\n event.dragger.stop(event.dragEvent.clientX, event.dragEvent.clientY);\n await this.nextFrame();\n this.dragService.startDragSelectedNodes(event.triggerEvent);\n }\n\n /** 获取重叠位置 */\n private getCollisionTransform(params: {\n transforms: FlowNodeTransformData[];\n targetRect?: Rectangle;\n targetPoint?: PositionSchema;\n withPadding?: boolean;\n }): FlowNodeTransformData | undefined {\n const { targetRect, targetPoint, transforms, withPadding = false } = params;\n const collisionTransform = transforms.find((transform) => {\n const { bounds, entity } = transform;\n const padding = withPadding ? this.document.layout.getPadding(entity) : { left: 0, right: 0 };\n const transformRect = new Rectangle(\n bounds.x + padding.left + padding.right,\n bounds.y,\n bounds.width,\n bounds.height\n );\n // 检测两个正方形是否相互碰撞\n if (targetRect) {\n return this.isRectIntersects(targetRect, transformRect);\n }\n if (targetPoint) {\n return this.isPointInRect(targetPoint, transformRect);\n }\n return false;\n });\n return collisionTransform;\n }\n\n /** 设置放置节点高亮 */\n private setDropNode(dropNode?: WorkflowNodeEntity) {\n if (this.state.dropNode === dropNode) {\n return;\n }\n if (this.state.dropNode) {\n // 清除上一个节点高亮\n const renderData = this.state.dropNode.getData(FlowNodeRenderData);\n const renderDom = renderData.node?.children?.[0] as HTMLElement;\n if (renderDom) {\n renderDom.classList.remove('selected');\n }\n }\n this.state.dropNode = dropNode;\n if (!dropNode) {\n return;\n }\n // 设置当前节点高亮\n const renderData = dropNode.getData(FlowNodeRenderData);\n const renderDom = renderData.node?.children?.[0] as HTMLElement;\n if (renderDom) {\n renderDom.classList.add('selected');\n }\n }\n\n /** 获取容器节点transforms */\n private getContainerTransforms(): FlowNodeTransformData[] {\n return this.document\n .getAllNodes()\n .filter((node) => {\n if (node.originParent) {\n return node.getNodeMeta().selectable && node.originParent.getNodeMeta().selectable;\n }\n return node.getNodeMeta().selectable;\n })\n .filter((node) => this.isContainer(node))\n .sort((a, b) => {\n const aIndex = a.renderData.stackIndex;\n const bIndex = b.renderData.stackIndex;\n // 确保层级高的节点在前面\n return bIndex - aIndex;\n })\n .map((node) => node.transform);\n }\n\n /** 放置节点到容器 */\n private async dropNodeToContainer(): Promise<void> {\n const { dropNode, dragNode, isDraggingNode } = this.state;\n if (!isDraggingNode || !dragNode || !dropNode) {\n return;\n }\n return await this.moveIntoContainer({\n node: dragNode,\n containerNode: dropNode,\n });\n }\n\n /** 拖拽节点 */\n private draggingNode(nodeDragEvent: NodesDragEvent): void {\n const { dragNode, isDraggingNode, transforms = [] } = this.state;\n if (!isDraggingNode || !dragNode || !transforms?.length) {\n return this.setDropNode(undefined);\n }\n const mousePos = this.playgroundConfig.getPosFromMouseEvent(nodeDragEvent.dragEvent);\n const availableTransforms = transforms.filter(\n (transform) => transform.entity.id !== dragNode.id\n );\n const collisionTransform = this.getCollisionTransform({\n targetPoint: mousePos,\n transforms: availableTransforms,\n });\n const dropNode = collisionTransform?.entity;\n const canDrop = this.canDropToContainer({\n dragNode,\n dropNode,\n });\n if (!canDrop) {\n return this.setDropNode(undefined);\n }\n return this.setDropNode(dropNode);\n }\n\n /** 判断能否将节点拖入容器 */\n protected canDropToContainer(params: {\n dragNode: WorkflowNodeEntity;\n dropNode?: WorkflowNodeEntity;\n }): boolean {\n const { dragNode, dropNode } = params;\n const isDropContainer = dropNode?.getNodeMeta<WorkflowNodeMeta>().isContainer;\n if (!dropNode || !isDropContainer || this.isParent(dragNode, dropNode)) {\n return false;\n }\n if (\n dragNode.flowNodeType === FlowNodeBaseType.GROUP &&\n dropNode.flowNodeType !== FlowNodeBaseType.GROUP\n ) {\n // 禁止将 group 节点拖入非 group 节点(由于目前不支持多节点拖入容器,无法计算有效线条,因此进行屏蔽)\n return false;\n }\n const canDrop = this.dragService.canDropToNode({\n dragNodeType: dragNode.flowNodeType,\n dropNodeType: dropNode?.flowNodeType,\n dragNode,\n dropNode,\n });\n if (!canDrop.allowDrop) {\n return false;\n }\n return true;\n }\n\n /** 判断一个节点是否为另一个节点的父节点(向上查找直到根节点) */\n private isParent(node: WorkflowNodeEntity, parent: WorkflowNodeEntity): boolean {\n let current = node.parent;\n while (current) {\n if (current.id === parent.id) {\n return true;\n }\n current = current.parent;\n }\n return false;\n }\n\n /** 将节点移入容器 */\n private async moveIntoContainer(params: {\n node: WorkflowNodeEntity;\n containerNode: WorkflowNodeEntity;\n }): Promise<void> {\n const { node, containerNode } = params;\n const parentNode = node.parent;\n\n this.operationService.moveNode(node, {\n parent: containerNode,\n });\n\n this.operationService.updateNodePosition(node, this.adjustSubNodePosition(node, containerNode));\n\n await this.nextFrame();\n\n this.emitter.fire({\n type: NodeIntoContainerType.In,\n node,\n sourceContainer: parentNode,\n targetContainer: containerNode,\n });\n }\n\n /**\n * 如果存在容器节点,且传入鼠标坐标,需要用容器的坐标减去传入的鼠标坐标\n */\n private adjustSubNodePosition(\n targetNode: WorkflowNodeEntity,\n containerNode: WorkflowNodeEntity\n ): IPoint {\n if (containerNode.flowNodeType === FlowNodeBaseType.ROOT) {\n return targetNode.transform.position;\n }\n const nodeWorldTransform = targetNode.transform.transform.worldTransform;\n const containerWorldTransform = containerNode.transform.transform.worldTransform;\n const nodePosition = {\n x: nodeWorldTransform.tx,\n y: nodeWorldTransform.ty,\n };\n const isParentEmpty = !containerNode.children || containerNode.children.length === 0;\n const containerPadding = this.document.layout.getPadding(containerNode);\n if (isParentEmpty) {\n // 确保空容器节点不偏移\n return {\n x: 0,\n y: containerPadding.top,\n };\n } else {\n return {\n x: nodePosition.x - containerWorldTransform.tx,\n y: nodePosition.y - containerWorldTransform.ty,\n };\n }\n }\n\n private isContainer(node?: WorkflowNodeEntity): boolean {\n return node?.getNodeMeta<WorkflowNodeMeta>().isContainer ?? false;\n }\n\n /** 判断点是否在矩形内 */\n private isPointInRect(point: PositionSchema, rect: Rectangle): boolean {\n return (\n point.x >= rect.left && point.x <= rect.right && point.y >= rect.top && point.y <= rect.bottom\n );\n }\n\n /** 判断两个矩形是否相交 */\n private isRectIntersects(rectA: Rectangle, rectB: Rectangle): boolean {\n // 检查水平方向是否有重叠\n const hasHorizontalOverlap = rectA.right > rectB.left && rectA.left < rectB.right;\n // 检查垂直方向是否有重叠\n const hasVerticalOverlap = rectA.bottom > rectB.top && rectA.top < rectB.bottom;\n // 只有当水平和垂直方向都有重叠时,两个矩形才相交\n return hasHorizontalOverlap && hasVerticalOverlap;\n }\n\n private async nextFrame(): Promise<void> {\n await new Promise((resolve) => requestAnimationFrame(resolve));\n }\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { definePluginCreator } from '@flowgram.ai/core';\n\nimport type { WorkflowContainerPluginOptions } from './type';\nimport { NodeIntoContainerService } from '.';\n\nexport const createContainerNodePlugin = definePluginCreator<WorkflowContainerPluginOptions>({\n onBind: ({ bind }) => {\n bind(NodeIntoContainerService).toSelf().inSingletonScope();\n },\n onInit(ctx, options) {\n ctx.get(NodeIntoContainerService).init();\n },\n onReady(ctx, options) {\n if (options.disableNodeIntoContainer !== true) {\n ctx.get(NodeIntoContainerService).ready();\n }\n },\n onDispose(ctx) {\n ctx.get(NodeIntoContainerService).dispose();\n },\n});\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { useState, useEffect } from 'react';\n\nimport {\n useCurrentEntity,\n WorkflowNodeMeta,\n WorkflowNodePortsData,\n} from '@flowgram.ai/free-layout-core';\nimport { FlowNodeTransformData } from '@flowgram.ai/document';\n\nexport interface NodeSize {\n width: number;\n height: number;\n}\n\nexport const useNodeSize = (): NodeSize | undefined => {\n const node = useCurrentEntity();\n const nodeMeta = node.getNodeMeta<WorkflowNodeMeta>();\n const { size = { width: 300, height: 200 }, isContainer } = nodeMeta;\n\n const transform = node.getData<FlowNodeTransformData>(FlowNodeTransformData);\n const [width, setWidth] = useState(size.width);\n const [height, setHeight] = useState(size.height);\n\n const updatePorts = () => {\n const portsData = node.getData<WorkflowNodePortsData>(WorkflowNodePortsData);\n portsData.updateDynamicPorts();\n };\n\n const updateSize = () => {\n // 无子节点时\n if (node.blocks.length === 0) {\n setWidth(size.width);\n setHeight(size.height);\n return;\n }\n // 存在子节点时,只监听宽高变化\n setWidth(transform.bounds.width);\n setHeight(transform.bounds.height);\n };\n\n useEffect(() => {\n const dispose = transform.onDataChange(() => {\n updateSize();\n updatePorts();\n });\n return () => dispose.dispose();\n }, [transform, width, height]);\n\n useEffect(() => {\n // 初始化触发一次\n updateSize();\n }, []);\n\n if (!isContainer) {\n return;\n }\n\n return {\n width,\n height,\n };\n};\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { useLayoutEffect } from 'react';\n\nimport { useCurrentEntity } from '@flowgram.ai/free-layout-core';\n\nimport { NodeSize } from './use-node-size';\n\nexport const useSyncNodeRenderSize = (nodeSize?: NodeSize) => {\n const node = useCurrentEntity();\n\n useLayoutEffect(() => {\n if (!nodeSize) {\n return;\n }\n node.renderData.node.style.width = nodeSize.width + 'px';\n node.renderData.node.style.height = nodeSize.height + 'px';\n }, [nodeSize?.width, nodeSize?.height]);\n};\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport React, { type FC } from 'react';\n\nimport { useCurrentEntity } from '@flowgram.ai/free-layout-core';\nimport { useService } from '@flowgram.ai/core';\nimport { BackgroundConfig, BackgroundLayerOptions } from '@flowgram.ai/background-plugin';\n\nimport { SubCanvasBackgroundStyle } from './style';\n\nexport const SubCanvasBackground: FC = () => {\n const node = useCurrentEntity();\n\n // 通过 inversify 获取背景配置,如果没有配置则使用默认值\n let backgroundConfig: BackgroundLayerOptions = {};\n try {\n backgroundConfig = useService<BackgroundLayerOptions>(BackgroundConfig);\n } catch (error) {\n // 如果 BackgroundConfig 没有注册,使用默认配置\n // 静默处理,使用默认配置\n }\n\n // 获取配置值,如果没有则使用默认值\n const gridSize = backgroundConfig.gridSize ?? 20;\n const dotSize = backgroundConfig.dotSize ?? 1;\n const dotColor = backgroundConfig.dotColor ?? '#eceeef';\n const dotOpacity = backgroundConfig.dotOpacity ?? 0.5;\n const backgroundColor = backgroundConfig.backgroundColor ?? '#f2f3f5';\n // 只有当 dotFillColor 被明确设置且与 dotColor 不同时才添加 fill 属性\n const dotFillColor =\n backgroundConfig.dotFillColor === dotColor ? '' : backgroundConfig.dotFillColor;\n\n // 生成唯一的 pattern ID\n const patternId = `sub-canvas-dot-pattern-${node.id}`;\n\n return (\n <SubCanvasBackgroundStyle\n className=\"sub-canvas-background\"\n data-flow-editor-selectable=\"true\"\n style={{ backgroundColor: backgroundColor }}\n >\n <svg width=\"100%\" height=\"100%\">\n <pattern id={patternId} width={gridSize} height={gridSize} patternUnits=\"userSpaceOnUse\">\n <circle\n cx={dotSize}\n cy={dotSize}\n r={dotSize}\n stroke={dotColor}\n fill={dotFillColor}\n fillOpacity={dotOpacity}\n />\n </pattern>\n <rect\n width=\"100%\"\n height=\"100%\"\n fill={`url(#${patternId})`}\n data-node-panel-container={node.id}\n />\n </svg>\n </SubCanvasBackgroundStyle>\n );\n};\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport styled from 'styled-components';\n\nexport const SubCanvasBackgroundStyle = styled.div`\n width: 100%;\n height: 100%;\n inset: 56px 18px 18px;\n /* 背景色现在通过 style 属性动态设置 */\n`;\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport React, { CSSProperties, ReactNode, type FC } from 'react';\n\nimport { SubCanvasBorderStyle } from './style';\n\ninterface ISubCanvasBorder {\n style?: CSSProperties;\n children?: ReactNode | ReactNode[];\n}\n\nexport const SubCanvasBorder: FC<ISubCanvasBorder> = ({ style, children }) => (\n <SubCanvasBorderStyle\n className=\"sub-canvas-border\"\n style={{\n ...style,\n }}\n >\n {children}\n </SubCanvasBorderStyle>\n);\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport styled from 'styled-components';\n\nexport const SubCanvasBorderStyle = styled.div`\n pointer-events: none;\n\n position: relative;\n\n display: flex;\n align-items: center;\n\n width: 100%;\n height: 100%;\n\n background-color: transparent;\n border: 1px solid var(--coz-stroke-plus, rgba(6, 7, 9, 15%));\n border-color: var(--coz-bg-plus, rgb(249, 249, 249));\n border-style: solid;\n border-width: 8px;\n border-radius: 8px;\n\n &::before {\n content: '';\n\n position: absolute;\n z-index: 0;\n inset: -4px;\n\n background-color: transparent;\n border-color: var(--coz-bg-plus, rgb(249, 249, 249));\n border-style: solid;\n border-width: 4px;\n border-radius: 8px;\n }\n`;\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport React, { CSSProperties, type FC } from 'react';\n\nimport { SubCanvasRenderStyle } from './style';\nimport { SubCanvasTips } from '../tips';\nimport { SubCanvasBorder } from '../border';\nimport { SubCanvasBackground } from '../background';\nimport { useNodeSize, useSyncNodeRenderSize } from '../../hooks';\n\ninterface ISubCanvasRender {\n offsetY?: number;\n className?: string;\n style?: CSSProperties;\n tipText?: string | React.ReactNode;\n}\n\nexport const SubCanvasRender: FC<ISubCanvasRender> = ({\n className,\n style,\n offsetY = 0,\n tipText,\n}) => {\n const nodeSize = useNodeSize();\n const nodeHeight = nodeSize?.height ?? 0;\n\n useSyncNodeRenderSize(nodeSize);\n\n return (\n <SubCanvasRenderStyle\n className={`sub-canvas-render ${className ?? ''}`}\n style={{\n height: nodeHeight + offsetY,\n ...style,\n }}\n data-flow-editor-selectable=\"true\"\n onDragStart={(e) => {\n e.stopPropagation();\n }}\n >\n <SubCanvasBorder>\n <SubCanvasBackground />\n <SubCanvasTips tipText={tipText} />\n </SubCanvasBorder>\n </SubCanvasRenderStyle>\n );\n};\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport styled from 'styled-components';\n\nexport const SubCanvasRenderStyle = styled.div`\n width: 100%;\n height: 100%;\n`;\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport React from 'react';\n\nimport { I18n } from '@flowgram.ai/i18n';\n\nimport { useControlTips } from './use-control';\nimport { SubCanvasTipsStyle } from './style';\nimport { isMacOS } from './is-mac-os';\nimport { IconClose } from './icon-close';\n\ninterface SubCanvasTipsProps {\n tipText?: string | React.ReactNode;\n neverRemindText?: string | React.ReactNode;\n}\n\nexport const SubCanvasTips = ({ tipText, neverRemindText }: SubCanvasTipsProps) => {\n const { visible, close, closeForever } = useControlTips();\n\n const displayContent =\n tipText || I18n.t('Hold {{key}} to drag node out', { key: isMacOS ? 'Cmd ⌘' : 'Ctrl' });\n\n if (!visible) {\n return null;\n }\n return (\n <SubCanvasTipsStyle className={'sub-canvas-tips'}>\n <div className=\"container\">\n <div className=\"content\">\n {typeof displayContent === 'string' ? (\n <p className=\"text\">{displayContent}</p>\n ) : (\n <div className=\"custom-content\">{displayContent}</div>\n )}\n <div\n className=\"space\"\n style={{\n width: 0,\n }}\n />\n </div>\n <div className=\"actions\">\n <p className=\"close-forever\" onClick={closeForever}>\n {neverRemindText || I18n.t('Never Remind')}\n </p>\n <div className=\"close\" onClick={close}>\n <IconClose />\n </div>\n </div>\n </div>\n </SubCanvasTipsStyle>\n );\n};\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { useCallback, useEffect, useState } from 'react';\n\nimport { useCurrentEntity } from '@flowgram.ai/free-layout-core';\nimport { useService } from '@flowgram.ai/core';\n\nimport { NodeIntoContainerService, NodeIntoContainerType } from '../../../node-into-container';\nimport { TipsGlobalStore } from './global-store';\n\nexport const useControlTips = () => {\n const node = useCurrentEntity();\n const [visible, setVisible] = useState(false);\n const globalStore = TipsGlobalStore.instance;\n\n const nodeIntoContainerService = useService<NodeIntoContainerService>(NodeIntoContainerService);\n\n const show = useCallback(() => {\n if (globalStore.isClosed()) {\n return;\n }\n\n setVisible(true);\n }, [globalStore]);\n\n const close = useCallback(() => {\n globalStore.close();\n setVisible(false);\n }, [globalStore]);\n\n const closeForever = useCallback(() => {\n globalStore.closeForever();\n close();\n }, [close, globalStore]);\n\n useEffect(() => {\n // 监听移入\n const inDisposer = nodeIntoContainerService.on((e) => {\n if (e.type !== NodeIntoContainerType.In) {\n return;\n }\n if (e.targetContainer === node) {\n show();\n }\n });\n // 监听移出事件\n const outDisposer = nodeIntoContainerService.on((e) => {\n if (e.type !== NodeIntoContainerType.Out) {\n return;\n }\n if (e.sourceContainer === node && !node.blocks.length) {\n setVisible(false);\n }\n });\n return () => {\n inDisposer.dispose();\n outDisposer.dispose();\n };\n }, [nodeIntoContainerService, node, show, close, visible]);\n\n return {\n visible,\n close,\n closeForever,\n };\n};\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\n/* eslint-disable @typescript-eslint/naming-convention -- no need */\n\nconst STORAGE_KEY = 'workflow-move-into-sub-canvas-tip-visible';\nconst STORAGE_VALUE = 'false';\n\nexport class TipsGlobalStore {\n private static _instance?: TipsGlobalStore;\n\n public static get instance(): TipsGlobalStore {\n if (!this._instance) {\n this._instance = new TipsGlobalStore();\n }\n return this._instance;\n }\n\n private closed = false;\n\n public isClosed(): boolean {\n return this.isCloseForever() || this.closed;\n }\n\n public close(): void {\n this.closed = true;\n }\n\n public isCloseForever(): boolean {\n return localStorage.getItem(STORAGE_KEY) === STORAGE_VALUE;\n }\n\n public closeForever(): void {\n localStorage.setItem(STORAGE_KEY, STORAGE_VALUE);\n }\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport styled from 'styled-components';\n\nexport const SubCanvasTipsStyle = styled.div`\n pointer-events: auto;\n position: absolute;\n top: 0;\n\n width: 100%;\n height: 28px;\n\n .container {\n height: 100%;\n background-color: #e4e6f5;\n border-radius: 4px 4px 0 0;\n\n .content {\n overflow: hidden;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n\n width: 100%;\n height: 100%;\n\n .text {\n font-size: 14px;\n font-weight: 400;\n font-style: normal;\n line-height: 20px;\n color: rgba(15, 21, 40, 82%);\n text-overflow: ellipsis;\n }\n\n .custom-content {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: 100%;\n\n /* 为自定义内容提供默认样式,但允许覆盖 */\n font-size: 14px;\n font-weight: 400;\n line-height: 20px;\n color: rgba(15, 21, 40, 82%);\n\n /* 确保自定义内容不会超出容器 */\n overflow: hidden;\n }\n\n .space {\n width: 128px;\n }\n }\n\n .actions {\n position: absolute;\n top: 0;\n right: 0;\n\n display: flex;\n gap: 8px;\n align-items: center;\n\n height: 28px;\n padding: 0 16px;\n\n .close-forever {\n cursor: pointer;\n\n padding: 0 3px;\n\n font-size: 12px;\n font-weight: 400;\n font-style: normal;\n line-height: 12px;\n color: rgba(32, 41, 69, 62%);\n }\n\n .close {\n display: flex;\n cursor: pointer;\n height: 100%;\n align-items: center;\n }\n }\n }\n`;\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nexport const isMacOS = /(Macintosh|MacIntel|MacPPC|Mac68K|iPad)/.test(navigator.userAgent);\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport React from 'react';\n\nexport const IconClose = () => (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"none\" viewBox=\"0 0 16 16\">\n <path\n fill=\"#060709\"\n fillOpacity=\"0.5\"\n d=\"M12.13 12.128a.5.5 0 0 0 .001-.706L8.71 8l3.422-3.423a.5.5 0 0 0-.001-.705.5.5 0 0 0-.706-.002L8.002 7.293 4.579 3.87a.5.5 0 0 0-.705.002.5.5 0 0 0-.002.705L7.295 8l-3.423 3.422a.5.5 0 0 0 .002.706c.195.195.51.197.705.001l3.423-3.422 3.422 3.422c.196.196.51.194.706-.001\"\n ></path>\n </svg>\n);\n"],"mappings":"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","names":["NodeIntoContainerType","renderData","renderDom","FlowNodeTransformData","useCurrentEntity","useCurrentEntity","useCurrentEntity","React","styled","React","React","styled","React","useEffect","useState","useCurrentEntity","useService","useCurrentEntity","useState","useService","useEffect","styled","React","React","React"]}
|
|
1
|
+
{"version":3,"sources":["../../src/node-into-container/constant.ts","../../src/node-into-container/service.ts","../../src/utils/next-frame.ts","../../src/utils/is-container.ts","../../src/utils/get-container-transforms.ts","../../src/utils/get-collision-transform.ts","../../src/utils/is-rect-intersects.ts","../../src/utils/is-point-in-rect.ts","../../src/utils/adjust-sub-node-position.ts","../../src/utils/index.ts","../../src/node-into-container/plugin.tsx","../../src/sub-canvas/hooks/use-node-size.ts","../../src/sub-canvas/hooks/use-sync-node-render-size.ts","../../src/sub-canvas/components/background/index.tsx","../../src/sub-canvas/components/background/style.ts","../../src/sub-canvas/components/border/index.tsx","../../src/sub-canvas/components/border/style.ts","../../src/sub-canvas/components/render/index.tsx","../../src/sub-canvas/components/render/style.ts","../../src/sub-canvas/components/tips/index.tsx","../../src/sub-canvas/components/tips/use-control.ts","../../src/sub-canvas/components/tips/global-store.ts","../../src/sub-canvas/components/tips/style.ts","../../src/sub-canvas/components/tips/is-mac-os.ts","../../src/sub-canvas/components/tips/icon-close.tsx"],"sourcesContent":["/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nexport enum NodeIntoContainerType {\n In = 'in',\n Out = 'out',\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\n/* eslint-disable @typescript-eslint/no-non-null-assertion -- no need */\nimport { throttle } from 'lodash';\nimport { inject, injectable } from 'inversify';\nimport { type Disposable, DisposableCollection, Emitter } from '@flowgram.ai/utils';\nimport {\n type NodesDragEvent,\n WorkflowDocument,\n WorkflowDragService,\n WorkflowLinesManager,\n type WorkflowNodeEntity,\n WorkflowNodeMeta,\n WorkflowOperationBaseService,\n WorkflowSelectService,\n} from '@flowgram.ai/free-layout-core';\nimport { HistoryService } from '@flowgram.ai/free-history-plugin';\nimport { FlowNodeRenderData, FlowNodeBaseType } from '@flowgram.ai/document';\nimport { PlaygroundConfigEntity, TransformData } from '@flowgram.ai/core';\n\nimport type { NodeIntoContainerEvent, NodeIntoContainerState } from './type';\nimport { NodeIntoContainerType } from './constant';\nimport { ContainerUtils } from '../utils';\n\n@injectable()\nexport class NodeIntoContainerService {\n public state: NodeIntoContainerState;\n\n @inject(WorkflowDragService)\n private dragService: WorkflowDragService;\n\n @inject(WorkflowDocument)\n private document: WorkflowDocument;\n\n @inject(PlaygroundConfigEntity)\n private playgroundConfig: PlaygroundConfigEntity;\n\n @inject(WorkflowOperationBaseService)\n private operationService: WorkflowOperationBaseService;\n\n @inject(WorkflowLinesManager)\n private linesManager: WorkflowLinesManager;\n\n @inject(HistoryService) private historyService: HistoryService;\n\n @inject(WorkflowSelectService) private selectService: WorkflowSelectService;\n\n private emitter = new Emitter<NodeIntoContainerEvent>();\n\n private toDispose = new DisposableCollection();\n\n public readonly on = this.emitter.event;\n\n public init(): void {\n this.initState();\n this.toDispose.push(this.emitter);\n }\n\n public ready(): void {\n this.toDispose.push(this.listenDragToContainer());\n }\n\n public dispose(): void {\n this.initState();\n this.toDispose.dispose();\n }\n\n /** 将节点移出容器 */\n public async moveOutContainer(params: { node: WorkflowNodeEntity }): Promise<void> {\n const { node } = params;\n const parentNode = node.parent;\n const containerNode = parentNode?.parent;\n const nodeJSON = this.document.toNodeJSON(node);\n if (\n !parentNode ||\n !containerNode ||\n !ContainerUtils.isContainer(parentNode) ||\n !nodeJSON.meta?.position\n ) {\n return;\n }\n const parentTransform = parentNode.getData<TransformData>(TransformData);\n this.operationService.moveNode(node, {\n parent: containerNode,\n });\n await ContainerUtils.nextFrame();\n parentTransform.fireChange();\n this.operationService.updateNodePosition(node, {\n x: parentTransform.position.x + nodeJSON.meta!.position!.x,\n y: parentTransform.position.y + nodeJSON.meta!.position!.y,\n });\n this.emitter.fire({\n type: NodeIntoContainerType.Out,\n node,\n sourceContainer: parentNode,\n targetContainer: containerNode,\n });\n }\n\n /** 能否将节点移出容器 */\n public canMoveOutContainer(node: WorkflowNodeEntity): boolean {\n const parentNode = node.parent;\n const containerNode = parentNode?.parent;\n if (!parentNode || !containerNode || !ContainerUtils.isContainer(parentNode)) {\n return false;\n }\n const canDrop = this.dragService.canDropToNode({\n dragNodeType: node.flowNodeType,\n dragNode: node,\n dropNodeType: containerNode?.flowNodeType,\n dropNode: containerNode,\n });\n if (!canDrop.allowDrop) {\n return false;\n }\n return true;\n }\n\n /** 移除节点所有非法连线 */\n public async clearInvalidLines(params: {\n dragNode?: WorkflowNodeEntity;\n sourceParent?: WorkflowNodeEntity;\n }): Promise<void> {\n const { dragNode, sourceParent } = params;\n if (!dragNode) {\n return;\n }\n if (dragNode.parent === sourceParent) {\n // 容器节点未改变\n return;\n }\n if (\n dragNode.parent?.flowNodeType === FlowNodeBaseType.GROUP ||\n sourceParent?.flowNodeType === FlowNodeBaseType.GROUP\n ) {\n // 移入移出 group 节点无需删除节点\n return;\n }\n await this.removeNodeLines(dragNode);\n }\n\n /** 移除节点连线 */\n public async removeNodeLines(node: WorkflowNodeEntity): Promise<void> {\n const lines = this.linesManager.getAllLines();\n lines.forEach((line) => {\n if (line.from.id !== node.id && line.to?.id !== node.id) {\n return;\n }\n line.dispose();\n });\n await ContainerUtils.nextFrame();\n }\n\n /** 初始化状态 */\n private initState(): void {\n this.state = {\n isDraggingNode: false,\n isSkipEvent: false,\n transforms: undefined,\n dragNode: undefined,\n dropNode: undefined,\n sourceParent: undefined,\n };\n }\n\n /** 监听节点拖拽 */\n private listenDragToContainer(): Disposable {\n const draggingNode = (e: NodesDragEvent) => this.draggingNode(e);\n const throttledDraggingNode = throttle(draggingNode, 200); // 200ms触发一次计算\n return this.dragService.onNodesDrag(async (event) => {\n if (this.selectService.selectedNodes.length !== 1) {\n return;\n }\n if (event.type === 'onDragStart') {\n if (this.state.isSkipEvent) {\n // 拖出容器后重新进入\n this.state.isSkipEvent = false;\n return;\n }\n this.historyService.startTransaction(); // 开始合并历史记录\n this.state.isDraggingNode = true;\n this.state.transforms = ContainerUtils.getContainerTransforms(this.document.getAllNodes());\n this.state.dragNode = this.selectService.selectedNodes[0];\n this.state.dropNode = undefined;\n this.state.sourceParent = this.state.dragNode?.parent;\n await this.dragOutContainer(event); // 检查是否需拖出容器\n }\n if (event.type === 'onDragging') {\n throttledDraggingNode(event);\n }\n if (event.type === 'onDragEnd') {\n if (this.state.isSkipEvent) {\n // 拖出容器情况下需跳过本次事件\n return;\n }\n throttledDraggingNode.cancel();\n draggingNode(event); // 直接触发一次计算,防止延迟\n await this.dropNodeToContainer(); // 放置节点\n await this.clearInvalidLines({\n dragNode: this.state.dragNode,\n sourceParent: this.state.sourceParent,\n }); // 清除非法线条\n this.setDropNode(undefined);\n this.initState(); // 重置状态\n this.historyService.endTransaction(); // 结束合并历史记录\n }\n });\n }\n\n /** 监听节点拖拽出容器 */\n private async dragOutContainer(event: NodesDragEvent): Promise<void> {\n const { dragNode } = this.state;\n const activated = event.triggerEvent.metaKey || event.triggerEvent.ctrlKey;\n if (\n !activated || // 必须按住指定按键\n !dragNode || // 必须有一个节点\n !this.canMoveOutContainer(dragNode) // 需要能被移出容器\n ) {\n return;\n }\n this.moveOutContainer({ node: dragNode });\n this.state.isSkipEvent = true;\n event.dragger.stop(event.dragEvent.clientX, event.dragEvent.clientY);\n await ContainerUtils.nextFrame();\n this.dragService.startDragSelectedNodes(event.triggerEvent);\n }\n\n /** 设置放置节点高亮 */\n private setDropNode(dropNode?: WorkflowNodeEntity) {\n if (this.state.dropNode === dropNode) {\n return;\n }\n if (this.state.dropNode) {\n // 清除上一个节点高亮\n const renderData = this.state.dropNode.getData(FlowNodeRenderData);\n const renderDom = renderData.node?.children?.[0] as HTMLElement;\n if (renderDom) {\n renderDom.classList.remove('selected');\n }\n }\n this.state.dropNode = dropNode;\n if (!dropNode) {\n return;\n }\n // 设置当前节点高亮\n const renderData = dropNode.getData(FlowNodeRenderData);\n const renderDom = renderData.node?.children?.[0] as HTMLElement;\n if (renderDom) {\n renderDom.classList.add('selected');\n }\n }\n\n /** 放置节点到容器 */\n private async dropNodeToContainer(): Promise<void> {\n const { dropNode, dragNode, isDraggingNode } = this.state;\n if (!isDraggingNode || !dragNode || !dropNode) {\n return;\n }\n return await this.moveIntoContainer({\n node: dragNode,\n containerNode: dropNode,\n });\n }\n\n /** 拖拽节点 */\n private draggingNode(nodeDragEvent: NodesDragEvent): void {\n const { dragNode, isDraggingNode, transforms = [] } = this.state;\n if (!isDraggingNode || !dragNode || !transforms?.length) {\n return this.setDropNode(undefined);\n }\n const mousePos = this.playgroundConfig.getPosFromMouseEvent(nodeDragEvent.dragEvent);\n const availableTransforms = transforms.filter(\n (transform) => transform.entity.id !== dragNode.id\n );\n const collisionTransform = ContainerUtils.getCollisionTransform({\n targetPoint: mousePos,\n transforms: availableTransforms,\n document: this.document,\n });\n const dropNode = collisionTransform?.entity;\n const canDrop = this.canDropToContainer({\n dragNode,\n dropNode,\n });\n if (!canDrop) {\n return this.setDropNode(undefined);\n }\n return this.setDropNode(dropNode);\n }\n\n /** 判断能否将节点拖入容器 */\n protected canDropToContainer(params: {\n dragNode: WorkflowNodeEntity;\n dropNode?: WorkflowNodeEntity;\n }): boolean {\n const { dragNode, dropNode } = params;\n const isDropContainer = dropNode?.getNodeMeta<WorkflowNodeMeta>().isContainer;\n if (!dropNode || !isDropContainer || this.isParent(dragNode, dropNode)) {\n return false;\n }\n if (\n dragNode.flowNodeType === FlowNodeBaseType.GROUP &&\n dropNode.flowNodeType !== FlowNodeBaseType.GROUP\n ) {\n // 禁止将 group 节点拖入非 group 节点(由于目前不支持多节点拖入容器,无法计算有效线条,因此进行屏蔽)\n return false;\n }\n const canDrop = this.dragService.canDropToNode({\n dragNodeType: dragNode.flowNodeType,\n dropNodeType: dropNode?.flowNodeType,\n dragNode,\n dropNode,\n });\n if (!canDrop.allowDrop) {\n return false;\n }\n return true;\n }\n\n /** 判断一个节点是否为另一个节点的父节点(向上查找直到根节点) */\n private isParent(node: WorkflowNodeEntity, parent: WorkflowNodeEntity): boolean {\n let current = node.parent;\n while (current) {\n if (current.id === parent.id) {\n return true;\n }\n current = current.parent;\n }\n return false;\n }\n\n /** 将节点移入容器 */\n private async moveIntoContainer(params: {\n node: WorkflowNodeEntity;\n containerNode: WorkflowNodeEntity;\n }): Promise<void> {\n const { node, containerNode } = params;\n const parentNode = node.parent;\n\n this.operationService.moveNode(node, {\n parent: containerNode,\n });\n\n const containerPadding = this.document.layout.getPadding(containerNode);\n const position = ContainerUtils.adjustSubNodePosition({\n targetNode: node,\n containerNode,\n containerPadding,\n });\n\n this.operationService.updateNodePosition(node, position);\n\n await ContainerUtils.nextFrame();\n\n this.emitter.fire({\n type: NodeIntoContainerType.In,\n node,\n sourceContainer: parentNode,\n targetContainer: containerNode,\n });\n }\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nexport const nextFrame = async (): Promise<void> => {\n await new Promise((resolve) => requestAnimationFrame(resolve));\n};\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { WorkflowNodeEntity, WorkflowNodeMeta } from '@flowgram.ai/free-layout-core';\n\nexport const isContainer = (node?: WorkflowNodeEntity): boolean =>\n node?.getNodeMeta<WorkflowNodeMeta>().isContainer ?? false;\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 { FlowNodeTransformData } from '@flowgram.ai/document';\n\nimport { isContainer } from './is-container';\n\n/** 获取容器节点transforms */\nexport const getContainerTransforms = (allNodes: WorkflowNodeEntity[]): FlowNodeTransformData[] =>\n allNodes\n .filter((node) => {\n if (node.originParent) {\n return node.getNodeMeta().selectable && node.originParent.getNodeMeta().selectable;\n }\n return node.getNodeMeta().selectable;\n })\n .filter((node) => isContainer(node))\n .sort((a, b) => {\n const aIndex = a.renderData.stackIndex;\n const bIndex = b.renderData.stackIndex;\n // 确保层级高的节点在前面\n return bIndex - aIndex;\n })\n .map((node) => node.transform);\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { PositionSchema, Rectangle } from '@flowgram.ai/utils';\nimport { WorkflowDocument } from '@flowgram.ai/free-layout-core';\nimport { FlowNodeTransformData } from '@flowgram.ai/document';\n\nimport { isRectIntersects } from './is-rect-intersects';\nimport { isPointInRect } from './is-point-in-rect';\n\n/** 获取重叠位置 */\nexport const getCollisionTransform = (params: {\n transforms: FlowNodeTransformData[];\n targetRect?: Rectangle;\n targetPoint?: PositionSchema;\n withPadding?: boolean;\n document: WorkflowDocument;\n}): FlowNodeTransformData | undefined => {\n const { targetRect, targetPoint, transforms, withPadding = false, document } = params;\n const collisionTransform = transforms.find((transform) => {\n const { bounds, entity } = transform;\n const padding = withPadding ? document.layout.getPadding(entity) : { left: 0, right: 0 };\n const transformRect = new Rectangle(\n bounds.x + padding.left + padding.right,\n bounds.y,\n bounds.width,\n bounds.height\n );\n // 检测两个正方形是否相互碰撞\n if (targetRect) {\n return isRectIntersects(targetRect, transformRect);\n }\n if (targetPoint) {\n return isPointInRect(targetPoint, transformRect);\n }\n return false;\n });\n return collisionTransform;\n};\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { Rectangle } from '@flowgram.ai/utils';\n\nexport const isRectIntersects = (rectA: Rectangle, rectB: Rectangle): boolean => {\n // 检查水平方向是否有重叠\n const hasHorizontalOverlap = rectA.right > rectB.left && rectA.left < rectB.right;\n // 检查垂直方向是否有重叠\n const hasVerticalOverlap = rectA.bottom > rectB.top && rectA.top < rectB.bottom;\n // 只有当水平和垂直方向都有重叠时,两个矩形才相交\n return hasHorizontalOverlap && hasVerticalOverlap;\n};\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { PositionSchema, Rectangle } from '@flowgram.ai/utils';\n\nexport const isPointInRect = (point: PositionSchema, rect: Rectangle): boolean =>\n point.x >= rect.left && point.x <= rect.right && point.y >= rect.top && point.y <= rect.bottom;\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { IPoint, PaddingSchema } from '@flowgram.ai/utils';\nimport { WorkflowNodeEntity } from '@flowgram.ai/free-layout-core';\nimport { FlowNodeBaseType } from '@flowgram.ai/document';\n\n/**\n * 如果存在容器节点,且传入鼠标坐标,需要用容器的坐标减去传入的鼠标坐标\n */\nexport const adjustSubNodePosition = (params: {\n targetNode: WorkflowNodeEntity;\n containerNode: WorkflowNodeEntity;\n containerPadding: PaddingSchema;\n}): IPoint => {\n const { targetNode, containerNode, containerPadding } = params;\n if (containerNode.flowNodeType === FlowNodeBaseType.ROOT) {\n return targetNode.transform.position;\n }\n const nodeWorldTransform = targetNode.transform.transform.worldTransform;\n const containerWorldTransform = containerNode.transform.transform.worldTransform;\n const nodePosition = {\n x: nodeWorldTransform.tx,\n y: nodeWorldTransform.ty,\n };\n const isParentEmpty = !containerNode.children || containerNode.children.length === 0;\n if (isParentEmpty) {\n // 确保空容器节点不偏移\n return {\n x: 0,\n y: containerPadding.top,\n };\n } else {\n return {\n x: nodePosition.x - containerWorldTransform.tx,\n y: nodePosition.y - containerWorldTransform.ty,\n };\n }\n};\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { nextFrame } from './next-frame';\nimport { isContainer } from './is-container';\nimport { getContainerTransforms } from './get-container-transforms';\nimport { getCollisionTransform } from './get-collision-transform';\nimport { adjustSubNodePosition } from './adjust-sub-node-position';\n\nexport const ContainerUtils = {\n nextFrame,\n isContainer,\n adjustSubNodePosition,\n getContainerTransforms,\n getCollisionTransform,\n};\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { definePluginCreator } from '@flowgram.ai/core';\n\nimport type { WorkflowContainerPluginOptions } from './type';\nimport { NodeIntoContainerService } from '.';\n\nexport const createContainerNodePlugin = definePluginCreator<WorkflowContainerPluginOptions>({\n onBind: ({ bind }) => {\n bind(NodeIntoContainerService).toSelf().inSingletonScope();\n },\n onInit(ctx, options) {\n ctx.get(NodeIntoContainerService).init();\n },\n onReady(ctx, options) {\n if (options.disableNodeIntoContainer !== true) {\n ctx.get(NodeIntoContainerService).ready();\n }\n },\n onDispose(ctx) {\n ctx.get(NodeIntoContainerService).dispose();\n },\n});\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { useState, useEffect } from 'react';\n\nimport {\n useCurrentEntity,\n WorkflowNodeMeta,\n WorkflowNodePortsData,\n} from '@flowgram.ai/free-layout-core';\nimport { FlowNodeTransformData } from '@flowgram.ai/document';\n\nexport interface NodeSize {\n width: number;\n height: number;\n}\n\nexport const useNodeSize = (): NodeSize | undefined => {\n const node = useCurrentEntity();\n const nodeMeta = node.getNodeMeta<WorkflowNodeMeta>();\n const { size = { width: 300, height: 200 }, isContainer } = nodeMeta;\n\n const transform = node.getData<FlowNodeTransformData>(FlowNodeTransformData);\n const [width, setWidth] = useState(size.width);\n const [height, setHeight] = useState(size.height);\n\n const updatePorts = () => {\n const portsData = node.getData<WorkflowNodePortsData>(WorkflowNodePortsData);\n portsData.updateDynamicPorts();\n };\n\n const updateSize = () => {\n // 无子节点时\n if (node.blocks.length === 0) {\n setWidth(size.width);\n setHeight(size.height);\n return;\n }\n // 存在子节点时,只监听宽高变化\n setWidth(transform.bounds.width);\n setHeight(transform.bounds.height);\n };\n\n useEffect(() => {\n const dispose = transform.onDataChange(() => {\n updateSize();\n updatePorts();\n });\n return () => dispose.dispose();\n }, [transform, width, height]);\n\n useEffect(() => {\n // 初始化触发一次\n updateSize();\n }, []);\n\n if (!isContainer) {\n return;\n }\n\n return {\n width,\n height,\n };\n};\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { useLayoutEffect } from 'react';\n\nimport { useCurrentEntity } from '@flowgram.ai/free-layout-core';\n\nimport { NodeSize } from './use-node-size';\n\nexport const useSyncNodeRenderSize = (nodeSize?: NodeSize) => {\n const node = useCurrentEntity();\n\n useLayoutEffect(() => {\n if (!nodeSize) {\n return;\n }\n node.renderData.node.style.width = nodeSize.width + 'px';\n node.renderData.node.style.height = nodeSize.height + 'px';\n }, [nodeSize?.width, nodeSize?.height]);\n};\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport React, { type FC } from 'react';\n\nimport { useCurrentEntity } from '@flowgram.ai/free-layout-core';\nimport { useService } from '@flowgram.ai/core';\nimport { BackgroundConfig, BackgroundLayerOptions } from '@flowgram.ai/background-plugin';\n\nimport { SubCanvasBackgroundStyle } from './style';\n\nexport const SubCanvasBackground: FC = () => {\n const node = useCurrentEntity();\n\n // 通过 inversify 获取背景配置,如果没有配置则使用默认值\n let backgroundConfig: BackgroundLayerOptions = {};\n try {\n backgroundConfig = useService<BackgroundLayerOptions>(BackgroundConfig);\n } catch (error) {\n // 如果 BackgroundConfig 没有注册,使用默认配置\n // 静默处理,使用默认配置\n }\n\n // 获取配置值,如果没有则使用默认值\n const gridSize = backgroundConfig.gridSize ?? 20;\n const dotSize = backgroundConfig.dotSize ?? 1;\n const dotColor = backgroundConfig.dotColor ?? '#eceeef';\n const dotOpacity = backgroundConfig.dotOpacity ?? 0.5;\n const backgroundColor = backgroundConfig.backgroundColor ?? '#f2f3f5';\n // 只有当 dotFillColor 被明确设置且与 dotColor 不同时才添加 fill 属性\n const dotFillColor =\n backgroundConfig.dotFillColor === dotColor ? '' : backgroundConfig.dotFillColor;\n\n // 生成唯一的 pattern ID\n const patternId = `sub-canvas-dot-pattern-${node.id}`;\n\n return (\n <SubCanvasBackgroundStyle\n className=\"sub-canvas-background\"\n data-flow-editor-selectable=\"true\"\n style={{ backgroundColor: backgroundColor }}\n >\n <svg width=\"100%\" height=\"100%\">\n <pattern id={patternId} width={gridSize} height={gridSize} patternUnits=\"userSpaceOnUse\">\n <circle\n cx={dotSize}\n cy={dotSize}\n r={dotSize}\n stroke={dotColor}\n fill={dotFillColor}\n fillOpacity={dotOpacity}\n />\n </pattern>\n <rect\n width=\"100%\"\n height=\"100%\"\n fill={`url(#${patternId})`}\n data-node-panel-container={node.id}\n />\n </svg>\n </SubCanvasBackgroundStyle>\n );\n};\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport styled from 'styled-components';\n\nexport const SubCanvasBackgroundStyle = styled.div`\n width: 100%;\n height: 100%;\n inset: 56px 18px 18px;\n /* 背景色现在通过 style 属性动态设置 */\n`;\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport React, { CSSProperties, ReactNode, type FC } from 'react';\n\nimport { SubCanvasBorderStyle } from './style';\n\ninterface ISubCanvasBorder {\n style?: CSSProperties;\n children?: ReactNode | ReactNode[];\n}\n\nexport const SubCanvasBorder: FC<ISubCanvasBorder> = ({ style, children }) => (\n <SubCanvasBorderStyle\n className=\"sub-canvas-border\"\n style={{\n ...style,\n }}\n >\n {children}\n </SubCanvasBorderStyle>\n);\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport styled from 'styled-components';\n\nexport const SubCanvasBorderStyle = styled.div`\n pointer-events: none;\n\n position: relative;\n\n display: flex;\n align-items: center;\n\n width: 100%;\n height: 100%;\n\n background-color: transparent;\n border: 1px solid var(--coz-stroke-plus, rgba(6, 7, 9, 15%));\n border-color: var(--coz-bg-plus, rgb(249, 249, 249));\n border-style: solid;\n border-width: 8px;\n border-radius: 8px;\n\n &::before {\n content: '';\n\n position: absolute;\n z-index: 0;\n inset: -4px;\n\n background-color: transparent;\n border-color: var(--coz-bg-plus, rgb(249, 249, 249));\n border-style: solid;\n border-width: 4px;\n border-radius: 8px;\n }\n`;\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport React, { CSSProperties, type FC } from 'react';\n\nimport { SubCanvasRenderStyle } from './style';\nimport { SubCanvasTips } from '../tips';\nimport { SubCanvasBorder } from '../border';\nimport { SubCanvasBackground } from '../background';\nimport { useNodeSize, useSyncNodeRenderSize } from '../../hooks';\n\ninterface ISubCanvasRender {\n offsetY?: number;\n className?: string;\n style?: CSSProperties;\n tipText?: string | React.ReactNode;\n}\n\nexport const SubCanvasRender: FC<ISubCanvasRender> = ({\n className,\n style,\n offsetY = 0,\n tipText,\n}) => {\n const nodeSize = useNodeSize();\n const nodeHeight = nodeSize?.height ?? 0;\n\n useSyncNodeRenderSize(nodeSize);\n\n return (\n <SubCanvasRenderStyle\n className={`sub-canvas-render ${className ?? ''}`}\n style={{\n height: nodeHeight + offsetY,\n ...style,\n }}\n data-flow-editor-selectable=\"true\"\n onDragStart={(e) => {\n e.stopPropagation();\n }}\n >\n <SubCanvasBorder>\n <SubCanvasBackground />\n <SubCanvasTips tipText={tipText} />\n </SubCanvasBorder>\n </SubCanvasRenderStyle>\n );\n};\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport styled from 'styled-components';\n\nexport const SubCanvasRenderStyle = styled.div`\n width: 100%;\n height: 100%;\n`;\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport React from 'react';\n\nimport { I18n } from '@flowgram.ai/i18n';\n\nimport { useControlTips } from './use-control';\nimport { SubCanvasTipsStyle } from './style';\nimport { isMacOS } from './is-mac-os';\nimport { IconClose } from './icon-close';\n\ninterface SubCanvasTipsProps {\n tipText?: string | React.ReactNode;\n neverRemindText?: string | React.ReactNode;\n}\n\nexport const SubCanvasTips = ({ tipText, neverRemindText }: SubCanvasTipsProps) => {\n const { visible, close, closeForever } = useControlTips();\n\n const displayContent =\n tipText || I18n.t('Hold {{key}} to drag node out', { key: isMacOS ? 'Cmd ⌘' : 'Ctrl' });\n\n if (!visible) {\n return null;\n }\n return (\n <SubCanvasTipsStyle className={'sub-canvas-tips'}>\n <div className=\"container\">\n <div className=\"content\">\n {typeof displayContent === 'string' ? (\n <p className=\"text\">{displayContent}</p>\n ) : (\n <div className=\"custom-content\">{displayContent}</div>\n )}\n <div\n className=\"space\"\n style={{\n width: 0,\n }}\n />\n </div>\n <div className=\"actions\">\n <p className=\"close-forever\" onClick={closeForever}>\n {neverRemindText || I18n.t('Never Remind')}\n </p>\n <div className=\"close\" onClick={close}>\n <IconClose />\n </div>\n </div>\n </div>\n </SubCanvasTipsStyle>\n );\n};\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { useCallback, useEffect, useState } from 'react';\n\nimport { useCurrentEntity } from '@flowgram.ai/free-layout-core';\nimport { useService } from '@flowgram.ai/core';\n\nimport { NodeIntoContainerService, NodeIntoContainerType } from '../../../node-into-container';\nimport { TipsGlobalStore } from './global-store';\n\nexport const useControlTips = () => {\n const node = useCurrentEntity();\n const [visible, setVisible] = useState(false);\n const globalStore = TipsGlobalStore.instance;\n\n const nodeIntoContainerService = useService<NodeIntoContainerService>(NodeIntoContainerService);\n\n const show = useCallback(() => {\n if (globalStore.isClosed()) {\n return;\n }\n\n setVisible(true);\n }, [globalStore]);\n\n const close = useCallback(() => {\n globalStore.close();\n setVisible(false);\n }, [globalStore]);\n\n const closeForever = useCallback(() => {\n globalStore.closeForever();\n close();\n }, [close, globalStore]);\n\n useEffect(() => {\n // 监听移入\n const inDisposer = nodeIntoContainerService.on((e) => {\n if (e.type !== NodeIntoContainerType.In) {\n return;\n }\n if (e.targetContainer === node) {\n show();\n }\n });\n // 监听移出事件\n const outDisposer = nodeIntoContainerService.on((e) => {\n if (e.type !== NodeIntoContainerType.Out) {\n return;\n }\n if (e.sourceContainer === node && !node.blocks.length) {\n setVisible(false);\n }\n });\n return () => {\n inDisposer.dispose();\n outDisposer.dispose();\n };\n }, [nodeIntoContainerService, node, show, close, visible]);\n\n return {\n visible,\n close,\n closeForever,\n };\n};\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\n/* eslint-disable @typescript-eslint/naming-convention -- no need */\n\nconst STORAGE_KEY = 'workflow-move-into-sub-canvas-tip-visible';\nconst STORAGE_VALUE = 'false';\n\nexport class TipsGlobalStore {\n private static _instance?: TipsGlobalStore;\n\n public static get instance(): TipsGlobalStore {\n if (!this._instance) {\n this._instance = new TipsGlobalStore();\n }\n return this._instance;\n }\n\n private closed = false;\n\n public isClosed(): boolean {\n return this.isCloseForever() || this.closed;\n }\n\n public close(): void {\n this.closed = true;\n }\n\n public isCloseForever(): boolean {\n return localStorage.getItem(STORAGE_KEY) === STORAGE_VALUE;\n }\n\n public closeForever(): void {\n localStorage.setItem(STORAGE_KEY, STORAGE_VALUE);\n }\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport styled from 'styled-components';\n\nexport const SubCanvasTipsStyle = styled.div`\n pointer-events: auto;\n position: absolute;\n top: 0;\n\n width: 100%;\n height: 28px;\n\n .container {\n height: 100%;\n background-color: #e4e6f5;\n border-radius: 4px 4px 0 0;\n\n .content {\n overflow: hidden;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n\n width: 100%;\n height: 100%;\n\n .text {\n font-size: 14px;\n font-weight: 400;\n font-style: normal;\n line-height: 20px;\n color: rgba(15, 21, 40, 82%);\n text-overflow: ellipsis;\n }\n\n .custom-content {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: 100%;\n\n /* 为自定义内容提供默认样式,但允许覆盖 */\n font-size: 14px;\n font-weight: 400;\n line-height: 20px;\n color: rgba(15, 21, 40, 82%);\n\n /* 确保自定义内容不会超出容器 */\n overflow: hidden;\n }\n\n .space {\n width: 128px;\n }\n }\n\n .actions {\n position: absolute;\n top: 0;\n right: 0;\n\n display: flex;\n gap: 8px;\n align-items: center;\n\n height: 28px;\n padding: 0 16px;\n\n .close-forever {\n cursor: pointer;\n\n padding: 0 3px;\n\n font-size: 12px;\n font-weight: 400;\n font-style: normal;\n line-height: 12px;\n color: rgba(32, 41, 69, 62%);\n }\n\n .close {\n display: flex;\n cursor: pointer;\n height: 100%;\n align-items: center;\n }\n }\n }\n`;\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nexport const isMacOS = /(Macintosh|MacIntel|MacPPC|Mac68K|iPad)/.test(navigator.userAgent);\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport React from 'react';\n\nexport const IconClose = () => (\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" fill=\"none\" viewBox=\"0 0 16 16\">\n <path\n fill=\"#060709\"\n fillOpacity=\"0.5\"\n d=\"M12.13 12.128a.5.5 0 0 0 .001-.706L8.71 8l3.422-3.423a.5.5 0 0 0-.001-.705.5.5 0 0 0-.706-.002L8.002 7.293 4.579 3.87a.5.5 0 0 0-.705.002.5.5 0 0 0-.002.705L7.295 8l-3.423 3.422a.5.5 0 0 0 .002.706c.195.195.51.197.705.001l3.423-3.422 3.422 3.422c.196.196.51.194.706-.001\"\n ></path>\n </svg>\n);\n"],"mappings":";;;;;;;;;;;;AAKO,IAAK,wBAAL,kBAAKA,2BAAL;AACL,EAAAA,uBAAA,QAAK;AACL,EAAAA,uBAAA,SAAM;AAFI,SAAAA;AAAA,GAAA;;;ACCZ,SAAS,gBAAgB;AACzB,SAAS,QAAQ,kBAAkB;AACnC,SAA0B,sBAAsB,eAAe;AAC/D;AAAA,EAEE;AAAA,EACA;AAAA,EACA;AAAA,EAGA;AAAA,EACA;AAAA,OACK;AACP,SAAS,sBAAsB;AAC/B,SAAS,oBAAoB,oBAAAC,yBAAwB;AACrD,SAAS,wBAAwB,qBAAqB;;;AChB/C,IAAM,YAAY,YAA2B;AAClD,QAAM,IAAI,QAAQ,CAAC,YAAY,sBAAsB,OAAO,CAAC;AAC/D;;;ACAO,IAAM,cAAc,CAAC,SAC1B,MAAM,YAA8B,EAAE,eAAe;;;ACGhD,IAAM,yBAAyB,CAAC,aACrC,SACG,OAAO,CAAC,SAAS;AAChB,MAAI,KAAK,cAAc;AACrB,WAAO,KAAK,YAAY,EAAE,cAAc,KAAK,aAAa,YAAY,EAAE;AAAA,EAC1E;AACA,SAAO,KAAK,YAAY,EAAE;AAC5B,CAAC,EACA,OAAO,CAAC,SAAS,YAAY,IAAI,CAAC,EAClC,KAAK,CAAC,GAAG,MAAM;AACd,QAAM,SAAS,EAAE,WAAW;AAC5B,QAAM,SAAS,EAAE,WAAW;AAE5B,SAAO,SAAS;AAClB,CAAC,EACA,IAAI,CAAC,SAAS,KAAK,SAAS;;;ACrBjC,SAAyB,iBAAiB;;;ACEnC,IAAM,mBAAmB,CAAC,OAAkB,UAA8B;AAE/E,QAAM,uBAAuB,MAAM,QAAQ,MAAM,QAAQ,MAAM,OAAO,MAAM;AAE5E,QAAM,qBAAqB,MAAM,SAAS,MAAM,OAAO,MAAM,MAAM,MAAM;AAEzE,SAAO,wBAAwB;AACjC;;;ACPO,IAAM,gBAAgB,CAAC,OAAuB,SACnD,MAAM,KAAK,KAAK,QAAQ,MAAM,KAAK,KAAK,SAAS,MAAM,KAAK,KAAK,OAAO,MAAM,KAAK,KAAK;;;AFKnF,IAAM,wBAAwB,CAAC,WAMG;AACvC,QAAM,EAAE,YAAY,aAAa,YAAY,cAAc,OAAO,SAAS,IAAI;AAC/E,QAAM,qBAAqB,WAAW,KAAK,CAAC,cAAc;AACxD,UAAM,EAAE,QAAQ,OAAO,IAAI;AAC3B,UAAM,UAAU,cAAc,SAAS,OAAO,WAAW,MAAM,IAAI,EAAE,MAAM,GAAG,OAAO,EAAE;AACvF,UAAM,gBAAgB,IAAI;AAAA,MACxB,OAAO,IAAI,QAAQ,OAAO,QAAQ;AAAA,MAClC,OAAO;AAAA,MACP,OAAO;AAAA,MACP,OAAO;AAAA,IACT;AAEA,QAAI,YAAY;AACd,aAAO,iBAAiB,YAAY,aAAa;AAAA,IACnD;AACA,QAAI,aAAa;AACf,aAAO,cAAc,aAAa,aAAa;AAAA,IACjD;AACA,WAAO;AAAA,EACT,CAAC;AACD,SAAO;AACT;;;AGjCA,SAAS,wBAAwB;AAK1B,IAAM,wBAAwB,CAAC,WAIxB;AACZ,QAAM,EAAE,YAAY,eAAe,iBAAiB,IAAI;AACxD,MAAI,cAAc,iBAAiB,iBAAiB,MAAM;AACxD,WAAO,WAAW,UAAU;AAAA,EAC9B;AACA,QAAM,qBAAqB,WAAW,UAAU,UAAU;AAC1D,QAAM,0BAA0B,cAAc,UAAU,UAAU;AAClE,QAAM,eAAe;AAAA,IACnB,GAAG,mBAAmB;AAAA,IACtB,GAAG,mBAAmB;AAAA,EACxB;AACA,QAAM,gBAAgB,CAAC,cAAc,YAAY,cAAc,SAAS,WAAW;AACnF,MAAI,eAAe;AAEjB,WAAO;AAAA,MACL,GAAG;AAAA,MACH,GAAG,iBAAiB;AAAA,IACtB;AAAA,EACF,OAAO;AACL,WAAO;AAAA,MACL,GAAG,aAAa,IAAI,wBAAwB;AAAA,MAC5C,GAAG,aAAa,IAAI,wBAAwB;AAAA,IAC9C;AAAA,EACF;AACF;;;AC7BO,IAAM,iBAAiB;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;;;ARWO,IAAM,2BAAN,MAA+B;AAAA,EAA/B;AAsBL,SAAQ,UAAU,IAAI,QAAgC;AAEtD,SAAQ,YAAY,IAAI,qBAAqB;AAE7C,SAAgB,KAAK,KAAK,QAAQ;AAAA;AAAA,EAE3B,OAAa;AAClB,SAAK,UAAU;AACf,SAAK,UAAU,KAAK,KAAK,OAAO;AAAA,EAClC;AAAA,EAEO,QAAc;AACnB,SAAK,UAAU,KAAK,KAAK,sBAAsB,CAAC;AAAA,EAClD;AAAA,EAEO,UAAgB;AACrB,SAAK,UAAU;AACf,SAAK,UAAU,QAAQ;AAAA,EACzB;AAAA;AAAA,EAGA,MAAa,iBAAiB,QAAqD;AACjF,UAAM,EAAE,KAAK,IAAI;AACjB,UAAM,aAAa,KAAK;AACxB,UAAM,gBAAgB,YAAY;AAClC,UAAM,WAAW,KAAK,SAAS,WAAW,IAAI;AAC9C,QACE,CAAC,cACD,CAAC,iBACD,CAAC,eAAe,YAAY,UAAU,KACtC,CAAC,SAAS,MAAM,UAChB;AACA;AAAA,IACF;AACA,UAAM,kBAAkB,WAAW,QAAuB,aAAa;AACvE,SAAK,iBAAiB,SAAS,MAAM;AAAA,MACnC,QAAQ;AAAA,IACV,CAAC;AACD,UAAM,eAAe,UAAU;AAC/B,oBAAgB,WAAW;AAC3B,SAAK,iBAAiB,mBAAmB,MAAM;AAAA,MAC7C,GAAG,gBAAgB,SAAS,IAAI,SAAS,KAAM,SAAU;AAAA,MACzD,GAAG,gBAAgB,SAAS,IAAI,SAAS,KAAM,SAAU;AAAA,IAC3D,CAAC;AACD,SAAK,QAAQ,KAAK;AAAA,MAChB;AAAA,MACA;AAAA,MACA,iBAAiB;AAAA,MACjB,iBAAiB;AAAA,IACnB,CAAC;AAAA,EACH;AAAA;AAAA,EAGO,oBAAoB,MAAmC;AAC5D,UAAM,aAAa,KAAK;AACxB,UAAM,gBAAgB,YAAY;AAClC,QAAI,CAAC,cAAc,CAAC,iBAAiB,CAAC,eAAe,YAAY,UAAU,GAAG;AAC5E,aAAO;AAAA,IACT;AACA,UAAM,UAAU,KAAK,YAAY,cAAc;AAAA,MAC7C,cAAc,KAAK;AAAA,MACnB,UAAU;AAAA,MACV,cAAc,eAAe;AAAA,MAC7B,UAAU;AAAA,IACZ,CAAC;AACD,QAAI,CAAC,QAAQ,WAAW;AACtB,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,MAAa,kBAAkB,QAGb;AAChB,UAAM,EAAE,UAAU,aAAa,IAAI;AACnC,QAAI,CAAC,UAAU;AACb;AAAA,IACF;AACA,QAAI,SAAS,WAAW,cAAc;AAEpC;AAAA,IACF;AACA,QACE,SAAS,QAAQ,iBAAiBC,kBAAiB,SACnD,cAAc,iBAAiBA,kBAAiB,OAChD;AAEA;AAAA,IACF;AACA,UAAM,KAAK,gBAAgB,QAAQ;AAAA,EACrC;AAAA;AAAA,EAGA,MAAa,gBAAgB,MAAyC;AACpE,UAAM,QAAQ,KAAK,aAAa,YAAY;AAC5C,UAAM,QAAQ,CAAC,SAAS;AACtB,UAAI,KAAK,KAAK,OAAO,KAAK,MAAM,KAAK,IAAI,OAAO,KAAK,IAAI;AACvD;AAAA,MACF;AACA,WAAK,QAAQ;AAAA,IACf,CAAC;AACD,UAAM,eAAe,UAAU;AAAA,EACjC;AAAA;AAAA,EAGQ,YAAkB;AACxB,SAAK,QAAQ;AAAA,MACX,gBAAgB;AAAA,MAChB,aAAa;AAAA,MACb,YAAY;AAAA,MACZ,UAAU;AAAA,MACV,UAAU;AAAA,MACV,cAAc;AAAA,IAChB;AAAA,EACF;AAAA;AAAA,EAGQ,wBAAoC;AAC1C,UAAM,eAAe,CAAC,MAAsB,KAAK,aAAa,CAAC;AAC/D,UAAM,wBAAwB,SAAS,cAAc,GAAG;AACxD,WAAO,KAAK,YAAY,YAAY,OAAO,UAAU;AACnD,UAAI,KAAK,cAAc,cAAc,WAAW,GAAG;AACjD;AAAA,MACF;AACA,UAAI,MAAM,SAAS,eAAe;AAChC,YAAI,KAAK,MAAM,aAAa;AAE1B,eAAK,MAAM,cAAc;AACzB;AAAA,QACF;AACA,aAAK,eAAe,iBAAiB;AACrC,aAAK,MAAM,iBAAiB;AAC5B,aAAK,MAAM,aAAa,eAAe,uBAAuB,KAAK,SAAS,YAAY,CAAC;AACzF,aAAK,MAAM,WAAW,KAAK,cAAc,cAAc,CAAC;AACxD,aAAK,MAAM,WAAW;AACtB,aAAK,MAAM,eAAe,KAAK,MAAM,UAAU;AAC/C,cAAM,KAAK,iBAAiB,KAAK;AAAA,MACnC;AACA,UAAI,MAAM,SAAS,cAAc;AAC/B,8BAAsB,KAAK;AAAA,MAC7B;AACA,UAAI,MAAM,SAAS,aAAa;AAC9B,YAAI,KAAK,MAAM,aAAa;AAE1B;AAAA,QACF;AACA,8BAAsB,OAAO;AAC7B,qBAAa,KAAK;AAClB,cAAM,KAAK,oBAAoB;AAC/B,cAAM,KAAK,kBAAkB;AAAA,UAC3B,UAAU,KAAK,MAAM;AAAA,UACrB,cAAc,KAAK,MAAM;AAAA,QAC3B,CAAC;AACD,aAAK,YAAY,MAAS;AAC1B,aAAK,UAAU;AACf,aAAK,eAAe,eAAe;AAAA,MACrC;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,MAAc,iBAAiB,OAAsC;AACnE,UAAM,EAAE,SAAS,IAAI,KAAK;AAC1B,UAAM,YAAY,MAAM,aAAa,WAAW,MAAM,aAAa;AACnE,QACE,CAAC;AAAA,IACD,CAAC;AAAA,IACD,CAAC,KAAK,oBAAoB,QAAQ,GAClC;AACA;AAAA,IACF;AACA,SAAK,iBAAiB,EAAE,MAAM,SAAS,CAAC;AACxC,SAAK,MAAM,cAAc;AACzB,UAAM,QAAQ,KAAK,MAAM,UAAU,SAAS,MAAM,UAAU,OAAO;AACnE,UAAM,eAAe,UAAU;AAC/B,SAAK,YAAY,uBAAuB,MAAM,YAAY;AAAA,EAC5D;AAAA;AAAA,EAGQ,YAAY,UAA+B;AACjD,QAAI,KAAK,MAAM,aAAa,UAAU;AACpC;AAAA,IACF;AACA,QAAI,KAAK,MAAM,UAAU;AAEvB,YAAMC,cAAa,KAAK,MAAM,SAAS,QAAQ,kBAAkB;AACjE,YAAMC,aAAYD,YAAW,MAAM,WAAW,CAAC;AAC/C,UAAIC,YAAW;AACb,QAAAA,WAAU,UAAU,OAAO,UAAU;AAAA,MACvC;AAAA,IACF;AACA,SAAK,MAAM,WAAW;AACtB,QAAI,CAAC,UAAU;AACb;AAAA,IACF;AAEA,UAAM,aAAa,SAAS,QAAQ,kBAAkB;AACtD,UAAM,YAAY,WAAW,MAAM,WAAW,CAAC;AAC/C,QAAI,WAAW;AACb,gBAAU,UAAU,IAAI,UAAU;AAAA,IACpC;AAAA,EACF;AAAA;AAAA,EAGA,MAAc,sBAAqC;AACjD,UAAM,EAAE,UAAU,UAAU,eAAe,IAAI,KAAK;AACpD,QAAI,CAAC,kBAAkB,CAAC,YAAY,CAAC,UAAU;AAC7C;AAAA,IACF;AACA,WAAO,MAAM,KAAK,kBAAkB;AAAA,MAClC,MAAM;AAAA,MACN,eAAe;AAAA,IACjB,CAAC;AAAA,EACH;AAAA;AAAA,EAGQ,aAAa,eAAqC;AACxD,UAAM,EAAE,UAAU,gBAAgB,aAAa,CAAC,EAAE,IAAI,KAAK;AAC3D,QAAI,CAAC,kBAAkB,CAAC,YAAY,CAAC,YAAY,QAAQ;AACvD,aAAO,KAAK,YAAY,MAAS;AAAA,IACnC;AACA,UAAM,WAAW,KAAK,iBAAiB,qBAAqB,cAAc,SAAS;AACnF,UAAM,sBAAsB,WAAW;AAAA,MACrC,CAAC,cAAc,UAAU,OAAO,OAAO,SAAS;AAAA,IAClD;AACA,UAAM,qBAAqB,eAAe,sBAAsB;AAAA,MAC9D,aAAa;AAAA,MACb,YAAY;AAAA,MACZ,UAAU,KAAK;AAAA,IACjB,CAAC;AACD,UAAM,WAAW,oBAAoB;AACrC,UAAM,UAAU,KAAK,mBAAmB;AAAA,MACtC;AAAA,MACA;AAAA,IACF,CAAC;AACD,QAAI,CAAC,SAAS;AACZ,aAAO,KAAK,YAAY,MAAS;AAAA,IACnC;AACA,WAAO,KAAK,YAAY,QAAQ;AAAA,EAClC;AAAA;AAAA,EAGU,mBAAmB,QAGjB;AACV,UAAM,EAAE,UAAU,SAAS,IAAI;AAC/B,UAAM,kBAAkB,UAAU,YAA8B,EAAE;AAClE,QAAI,CAAC,YAAY,CAAC,mBAAmB,KAAK,SAAS,UAAU,QAAQ,GAAG;AACtE,aAAO;AAAA,IACT;AACA,QACE,SAAS,iBAAiBF,kBAAiB,SAC3C,SAAS,iBAAiBA,kBAAiB,OAC3C;AAEA,aAAO;AAAA,IACT;AACA,UAAM,UAAU,KAAK,YAAY,cAAc;AAAA,MAC7C,cAAc,SAAS;AAAA,MACvB,cAAc,UAAU;AAAA,MACxB;AAAA,MACA;AAAA,IACF,CAAC;AACD,QAAI,CAAC,QAAQ,WAAW;AACtB,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAGQ,SAAS,MAA0B,QAAqC;AAC9E,QAAI,UAAU,KAAK;AACnB,WAAO,SAAS;AACd,UAAI,QAAQ,OAAO,OAAO,IAAI;AAC5B,eAAO;AAAA,MACT;AACA,gBAAU,QAAQ;AAAA,IACpB;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,MAAc,kBAAkB,QAGd;AAChB,UAAM,EAAE,MAAM,cAAc,IAAI;AAChC,UAAM,aAAa,KAAK;AAExB,SAAK,iBAAiB,SAAS,MAAM;AAAA,MACnC,QAAQ;AAAA,IACV,CAAC;AAED,UAAM,mBAAmB,KAAK,SAAS,OAAO,WAAW,aAAa;AACtE,UAAM,WAAW,eAAe,sBAAsB;AAAA,MACpD,YAAY;AAAA,MACZ;AAAA,MACA;AAAA,IACF,CAAC;AAED,SAAK,iBAAiB,mBAAmB,MAAM,QAAQ;AAEvD,UAAM,eAAe,UAAU;AAE/B,SAAK,QAAQ,KAAK;AAAA,MAChB;AAAA,MACA;AAAA,MACA,iBAAiB;AAAA,MACjB,iBAAiB;AAAA,IACnB,CAAC;AAAA,EACH;AACF;AA5UU;AAAA,EADP,OAAO,mBAAmB;AAAA,GAHhB,yBAIH;AAGA;AAAA,EADP,OAAO,gBAAgB;AAAA,GANb,yBAOH;AAGA;AAAA,EADP,OAAO,sBAAsB;AAAA,GATnB,yBAUH;AAGA;AAAA,EADP,OAAO,4BAA4B;AAAA,GAZzB,yBAaH;AAGA;AAAA,EADP,OAAO,oBAAoB;AAAA,GAfjB,yBAgBH;AAEwB;AAAA,EAA/B,OAAO,cAAc;AAAA,GAlBX,yBAkBqB;AAEO;AAAA,EAAtC,OAAO,qBAAqB;AAAA,GApBlB,yBAoB4B;AApB5B,2BAAN;AAAA,EADN,WAAW;AAAA,GACC;;;ASvBb,SAAS,2BAA2B;AAK7B,IAAM,4BAA4B,oBAAoD;AAAA,EAC3F,QAAQ,CAAC,EAAE,KAAK,MAAM;AACpB,SAAK,wBAAwB,EAAE,OAAO,EAAE,iBAAiB;AAAA,EAC3D;AAAA,EACA,OAAO,KAAK,SAAS;AACnB,QAAI,IAAI,wBAAwB,EAAE,KAAK;AAAA,EACzC;AAAA,EACA,QAAQ,KAAK,SAAS;AACpB,QAAI,QAAQ,6BAA6B,MAAM;AAC7C,UAAI,IAAI,wBAAwB,EAAE,MAAM;AAAA,IAC1C;AAAA,EACF;AAAA,EACA,UAAU,KAAK;AACb,QAAI,IAAI,wBAAwB,EAAE,QAAQ;AAAA,EAC5C;AACF,CAAC;;;ACpBD,SAAS,UAAU,iBAAiB;AAEpC;AAAA,EACE;AAAA,EAEA;AAAA,OACK;AACP,SAAS,6BAA6B;AAO/B,IAAM,cAAc,MAA4B;AACrD,QAAM,OAAO,iBAAiB;AAC9B,QAAM,WAAW,KAAK,YAA8B;AACpD,QAAM,EAAE,OAAO,EAAE,OAAO,KAAK,QAAQ,IAAI,GAAG,aAAAG,aAAY,IAAI;AAE5D,QAAM,YAAY,KAAK,QAA+B,qBAAqB;AAC3E,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAS,KAAK,KAAK;AAC7C,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,KAAK,MAAM;AAEhD,QAAM,cAAc,MAAM;AACxB,UAAM,YAAY,KAAK,QAA+B,qBAAqB;AAC3E,cAAU,mBAAmB;AAAA,EAC/B;AAEA,QAAM,aAAa,MAAM;AAEvB,QAAI,KAAK,OAAO,WAAW,GAAG;AAC5B,eAAS,KAAK,KAAK;AACnB,gBAAU,KAAK,MAAM;AACrB;AAAA,IACF;AAEA,aAAS,UAAU,OAAO,KAAK;AAC/B,cAAU,UAAU,OAAO,MAAM;AAAA,EACnC;AAEA,YAAU,MAAM;AACd,UAAM,UAAU,UAAU,aAAa,MAAM;AAC3C,iBAAW;AACX,kBAAY;AAAA,IACd,CAAC;AACD,WAAO,MAAM,QAAQ,QAAQ;AAAA,EAC/B,GAAG,CAAC,WAAW,OAAO,MAAM,CAAC;AAE7B,YAAU,MAAM;AAEd,eAAW;AAAA,EACb,GAAG,CAAC,CAAC;AAEL,MAAI,CAACA,cAAa;AAChB;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,EACF;AACF;;;AC7DA,SAAS,uBAAuB;AAEhC,SAAS,oBAAAC,yBAAwB;AAI1B,IAAM,wBAAwB,CAAC,aAAwB;AAC5D,QAAM,OAAOA,kBAAiB;AAE9B,kBAAgB,MAAM;AACpB,QAAI,CAAC,UAAU;AACb;AAAA,IACF;AACA,SAAK,WAAW,KAAK,MAAM,QAAQ,SAAS,QAAQ;AACpD,SAAK,WAAW,KAAK,MAAM,SAAS,SAAS,SAAS;AAAA,EACxD,GAAG,CAAC,UAAU,OAAO,UAAU,MAAM,CAAC;AACxC;;;AChBA,OAAO,WAAwB;AAE/B,SAAS,oBAAAC,yBAAwB;AACjC,SAAS,kBAAkB;AAC3B,SAAS,wBAAgD;;;ACJzD,OAAO,YAAY;AAEZ,IAAM,2BAA2B,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;;;ADMxC,IAAM,sBAA0B,MAAM;AAC3C,QAAM,OAAOC,kBAAiB;AAG9B,MAAI,mBAA2C,CAAC;AAChD,MAAI;AACF,uBAAmB,WAAmC,gBAAgB;AAAA,EACxE,SAAS,OAAO;AAAA,EAGhB;AAGA,QAAM,WAAW,iBAAiB,YAAY;AAC9C,QAAM,UAAU,iBAAiB,WAAW;AAC5C,QAAM,WAAW,iBAAiB,YAAY;AAC9C,QAAM,aAAa,iBAAiB,cAAc;AAClD,QAAM,kBAAkB,iBAAiB,mBAAmB;AAE5D,QAAM,eACJ,iBAAiB,iBAAiB,WAAW,KAAK,iBAAiB;AAGrE,QAAM,YAAY,0BAA0B,KAAK,EAAE;AAEnD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,+BAA4B;AAAA,MAC5B,OAAO,EAAE,gBAAiC;AAAA;AAAA,IAE1C,oCAAC,SAAI,OAAM,QAAO,QAAO,UACvB,oCAAC,aAAQ,IAAI,WAAW,OAAO,UAAU,QAAQ,UAAU,cAAa,oBACtE;AAAA,MAAC;AAAA;AAAA,QACC,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,GAAG;AAAA,QACH,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,aAAa;AAAA;AAAA,IACf,CACF,GACA;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,QAAO;AAAA,QACP,MAAM,QAAQ,SAAS;AAAA,QACvB,6BAA2B,KAAK;AAAA;AAAA,IAClC,CACF;AAAA,EACF;AAEJ;;;AE3DA,OAAOC,YAAkD;;;ACAzD,OAAOC,aAAY;AAEZ,IAAM,uBAAuBA,QAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ADOpC,IAAM,kBAAwC,CAAC,EAAE,OAAO,SAAS,MACtE,gBAAAC,OAAA;AAAA,EAAC;AAAA;AAAA,IACC,WAAU;AAAA,IACV,OAAO;AAAA,MACL,GAAG;AAAA,IACL;AAAA;AAAA,EAEC;AACH;;;AEjBF,OAAOC,YAAuC;;;ACA9C,OAAOC,aAAY;AAEZ,IAAM,uBAAuBA,QAAO;AAAA;AAAA;AAAA;;;ACF3C,OAAOC,YAAW;AAElB,SAAS,YAAY;;;ACFrB,SAAS,aAAa,aAAAC,YAAW,YAAAC,iBAAgB;AAEjD,SAAS,oBAAAC,yBAAwB;AACjC,SAAS,cAAAC,mBAAkB;;;ACD3B,IAAM,cAAc;AACpB,IAAM,gBAAgB;AAEf,IAAM,kBAAN,MAAM,iBAAgB;AAAA,EAAtB;AAUL,SAAQ,SAAS;AAAA;AAAA,EAPjB,WAAkB,WAA4B;AAC5C,QAAI,CAAC,KAAK,WAAW;AACnB,WAAK,YAAY,IAAI,iBAAgB;AAAA,IACvC;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EAIO,WAAoB;AACzB,WAAO,KAAK,eAAe,KAAK,KAAK;AAAA,EACvC;AAAA,EAEO,QAAc;AACnB,SAAK,SAAS;AAAA,EAChB;AAAA,EAEO,iBAA0B;AAC/B,WAAO,aAAa,QAAQ,WAAW,MAAM;AAAA,EAC/C;AAAA,EAEO,eAAqB;AAC1B,iBAAa,QAAQ,aAAa,aAAa;AAAA,EACjD;AACF;;;ADxBO,IAAM,iBAAiB,MAAM;AAClC,QAAM,OAAOC,kBAAiB;AAC9B,QAAM,CAAC,SAAS,UAAU,IAAIC,UAAS,KAAK;AAC5C,QAAM,cAAc,gBAAgB;AAEpC,QAAM,2BAA2BC,YAAqC,wBAAwB;AAE9F,QAAM,OAAO,YAAY,MAAM;AAC7B,QAAI,YAAY,SAAS,GAAG;AAC1B;AAAA,IACF;AAEA,eAAW,IAAI;AAAA,EACjB,GAAG,CAAC,WAAW,CAAC;AAEhB,QAAM,QAAQ,YAAY,MAAM;AAC9B,gBAAY,MAAM;AAClB,eAAW,KAAK;AAAA,EAClB,GAAG,CAAC,WAAW,CAAC;AAEhB,QAAM,eAAe,YAAY,MAAM;AACrC,gBAAY,aAAa;AACzB,UAAM;AAAA,EACR,GAAG,CAAC,OAAO,WAAW,CAAC;AAEvB,EAAAC,WAAU,MAAM;AAEd,UAAM,aAAa,yBAAyB,GAAG,CAAC,MAAM;AACpD,UAAI,EAAE,wBAAmC;AACvC;AAAA,MACF;AACA,UAAI,EAAE,oBAAoB,MAAM;AAC9B,aAAK;AAAA,MACP;AAAA,IACF,CAAC;AAED,UAAM,cAAc,yBAAyB,GAAG,CAAC,MAAM;AACrD,UAAI,EAAE,0BAAoC;AACxC;AAAA,MACF;AACA,UAAI,EAAE,oBAAoB,QAAQ,CAAC,KAAK,OAAO,QAAQ;AACrD,mBAAW,KAAK;AAAA,MAClB;AAAA,IACF,CAAC;AACD,WAAO,MAAM;AACX,iBAAW,QAAQ;AACnB,kBAAY,QAAQ;AAAA,IACtB;AAAA,EACF,GAAG,CAAC,0BAA0B,MAAM,MAAM,OAAO,OAAO,CAAC;AAEzD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;AE/DA,OAAOC,aAAY;AAEZ,IAAM,qBAAqBA,QAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACFlC,IAAM,UAAU,0CAA0C,KAAK,UAAU,SAAS;;;ACAzF,OAAOC,YAAW;AAEX,IAAM,YAAY,MACvB,gBAAAA,OAAA,cAAC,SAAI,OAAM,8BAA6B,OAAM,MAAK,QAAO,MAAK,MAAK,QAAO,SAAQ,eACjF,gBAAAA,OAAA;AAAA,EAAC;AAAA;AAAA,IACC,MAAK;AAAA,IACL,aAAY;AAAA,IACZ,GAAE;AAAA;AACH,CACH;;;ALKK,IAAM,gBAAgB,CAAC,EAAE,SAAS,gBAAgB,MAA0B;AACjF,QAAM,EAAE,SAAS,OAAO,aAAa,IAAI,eAAe;AAExD,QAAM,iBACJ,WAAW,KAAK,EAAE,iCAAiC,EAAE,KAAK,UAAU,eAAU,OAAO,CAAC;AAExF,MAAI,CAAC,SAAS;AACZ,WAAO;AAAA,EACT;AACA,SACE,gBAAAC,OAAA,cAAC,sBAAmB,WAAW,qBAC7B,gBAAAA,OAAA,cAAC,SAAI,WAAU,eACb,gBAAAA,OAAA,cAAC,SAAI,WAAU,aACZ,OAAO,mBAAmB,WACzB,gBAAAA,OAAA,cAAC,OAAE,WAAU,UAAQ,cAAe,IAEpC,gBAAAA,OAAA,cAAC,SAAI,WAAU,oBAAkB,cAAe,GAElD,gBAAAA,OAAA;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,OAAO;AAAA,QACL,OAAO;AAAA,MACT;AAAA;AAAA,EACF,CACF,GACA,gBAAAA,OAAA,cAAC,SAAI,WAAU,aACb,gBAAAA,OAAA,cAAC,OAAE,WAAU,iBAAgB,SAAS,gBACnC,mBAAmB,KAAK,EAAE,cAAc,CAC3C,GACA,gBAAAA,OAAA,cAAC,SAAI,WAAU,SAAQ,SAAS,SAC9B,gBAAAA,OAAA,cAAC,eAAU,CACb,CACF,CACF,CACF;AAEJ;;;AFnCO,IAAM,kBAAwC,CAAC;AAAA,EACpD;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV;AACF,MAAM;AACJ,QAAM,WAAW,YAAY;AAC7B,QAAM,aAAa,UAAU,UAAU;AAEvC,wBAAsB,QAAQ;AAE9B,SACE,gBAAAC,OAAA;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,qBAAqB,aAAa,EAAE;AAAA,MAC/C,OAAO;AAAA,QACL,QAAQ,aAAa;AAAA,QACrB,GAAG;AAAA,MACL;AAAA,MACA,+BAA4B;AAAA,MAC5B,aAAa,CAAC,MAAM;AAClB,UAAE,gBAAgB;AAAA,MACpB;AAAA;AAAA,IAEA,gBAAAA,OAAA,cAAC,uBACC,gBAAAA,OAAA,cAAC,yBAAoB,GACrB,gBAAAA,OAAA,cAAC,iBAAc,SAAkB,CACnC;AAAA,EACF;AAEJ;","names":["NodeIntoContainerType","FlowNodeBaseType","FlowNodeBaseType","renderData","renderDom","isContainer","useCurrentEntity","useCurrentEntity","useCurrentEntity","React","styled","React","React","styled","React","useEffect","useState","useCurrentEntity","useService","useCurrentEntity","useState","useService","useEffect","styled","React","React","React"]}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import * as _flowgram_ai_utils from '@flowgram.ai/utils';
|
|
2
|
+
import * as _flowgram_ai_free_layout_core from '@flowgram.ai/free-layout-core';
|
|
2
3
|
import { WorkflowNodeEntity } from '@flowgram.ai/free-layout-core';
|
|
4
|
+
import * as _flowgram_ai_document from '@flowgram.ai/document';
|
|
3
5
|
import { FlowNodeTransformData } from '@flowgram.ai/document';
|
|
4
6
|
import * as _flowgram_ai_core from '@flowgram.ai/core';
|
|
5
7
|
import React, { FC, CSSProperties, ReactNode } from 'react';
|
|
@@ -70,12 +72,8 @@ declare class NodeIntoContainerService {
|
|
|
70
72
|
private listenDragToContainer;
|
|
71
73
|
/** 监听节点拖拽出容器 */
|
|
72
74
|
private dragOutContainer;
|
|
73
|
-
/** 获取重叠位置 */
|
|
74
|
-
private getCollisionTransform;
|
|
75
75
|
/** 设置放置节点高亮 */
|
|
76
76
|
private setDropNode;
|
|
77
|
-
/** 获取容器节点transforms */
|
|
78
|
-
private getContainerTransforms;
|
|
79
77
|
/** 放置节点到容器 */
|
|
80
78
|
private dropNodeToContainer;
|
|
81
79
|
/** 拖拽节点 */
|
|
@@ -89,16 +87,6 @@ declare class NodeIntoContainerService {
|
|
|
89
87
|
private isParent;
|
|
90
88
|
/** 将节点移入容器 */
|
|
91
89
|
private moveIntoContainer;
|
|
92
|
-
/**
|
|
93
|
-
* 如果存在容器节点,且传入鼠标坐标,需要用容器的坐标减去传入的鼠标坐标
|
|
94
|
-
*/
|
|
95
|
-
private adjustSubNodePosition;
|
|
96
|
-
private isContainer;
|
|
97
|
-
/** 判断点是否在矩形内 */
|
|
98
|
-
private isPointInRect;
|
|
99
|
-
/** 判断两个矩形是否相交 */
|
|
100
|
-
private isRectIntersects;
|
|
101
|
-
private nextFrame;
|
|
102
90
|
}
|
|
103
91
|
|
|
104
92
|
declare const createContainerNodePlugin: _flowgram_ai_core.PluginCreator<WorkflowContainerPluginOptions>;
|
|
@@ -162,4 +150,26 @@ interface SubCanvasTipsProps {
|
|
|
162
150
|
}
|
|
163
151
|
declare const SubCanvasTips: ({ tipText, neverRemindText }: SubCanvasTipsProps) => React.JSX.Element | null;
|
|
164
152
|
|
|
165
|
-
|
|
153
|
+
/**
|
|
154
|
+
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
|
155
|
+
* SPDX-License-Identifier: MIT
|
|
156
|
+
*/
|
|
157
|
+
declare const ContainerUtils: {
|
|
158
|
+
nextFrame: () => Promise<void>;
|
|
159
|
+
isContainer: (node?: _flowgram_ai_free_layout_core.WorkflowNodeEntity) => boolean;
|
|
160
|
+
adjustSubNodePosition: (params: {
|
|
161
|
+
targetNode: _flowgram_ai_free_layout_core.WorkflowNodeEntity;
|
|
162
|
+
containerNode: _flowgram_ai_free_layout_core.WorkflowNodeEntity;
|
|
163
|
+
containerPadding: _flowgram_ai_utils.PaddingSchema;
|
|
164
|
+
}) => _flowgram_ai_utils.IPoint;
|
|
165
|
+
getContainerTransforms: (allNodes: _flowgram_ai_free_layout_core.WorkflowNodeEntity[]) => _flowgram_ai_document.FlowNodeTransformData[];
|
|
166
|
+
getCollisionTransform: (params: {
|
|
167
|
+
transforms: _flowgram_ai_document.FlowNodeTransformData[];
|
|
168
|
+
targetRect?: _flowgram_ai_utils.Rectangle;
|
|
169
|
+
targetPoint?: _flowgram_ai_utils.PositionSchema;
|
|
170
|
+
withPadding?: boolean;
|
|
171
|
+
document: _flowgram_ai_free_layout_core.WorkflowDocument;
|
|
172
|
+
}) => _flowgram_ai_document.FlowNodeTransformData | undefined;
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
export { ContainerUtils, type NodeIntoContainerEvent, NodeIntoContainerService, type NodeIntoContainerState, NodeIntoContainerType, type NodeSize, SubCanvasBackground, SubCanvasBorder, SubCanvasRender, SubCanvasTips, type WorkflowContainerPluginOptions, createContainerNodePlugin, useNodeSize, useSyncNodeRenderSize };
|