@flowgram.ai/free-container-plugin 0.1.0-alpha.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,869 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var __decorateClass = (decorators, target, key, kind) => {
30
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
31
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
32
+ if (decorator = decorators[i])
33
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
34
+ if (kind && result) __defProp(target, key, result);
35
+ return result;
36
+ };
37
+
38
+ // src/index.ts
39
+ var src_exports = {};
40
+ __export(src_exports, {
41
+ NodeIntoContainerService: () => NodeIntoContainerService,
42
+ NodeIntoContainerType: () => NodeIntoContainerType,
43
+ SubCanvasBackground: () => SubCanvasBackground,
44
+ SubCanvasBorder: () => SubCanvasBorder,
45
+ SubCanvasRender: () => SubCanvasRender,
46
+ SubCanvasTips: () => SubCanvasTips,
47
+ createContainerNodePlugin: () => createContainerNodePlugin,
48
+ useNodeSize: () => useNodeSize,
49
+ useSyncNodeRenderSize: () => useSyncNodeRenderSize
50
+ });
51
+ module.exports = __toCommonJS(src_exports);
52
+
53
+ // src/node-into-container/constant.ts
54
+ var NodeIntoContainerType = /* @__PURE__ */ ((NodeIntoContainerType2) => {
55
+ NodeIntoContainerType2["In"] = "in";
56
+ NodeIntoContainerType2["Out"] = "out";
57
+ return NodeIntoContainerType2;
58
+ })(NodeIntoContainerType || {});
59
+
60
+ // src/node-into-container/service.ts
61
+ var import_lodash = require("lodash");
62
+ var import_inversify = require("inversify");
63
+ var import_utils = require("@flowgram.ai/utils");
64
+ var import_free_layout_core = require("@flowgram.ai/free-layout-core");
65
+ var import_free_history_plugin = require("@flowgram.ai/free-history-plugin");
66
+ var import_document = require("@flowgram.ai/document");
67
+ var import_core = require("@flowgram.ai/core");
68
+ var NodeIntoContainerService = class {
69
+ constructor() {
70
+ this.emitter = new import_utils.Emitter();
71
+ this.toDispose = new import_utils.DisposableCollection();
72
+ this.on = this.emitter.event;
73
+ }
74
+ init() {
75
+ this.initState();
76
+ this.toDispose.push(this.emitter);
77
+ }
78
+ ready() {
79
+ this.toDispose.push(this.listenDragToContainer());
80
+ }
81
+ dispose() {
82
+ this.initState();
83
+ this.toDispose.dispose();
84
+ }
85
+ /** 将节点移出容器 */
86
+ async moveOutContainer(params) {
87
+ const { node } = params;
88
+ const parentNode = node.parent;
89
+ const containerNode = parentNode?.parent;
90
+ const nodeJSON = this.document.toNodeJSON(node);
91
+ if (!parentNode || !containerNode || !this.isContainer(parentNode) || !nodeJSON.meta?.position) {
92
+ return;
93
+ }
94
+ const parentTransform = parentNode.getData(import_core.TransformData);
95
+ this.operationService.moveNode(node, {
96
+ parent: containerNode
97
+ });
98
+ await this.nextFrame();
99
+ parentTransform.fireChange();
100
+ this.operationService.updateNodePosition(node, {
101
+ x: parentTransform.position.x + nodeJSON.meta.position.x,
102
+ y: parentTransform.position.y + nodeJSON.meta.position.y
103
+ });
104
+ this.emitter.fire({
105
+ type: "out" /* Out */,
106
+ node,
107
+ sourceContainer: parentNode,
108
+ targetContainer: containerNode
109
+ });
110
+ }
111
+ /** 能否将节点移出容器 */
112
+ canMoveOutContainer(node) {
113
+ const parentNode = node.parent;
114
+ const containerNode = parentNode?.parent;
115
+ if (!parentNode || !containerNode || !this.isContainer(parentNode)) {
116
+ return false;
117
+ }
118
+ const canDrop = this.dragService.canDropToNode({
119
+ dragNodeType: node.flowNodeType,
120
+ dragNode: node,
121
+ dropNodeType: containerNode?.flowNodeType,
122
+ dropNode: containerNode
123
+ });
124
+ if (!canDrop.allowDrop) {
125
+ return false;
126
+ }
127
+ return true;
128
+ }
129
+ /** 移除节点所有非法连线 */
130
+ async clearInvalidLines(params) {
131
+ const { dragNode, sourceParent } = params;
132
+ if (!dragNode) {
133
+ return;
134
+ }
135
+ if (dragNode.parent === sourceParent) {
136
+ return;
137
+ }
138
+ if (dragNode.parent?.flowNodeType === import_document.FlowNodeBaseType.GROUP || sourceParent?.flowNodeType === import_document.FlowNodeBaseType.GROUP) {
139
+ return;
140
+ }
141
+ await this.removeNodeLines(dragNode);
142
+ }
143
+ /** 移除节点连线 */
144
+ async removeNodeLines(node) {
145
+ const lines = this.linesManager.getAllLines();
146
+ lines.forEach((line) => {
147
+ if (line.from.id !== node.id && line.to?.id !== node.id) {
148
+ return;
149
+ }
150
+ line.dispose();
151
+ });
152
+ await this.nextFrame();
153
+ }
154
+ /** 初始化状态 */
155
+ initState() {
156
+ this.state = {
157
+ isDraggingNode: false,
158
+ isSkipEvent: false,
159
+ transforms: void 0,
160
+ dragNode: void 0,
161
+ dropNode: void 0,
162
+ sourceParent: void 0
163
+ };
164
+ }
165
+ /** 监听节点拖拽 */
166
+ listenDragToContainer() {
167
+ const draggingNode = (e) => this.draggingNode(e);
168
+ const throttledDraggingNode = (0, import_lodash.throttle)(draggingNode, 200);
169
+ return this.dragService.onNodesDrag(async (event) => {
170
+ if (this.selectService.selectedNodes.length !== 1) {
171
+ return;
172
+ }
173
+ if (event.type === "onDragStart") {
174
+ if (this.state.isSkipEvent) {
175
+ this.state.isSkipEvent = false;
176
+ return;
177
+ }
178
+ this.historyService.startTransaction();
179
+ this.state.isDraggingNode = true;
180
+ this.state.transforms = this.getContainerTransforms();
181
+ this.state.dragNode = this.selectService.selectedNodes[0];
182
+ this.state.dropNode = void 0;
183
+ this.state.sourceParent = this.state.dragNode?.parent;
184
+ await this.dragOutContainer(event);
185
+ }
186
+ if (event.type === "onDragging") {
187
+ throttledDraggingNode(event);
188
+ }
189
+ if (event.type === "onDragEnd") {
190
+ if (this.state.isSkipEvent) {
191
+ return;
192
+ }
193
+ throttledDraggingNode.cancel();
194
+ draggingNode(event);
195
+ await this.dropNodeToContainer();
196
+ await this.clearInvalidLines({
197
+ dragNode: this.state.dragNode,
198
+ sourceParent: this.state.sourceParent
199
+ });
200
+ this.setDropNode(void 0);
201
+ this.initState();
202
+ this.historyService.endTransaction();
203
+ }
204
+ });
205
+ }
206
+ /** 监听节点拖拽出容器 */
207
+ async dragOutContainer(event) {
208
+ const { dragNode } = this.state;
209
+ const activated = event.triggerEvent.metaKey || event.triggerEvent.ctrlKey;
210
+ if (!activated || // 必须按住指定按键
211
+ !dragNode || // 必须有一个节点
212
+ !this.canMoveOutContainer(dragNode)) {
213
+ return;
214
+ }
215
+ this.moveOutContainer({ node: dragNode });
216
+ this.state.isSkipEvent = true;
217
+ event.dragger.stop(event.dragEvent.clientX, event.dragEvent.clientY);
218
+ await this.nextFrame();
219
+ this.dragService.startDragSelectedNodes(event.triggerEvent);
220
+ }
221
+ /** 获取重叠位置 */
222
+ getCollisionTransform(params) {
223
+ const { targetRect, targetPoint, transforms, withPadding = false } = params;
224
+ const collisionTransform = transforms.find((transform) => {
225
+ const { bounds, entity } = transform;
226
+ const padding = withPadding ? this.document.layout.getPadding(entity) : { left: 0, right: 0 };
227
+ const transformRect = new import_utils.Rectangle(
228
+ bounds.x + padding.left + padding.right,
229
+ bounds.y,
230
+ bounds.width,
231
+ bounds.height
232
+ );
233
+ if (targetRect) {
234
+ return this.isRectIntersects(targetRect, transformRect);
235
+ }
236
+ if (targetPoint) {
237
+ return this.isPointInRect(targetPoint, transformRect);
238
+ }
239
+ return false;
240
+ });
241
+ return collisionTransform;
242
+ }
243
+ /** 设置放置节点高亮 */
244
+ setDropNode(dropNode) {
245
+ if (this.state.dropNode === dropNode) {
246
+ return;
247
+ }
248
+ if (this.state.dropNode) {
249
+ const renderData2 = this.state.dropNode.getData(import_document.FlowNodeRenderData);
250
+ const renderDom2 = renderData2.node?.children?.[0];
251
+ if (renderDom2) {
252
+ renderDom2.classList.remove("selected");
253
+ }
254
+ }
255
+ this.state.dropNode = dropNode;
256
+ if (!dropNode) {
257
+ return;
258
+ }
259
+ const renderData = dropNode.getData(import_document.FlowNodeRenderData);
260
+ const renderDom = renderData.node?.children?.[0];
261
+ if (renderDom) {
262
+ renderDom.classList.add("selected");
263
+ }
264
+ }
265
+ /** 获取容器节点transforms */
266
+ getContainerTransforms() {
267
+ return this.document.getAllNodes().filter((node) => {
268
+ if (node.originParent) {
269
+ return node.getNodeMeta().selectable && node.originParent.getNodeMeta().selectable;
270
+ }
271
+ return node.getNodeMeta().selectable;
272
+ }).filter((node) => this.isContainer(node)).sort((a, b) => {
273
+ const aIndex = a.renderData.stackIndex;
274
+ const bIndex = b.renderData.stackIndex;
275
+ return bIndex - aIndex;
276
+ }).map((node) => node.transform);
277
+ }
278
+ /** 放置节点到容器 */
279
+ async dropNodeToContainer() {
280
+ const { dropNode, dragNode, isDraggingNode } = this.state;
281
+ if (!isDraggingNode || !dragNode || !dropNode) {
282
+ return;
283
+ }
284
+ return await this.moveIntoContainer({
285
+ node: dragNode,
286
+ containerNode: dropNode
287
+ });
288
+ }
289
+ /** 拖拽节点 */
290
+ draggingNode(nodeDragEvent) {
291
+ const { dragNode, isDraggingNode, transforms = [] } = this.state;
292
+ if (!isDraggingNode || !dragNode || !transforms?.length) {
293
+ return this.setDropNode(void 0);
294
+ }
295
+ const mousePos = this.playgroundConfig.getPosFromMouseEvent(nodeDragEvent.dragEvent);
296
+ const availableTransforms = transforms.filter(
297
+ (transform) => transform.entity.id !== dragNode.id
298
+ );
299
+ const collisionTransform = this.getCollisionTransform({
300
+ targetPoint: mousePos,
301
+ transforms: availableTransforms
302
+ });
303
+ const dropNode = collisionTransform?.entity;
304
+ const canDrop = this.canDropToContainer({
305
+ dragNode,
306
+ dropNode
307
+ });
308
+ if (!canDrop) {
309
+ return this.setDropNode(void 0);
310
+ }
311
+ return this.setDropNode(dropNode);
312
+ }
313
+ /** 判断能否将节点拖入容器 */
314
+ canDropToContainer(params) {
315
+ const { dragNode, dropNode } = params;
316
+ const isDropContainer = dropNode?.getNodeMeta().isContainer;
317
+ if (!dropNode || !isDropContainer || this.isParent(dragNode, dropNode)) {
318
+ return false;
319
+ }
320
+ if (dragNode.flowNodeType === import_document.FlowNodeBaseType.GROUP && dropNode.flowNodeType !== import_document.FlowNodeBaseType.GROUP) {
321
+ return false;
322
+ }
323
+ const canDrop = this.dragService.canDropToNode({
324
+ dragNodeType: dragNode.flowNodeType,
325
+ dropNodeType: dropNode?.flowNodeType,
326
+ dragNode,
327
+ dropNode
328
+ });
329
+ if (!canDrop.allowDrop) {
330
+ return false;
331
+ }
332
+ return true;
333
+ }
334
+ /** 判断一个节点是否为另一个节点的父节点(向上查找直到根节点) */
335
+ isParent(node, parent) {
336
+ let current = node.parent;
337
+ while (current) {
338
+ if (current.id === parent.id) {
339
+ return true;
340
+ }
341
+ current = current.parent;
342
+ }
343
+ return false;
344
+ }
345
+ /** 将节点移入容器 */
346
+ async moveIntoContainer(params) {
347
+ const { node, containerNode } = params;
348
+ const parentNode = node.parent;
349
+ this.operationService.moveNode(node, {
350
+ parent: containerNode
351
+ });
352
+ this.operationService.updateNodePosition(node, this.adjustSubNodePosition(node, containerNode));
353
+ await this.nextFrame();
354
+ this.emitter.fire({
355
+ type: "in" /* In */,
356
+ node,
357
+ sourceContainer: parentNode,
358
+ targetContainer: containerNode
359
+ });
360
+ }
361
+ /**
362
+ * 如果存在容器节点,且传入鼠标坐标,需要用容器的坐标减去传入的鼠标坐标
363
+ */
364
+ adjustSubNodePosition(targetNode, containerNode) {
365
+ if (containerNode.flowNodeType === import_document.FlowNodeBaseType.ROOT) {
366
+ return targetNode.transform.position;
367
+ }
368
+ const nodeWorldTransform = targetNode.transform.transform.worldTransform;
369
+ const containerWorldTransform = containerNode.transform.transform.worldTransform;
370
+ const nodePosition = {
371
+ x: nodeWorldTransform.tx,
372
+ y: nodeWorldTransform.ty
373
+ };
374
+ const isParentEmpty = !containerNode.children || containerNode.children.length === 0;
375
+ const containerPadding = this.document.layout.getPadding(containerNode);
376
+ if (isParentEmpty) {
377
+ return {
378
+ x: 0,
379
+ y: containerPadding.top
380
+ };
381
+ } else {
382
+ return {
383
+ x: nodePosition.x - containerWorldTransform.tx,
384
+ y: nodePosition.y - containerWorldTransform.ty
385
+ };
386
+ }
387
+ }
388
+ isContainer(node) {
389
+ return node?.getNodeMeta().isContainer ?? false;
390
+ }
391
+ /** 判断点是否在矩形内 */
392
+ isPointInRect(point, rect) {
393
+ return point.x >= rect.left && point.x <= rect.right && point.y >= rect.top && point.y <= rect.bottom;
394
+ }
395
+ /** 判断两个矩形是否相交 */
396
+ isRectIntersects(rectA, rectB) {
397
+ const hasHorizontalOverlap = rectA.right > rectB.left && rectA.left < rectB.right;
398
+ const hasVerticalOverlap = rectA.bottom > rectB.top && rectA.top < rectB.bottom;
399
+ return hasHorizontalOverlap && hasVerticalOverlap;
400
+ }
401
+ async nextFrame() {
402
+ await new Promise((resolve) => requestAnimationFrame(resolve));
403
+ }
404
+ };
405
+ __decorateClass([
406
+ (0, import_inversify.inject)(import_free_layout_core.WorkflowDragService)
407
+ ], NodeIntoContainerService.prototype, "dragService", 2);
408
+ __decorateClass([
409
+ (0, import_inversify.inject)(import_free_layout_core.WorkflowDocument)
410
+ ], NodeIntoContainerService.prototype, "document", 2);
411
+ __decorateClass([
412
+ (0, import_inversify.inject)(import_core.PlaygroundConfigEntity)
413
+ ], NodeIntoContainerService.prototype, "playgroundConfig", 2);
414
+ __decorateClass([
415
+ (0, import_inversify.inject)(import_free_layout_core.WorkflowOperationBaseService)
416
+ ], NodeIntoContainerService.prototype, "operationService", 2);
417
+ __decorateClass([
418
+ (0, import_inversify.inject)(import_free_layout_core.WorkflowLinesManager)
419
+ ], NodeIntoContainerService.prototype, "linesManager", 2);
420
+ __decorateClass([
421
+ (0, import_inversify.inject)(import_free_history_plugin.HistoryService)
422
+ ], NodeIntoContainerService.prototype, "historyService", 2);
423
+ __decorateClass([
424
+ (0, import_inversify.inject)(import_free_layout_core.WorkflowSelectService)
425
+ ], NodeIntoContainerService.prototype, "selectService", 2);
426
+ NodeIntoContainerService = __decorateClass([
427
+ (0, import_inversify.injectable)()
428
+ ], NodeIntoContainerService);
429
+
430
+ // src/node-into-container/plugin.tsx
431
+ var import_core2 = require("@flowgram.ai/core");
432
+ var createContainerNodePlugin = (0, import_core2.definePluginCreator)({
433
+ onBind: ({ bind }) => {
434
+ bind(NodeIntoContainerService).toSelf().inSingletonScope();
435
+ },
436
+ onInit(ctx, options) {
437
+ ctx.get(NodeIntoContainerService).init();
438
+ },
439
+ onReady(ctx, options) {
440
+ if (options.disableNodeIntoContainer !== true) {
441
+ ctx.get(NodeIntoContainerService).ready();
442
+ }
443
+ },
444
+ onDispose(ctx) {
445
+ ctx.get(NodeIntoContainerService).dispose();
446
+ }
447
+ });
448
+
449
+ // src/sub-canvas/hooks/use-node-size.ts
450
+ var import_react = require("react");
451
+ var import_free_layout_core2 = require("@flowgram.ai/free-layout-core");
452
+ var import_document2 = require("@flowgram.ai/document");
453
+ var useNodeSize = () => {
454
+ const node = (0, import_free_layout_core2.useCurrentEntity)();
455
+ const nodeMeta = node.getNodeMeta();
456
+ const { size = { width: 300, height: 200 }, isContainer } = nodeMeta;
457
+ const transform = node.getData(import_document2.FlowNodeTransformData);
458
+ const [width, setWidth] = (0, import_react.useState)(size.width);
459
+ const [height, setHeight] = (0, import_react.useState)(size.height);
460
+ const updatePorts = () => {
461
+ const portsData = node.getData(import_free_layout_core2.WorkflowNodePortsData);
462
+ portsData.updateDynamicPorts();
463
+ };
464
+ const updateSize = () => {
465
+ if (node.blocks.length === 0) {
466
+ setWidth(size.width);
467
+ setHeight(size.height);
468
+ return;
469
+ }
470
+ setWidth(transform.bounds.width);
471
+ setHeight(transform.bounds.height);
472
+ };
473
+ (0, import_react.useEffect)(() => {
474
+ const dispose = transform.onDataChange(() => {
475
+ updateSize();
476
+ updatePorts();
477
+ });
478
+ return () => dispose.dispose();
479
+ }, [transform, width, height]);
480
+ (0, import_react.useEffect)(() => {
481
+ updateSize();
482
+ }, []);
483
+ if (!isContainer) {
484
+ return;
485
+ }
486
+ return {
487
+ width,
488
+ height
489
+ };
490
+ };
491
+
492
+ // src/sub-canvas/hooks/use-sync-node-render-size.ts
493
+ var import_react2 = require("react");
494
+ var import_free_layout_core3 = require("@flowgram.ai/free-layout-core");
495
+ var useSyncNodeRenderSize = (nodeSize) => {
496
+ const node = (0, import_free_layout_core3.useCurrentEntity)();
497
+ (0, import_react2.useLayoutEffect)(() => {
498
+ if (!nodeSize) {
499
+ return;
500
+ }
501
+ node.renderData.node.style.width = nodeSize.width + "px";
502
+ node.renderData.node.style.height = nodeSize.height + "px";
503
+ }, [nodeSize?.width, nodeSize?.height]);
504
+ };
505
+
506
+ // src/sub-canvas/components/background/index.tsx
507
+ var import_react3 = __toESM(require("react"));
508
+ var import_free_layout_core4 = require("@flowgram.ai/free-layout-core");
509
+ var import_core3 = require("@flowgram.ai/core");
510
+ var import_background_plugin = require("@flowgram.ai/background-plugin");
511
+
512
+ // src/sub-canvas/components/background/style.ts
513
+ var import_styled_components = __toESM(require("styled-components"));
514
+ var SubCanvasBackgroundStyle = import_styled_components.default.div`
515
+ width: 100%;
516
+ height: 100%;
517
+ inset: 56px 18px 18px;
518
+ /* 背景色现在通过 style 属性动态设置 */
519
+ `;
520
+
521
+ // src/sub-canvas/components/background/index.tsx
522
+ var SubCanvasBackground = () => {
523
+ const node = (0, import_free_layout_core4.useCurrentEntity)();
524
+ let backgroundConfig = {};
525
+ try {
526
+ backgroundConfig = (0, import_core3.useService)(import_background_plugin.BackgroundConfig);
527
+ } catch (error) {
528
+ }
529
+ const gridSize = backgroundConfig.gridSize ?? 20;
530
+ const dotSize = backgroundConfig.dotSize ?? 1;
531
+ const dotColor = backgroundConfig.dotColor ?? "#eceeef";
532
+ const dotOpacity = backgroundConfig.dotOpacity ?? 0.5;
533
+ const backgroundColor = backgroundConfig.backgroundColor ?? "#f2f3f5";
534
+ const dotFillColor = backgroundConfig.dotFillColor === dotColor ? "" : backgroundConfig.dotFillColor;
535
+ const patternId = `sub-canvas-dot-pattern-${node.id}`;
536
+ return /* @__PURE__ */ import_react3.default.createElement(
537
+ SubCanvasBackgroundStyle,
538
+ {
539
+ className: "sub-canvas-background",
540
+ "data-flow-editor-selectable": "true",
541
+ style: { backgroundColor }
542
+ },
543
+ /* @__PURE__ */ import_react3.default.createElement("svg", { width: "100%", height: "100%" }, /* @__PURE__ */ import_react3.default.createElement("pattern", { id: patternId, width: gridSize, height: gridSize, patternUnits: "userSpaceOnUse" }, /* @__PURE__ */ import_react3.default.createElement(
544
+ "circle",
545
+ {
546
+ cx: dotSize,
547
+ cy: dotSize,
548
+ r: dotSize,
549
+ stroke: dotColor,
550
+ fill: dotFillColor,
551
+ fillOpacity: dotOpacity
552
+ }
553
+ )), /* @__PURE__ */ import_react3.default.createElement(
554
+ "rect",
555
+ {
556
+ width: "100%",
557
+ height: "100%",
558
+ fill: `url(#${patternId})`,
559
+ "data-node-panel-container": node.id
560
+ }
561
+ ))
562
+ );
563
+ };
564
+
565
+ // src/sub-canvas/components/border/index.tsx
566
+ var import_react4 = __toESM(require("react"));
567
+
568
+ // src/sub-canvas/components/border/style.ts
569
+ var import_styled_components2 = __toESM(require("styled-components"));
570
+ var SubCanvasBorderStyle = import_styled_components2.default.div`
571
+ pointer-events: none;
572
+
573
+ position: relative;
574
+
575
+ display: flex;
576
+ align-items: center;
577
+
578
+ width: 100%;
579
+ height: 100%;
580
+
581
+ background-color: transparent;
582
+ border: 1px solid var(--coz-stroke-plus, rgba(6, 7, 9, 15%));
583
+ border-color: var(--coz-bg-plus, rgb(249, 249, 249));
584
+ border-style: solid;
585
+ border-width: 8px;
586
+ border-radius: 8px;
587
+
588
+ &::before {
589
+ content: '';
590
+
591
+ position: absolute;
592
+ z-index: 0;
593
+ inset: -4px;
594
+
595
+ background-color: transparent;
596
+ border-color: var(--coz-bg-plus, rgb(249, 249, 249));
597
+ border-style: solid;
598
+ border-width: 4px;
599
+ border-radius: 8px;
600
+ }
601
+ `;
602
+
603
+ // src/sub-canvas/components/border/index.tsx
604
+ var SubCanvasBorder = ({ style, children }) => /* @__PURE__ */ import_react4.default.createElement(
605
+ SubCanvasBorderStyle,
606
+ {
607
+ className: "sub-canvas-border",
608
+ style: {
609
+ ...style
610
+ }
611
+ },
612
+ children
613
+ );
614
+
615
+ // src/sub-canvas/components/render/index.tsx
616
+ var import_react8 = __toESM(require("react"));
617
+
618
+ // src/sub-canvas/components/render/style.ts
619
+ var import_styled_components3 = __toESM(require("styled-components"));
620
+ var SubCanvasRenderStyle = import_styled_components3.default.div`
621
+ width: 100%;
622
+ height: 100%;
623
+ `;
624
+
625
+ // src/sub-canvas/components/tips/index.tsx
626
+ var import_react7 = __toESM(require("react"));
627
+ var import_i18n = require("@flowgram.ai/i18n");
628
+
629
+ // src/sub-canvas/components/tips/use-control.ts
630
+ var import_react5 = require("react");
631
+ var import_free_layout_core5 = require("@flowgram.ai/free-layout-core");
632
+ var import_core4 = require("@flowgram.ai/core");
633
+
634
+ // src/sub-canvas/components/tips/global-store.ts
635
+ var STORAGE_KEY = "workflow-move-into-sub-canvas-tip-visible";
636
+ var STORAGE_VALUE = "false";
637
+ var TipsGlobalStore = class _TipsGlobalStore {
638
+ constructor() {
639
+ this.closed = false;
640
+ }
641
+ static get instance() {
642
+ if (!this._instance) {
643
+ this._instance = new _TipsGlobalStore();
644
+ }
645
+ return this._instance;
646
+ }
647
+ isClosed() {
648
+ return this.isCloseForever() || this.closed;
649
+ }
650
+ close() {
651
+ this.closed = true;
652
+ }
653
+ isCloseForever() {
654
+ return localStorage.getItem(STORAGE_KEY) === STORAGE_VALUE;
655
+ }
656
+ closeForever() {
657
+ localStorage.setItem(STORAGE_KEY, STORAGE_VALUE);
658
+ }
659
+ };
660
+
661
+ // src/sub-canvas/components/tips/use-control.ts
662
+ var useControlTips = () => {
663
+ const node = (0, import_free_layout_core5.useCurrentEntity)();
664
+ const [visible, setVisible] = (0, import_react5.useState)(false);
665
+ const globalStore = TipsGlobalStore.instance;
666
+ const nodeIntoContainerService = (0, import_core4.useService)(NodeIntoContainerService);
667
+ const show = (0, import_react5.useCallback)(() => {
668
+ if (globalStore.isClosed()) {
669
+ return;
670
+ }
671
+ setVisible(true);
672
+ }, [globalStore]);
673
+ const close = (0, import_react5.useCallback)(() => {
674
+ globalStore.close();
675
+ setVisible(false);
676
+ }, [globalStore]);
677
+ const closeForever = (0, import_react5.useCallback)(() => {
678
+ globalStore.closeForever();
679
+ close();
680
+ }, [close, globalStore]);
681
+ (0, import_react5.useEffect)(() => {
682
+ const inDisposer = nodeIntoContainerService.on((e) => {
683
+ if (e.type !== "in" /* In */) {
684
+ return;
685
+ }
686
+ if (e.targetContainer === node) {
687
+ show();
688
+ }
689
+ });
690
+ const outDisposer = nodeIntoContainerService.on((e) => {
691
+ if (e.type !== "out" /* Out */) {
692
+ return;
693
+ }
694
+ if (e.sourceContainer === node && !node.blocks.length) {
695
+ setVisible(false);
696
+ }
697
+ });
698
+ return () => {
699
+ inDisposer.dispose();
700
+ outDisposer.dispose();
701
+ };
702
+ }, [nodeIntoContainerService, node, show, close, visible]);
703
+ return {
704
+ visible,
705
+ close,
706
+ closeForever
707
+ };
708
+ };
709
+
710
+ // src/sub-canvas/components/tips/style.ts
711
+ var import_styled_components4 = __toESM(require("styled-components"));
712
+ var SubCanvasTipsStyle = import_styled_components4.default.div`
713
+ pointer-events: auto;
714
+ position: absolute;
715
+ top: 0;
716
+
717
+ width: 100%;
718
+ height: 28px;
719
+
720
+ .container {
721
+ height: 100%;
722
+ background-color: #e4e6f5;
723
+ border-radius: 4px 4px 0 0;
724
+
725
+ .content {
726
+ overflow: hidden;
727
+ display: inline-flex;
728
+ align-items: center;
729
+ justify-content: center;
730
+
731
+ width: 100%;
732
+ height: 100%;
733
+
734
+ .text {
735
+ font-size: 14px;
736
+ font-weight: 400;
737
+ font-style: normal;
738
+ line-height: 20px;
739
+ color: rgba(15, 21, 40, 82%);
740
+ text-overflow: ellipsis;
741
+ }
742
+
743
+ .custom-content {
744
+ display: flex;
745
+ align-items: center;
746
+ justify-content: center;
747
+ width: 100%;
748
+ height: 100%;
749
+
750
+ /* 为自定义内容提供默认样式,但允许覆盖 */
751
+ font-size: 14px;
752
+ font-weight: 400;
753
+ line-height: 20px;
754
+ color: rgba(15, 21, 40, 82%);
755
+
756
+ /* 确保自定义内容不会超出容器 */
757
+ overflow: hidden;
758
+ }
759
+
760
+ .space {
761
+ width: 128px;
762
+ }
763
+ }
764
+
765
+ .actions {
766
+ position: absolute;
767
+ top: 0;
768
+ right: 0;
769
+
770
+ display: flex;
771
+ gap: 8px;
772
+ align-items: center;
773
+
774
+ height: 28px;
775
+ padding: 0 16px;
776
+
777
+ .close-forever {
778
+ cursor: pointer;
779
+
780
+ padding: 0 3px;
781
+
782
+ font-size: 12px;
783
+ font-weight: 400;
784
+ font-style: normal;
785
+ line-height: 12px;
786
+ color: rgba(32, 41, 69, 62%);
787
+ }
788
+
789
+ .close {
790
+ display: flex;
791
+ cursor: pointer;
792
+ height: 100%;
793
+ align-items: center;
794
+ }
795
+ }
796
+ }
797
+ `;
798
+
799
+ // src/sub-canvas/components/tips/is-mac-os.ts
800
+ var isMacOS = /(Macintosh|MacIntel|MacPPC|Mac68K|iPad)/.test(navigator.userAgent);
801
+
802
+ // src/sub-canvas/components/tips/icon-close.tsx
803
+ var import_react6 = __toESM(require("react"));
804
+ var IconClose = () => /* @__PURE__ */ import_react6.default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", fill: "none", viewBox: "0 0 16 16" }, /* @__PURE__ */ import_react6.default.createElement(
805
+ "path",
806
+ {
807
+ fill: "#060709",
808
+ fillOpacity: "0.5",
809
+ 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"
810
+ }
811
+ ));
812
+
813
+ // src/sub-canvas/components/tips/index.tsx
814
+ var SubCanvasTips = ({ tipText, neverRemindText }) => {
815
+ const { visible, close, closeForever } = useControlTips();
816
+ const displayContent = tipText || import_i18n.I18n.t("Hold {{key}} to drag node out", { key: isMacOS ? "Cmd \u2318" : "Ctrl" });
817
+ if (!visible) {
818
+ return null;
819
+ }
820
+ return /* @__PURE__ */ import_react7.default.createElement(SubCanvasTipsStyle, { className: "sub-canvas-tips" }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "container" }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "content" }, typeof displayContent === "string" ? /* @__PURE__ */ import_react7.default.createElement("p", { className: "text" }, displayContent) : /* @__PURE__ */ import_react7.default.createElement("div", { className: "custom-content" }, displayContent), /* @__PURE__ */ import_react7.default.createElement(
821
+ "div",
822
+ {
823
+ className: "space",
824
+ style: {
825
+ width: 0
826
+ }
827
+ }
828
+ )), /* @__PURE__ */ import_react7.default.createElement("div", { className: "actions" }, /* @__PURE__ */ import_react7.default.createElement("p", { className: "close-forever", onClick: closeForever }, neverRemindText || import_i18n.I18n.t("Never Remind")), /* @__PURE__ */ import_react7.default.createElement("div", { className: "close", onClick: close }, /* @__PURE__ */ import_react7.default.createElement(IconClose, null)))));
829
+ };
830
+
831
+ // src/sub-canvas/components/render/index.tsx
832
+ var SubCanvasRender = ({
833
+ className,
834
+ style,
835
+ offsetY = 0,
836
+ tipText
837
+ }) => {
838
+ const nodeSize = useNodeSize();
839
+ const nodeHeight = nodeSize?.height ?? 0;
840
+ useSyncNodeRenderSize(nodeSize);
841
+ return /* @__PURE__ */ import_react8.default.createElement(
842
+ SubCanvasRenderStyle,
843
+ {
844
+ className: `sub-canvas-render ${className ?? ""}`,
845
+ style: {
846
+ height: nodeHeight + offsetY,
847
+ ...style
848
+ },
849
+ "data-flow-editor-selectable": "true",
850
+ onDragStart: (e) => {
851
+ e.stopPropagation();
852
+ }
853
+ },
854
+ /* @__PURE__ */ import_react8.default.createElement(SubCanvasBorder, null, /* @__PURE__ */ import_react8.default.createElement(SubCanvasBackground, null), /* @__PURE__ */ import_react8.default.createElement(SubCanvasTips, { tipText }))
855
+ );
856
+ };
857
+ // Annotate the CommonJS export names for ESM import in node:
858
+ 0 && (module.exports = {
859
+ NodeIntoContainerService,
860
+ NodeIntoContainerType,
861
+ SubCanvasBackground,
862
+ SubCanvasBorder,
863
+ SubCanvasRender,
864
+ SubCanvasTips,
865
+ createContainerNodePlugin,
866
+ useNodeSize,
867
+ useSyncNodeRenderSize
868
+ });
869
+ //# sourceMappingURL=index.js.map