@flowgram-vue/fixed-layout-core 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/LICENSE +22 -0
  2. package/dist/index.cjs +2327 -0
  3. package/dist/index.cjs.map +1 -0
  4. package/dist/index.d.ts +61 -0
  5. package/dist/index.js +2323 -0
  6. package/dist/index.js.map +1 -0
  7. package/package.json +56 -0
  8. package/src/activities/block-icon.ts +55 -0
  9. package/src/activities/block-order-icon.ts +64 -0
  10. package/src/activities/block.ts +192 -0
  11. package/src/activities/break.ts +14 -0
  12. package/src/activities/dynamic-split.ts +94 -0
  13. package/src/activities/empty.ts +35 -0
  14. package/src/activities/end.ts +26 -0
  15. package/src/activities/index.ts +24 -0
  16. package/src/activities/inline-blocks.ts +197 -0
  17. package/src/activities/input.ts +152 -0
  18. package/src/activities/loop-extends/constants.ts +25 -0
  19. package/src/activities/loop-extends/index.ts +10 -0
  20. package/src/activities/loop-extends/loop-empty-branch.ts +60 -0
  21. package/src/activities/loop-extends/loop-inline-blocks.ts +140 -0
  22. package/src/activities/loop-extends/loop-left-empty-block.ts +43 -0
  23. package/src/activities/loop-extends/loop-right-empty-block.ts +18 -0
  24. package/src/activities/loop.ts +198 -0
  25. package/src/activities/multi-inputs.ts +98 -0
  26. package/src/activities/multi-outputs.ts +65 -0
  27. package/src/activities/output.ts +18 -0
  28. package/src/activities/root.ts +23 -0
  29. package/src/activities/simple-split.ts +47 -0
  30. package/src/activities/slot/constants.ts +56 -0
  31. package/src/activities/slot/extends/index.ts +8 -0
  32. package/src/activities/slot/extends/slot-block.ts +229 -0
  33. package/src/activities/slot/extends/slot-icon.ts +32 -0
  34. package/src/activities/slot/extends/slot-inline-blocks.ts +102 -0
  35. package/src/activities/slot/index.ts +8 -0
  36. package/src/activities/slot/slot.ts +108 -0
  37. package/src/activities/slot/typings.ts +13 -0
  38. package/src/activities/slot/utils/create.ts +105 -0
  39. package/src/activities/slot/utils/layout.ts +49 -0
  40. package/src/activities/slot/utils/node.ts +38 -0
  41. package/src/activities/slot/utils/transition.ts +222 -0
  42. package/src/activities/start.ts +21 -0
  43. package/src/activities/static-split.ts +29 -0
  44. package/src/activities/try-catch-extends/catch-block.ts +78 -0
  45. package/src/activities/try-catch-extends/catch-inline-blocks.ts +122 -0
  46. package/src/activities/try-catch-extends/constants.ts +27 -0
  47. package/src/activities/try-catch-extends/index.ts +11 -0
  48. package/src/activities/try-catch-extends/main-inline-blocks.ts +147 -0
  49. package/src/activities/try-catch-extends/try-block.ts +26 -0
  50. package/src/activities/try-catch-extends/try-slot.ts +48 -0
  51. package/src/activities/try-catch.ts +176 -0
  52. package/src/fixed-layout-container-module.ts +20 -0
  53. package/src/flow-registers.ts +117 -0
  54. package/src/index.ts +45 -0
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import {
7
+ FlowNodeBaseType,
8
+ type FlowNodeRegistry,
9
+ type FlowTransitionLine,
10
+ FlowTransitionLineEnum,
11
+ LABEL_SIDE_TYPE,
12
+ FlowTransitionLabelEnum,
13
+ } from '@flowgram-vue/document';
14
+
15
+ /**
16
+ * 输入节点
17
+ */
18
+ export const InputRegistry: FlowNodeRegistry = {
19
+ type: FlowNodeBaseType.INPUT,
20
+ extend: FlowNodeBaseType.BLOCK,
21
+ meta: {
22
+ hidden: false,
23
+ },
24
+ getLines(transition, layout) {
25
+ const currentTransform = transition.transform;
26
+ const { isVertical } = transition.entity;
27
+ const lines: FlowTransitionLine[] = [];
28
+
29
+ const hasBranchDraggingAdder =
30
+ currentTransform && currentTransform.entity.isInlineBlock && transition.renderData.draggable;
31
+
32
+ // 分支拖拽场景线条 push
33
+ // 当有其余分支的时候,绘制一条两个分支之间的线条
34
+ if (hasBranchDraggingAdder) {
35
+ if (isVertical) {
36
+ const currentOffsetRightX = currentTransform.firstChild
37
+ ? currentTransform.firstChild.bounds.right
38
+ : currentTransform.bounds.right;
39
+ const nextOffsetLeftX =
40
+ (currentTransform.next?.firstChild
41
+ ? currentTransform.next?.firstChild.bounds?.left
42
+ : currentTransform.next?.bounds?.left) || 0;
43
+ const currentInputPointY = currentTransform.outputPoint.y;
44
+ if (currentTransform?.next) {
45
+ lines.push({
46
+ type: FlowTransitionLineEnum.MERGE_LINE,
47
+ isDraggingLine: true,
48
+ from: {
49
+ x: (currentOffsetRightX + nextOffsetLeftX) / 2,
50
+ y: currentInputPointY,
51
+ },
52
+ to: currentTransform.parent!.outputPoint,
53
+ side: LABEL_SIDE_TYPE.NORMAL_BRANCH,
54
+ });
55
+ }
56
+ } else {
57
+ const currentOffsetBottomX = currentTransform.firstChild
58
+ ? currentTransform.firstChild.bounds.bottom
59
+ : currentTransform.bounds.bottom;
60
+ const nextOffsetTopX =
61
+ (currentTransform.next?.firstChild
62
+ ? currentTransform.next?.firstChild.bounds?.top
63
+ : currentTransform.next?.bounds?.top) || 0;
64
+ const currentInputPointX = currentTransform.outputPoint.x;
65
+ if (currentTransform?.next) {
66
+ lines.push({
67
+ type: FlowTransitionLineEnum.MERGE_LINE,
68
+ isDraggingLine: true,
69
+ from: {
70
+ x: currentInputPointX,
71
+ y: (currentOffsetBottomX + nextOffsetTopX) / 2,
72
+ },
73
+ to: currentTransform.parent!.outputPoint,
74
+ side: LABEL_SIDE_TYPE.NORMAL_BRANCH,
75
+ });
76
+ }
77
+ }
78
+ }
79
+
80
+ // 最后一个节点是 end 节点,不绘制 mergeLine
81
+ if (!transition.isNodeEnd) {
82
+ lines.push({
83
+ type: FlowTransitionLineEnum.MERGE_LINE,
84
+ from: currentTransform.outputPoint,
85
+ to: currentTransform.parent!.outputPoint,
86
+ side: LABEL_SIDE_TYPE.NORMAL_BRANCH,
87
+ });
88
+ }
89
+
90
+ return lines;
91
+ },
92
+ getLabels(transition) {
93
+ const currentTransform = transition.transform;
94
+ const { isVertical } = transition.entity;
95
+
96
+ const draggingLabel = [];
97
+
98
+ const hasBranchDraggingAdder =
99
+ currentTransform && currentTransform.entity.isInlineBlock && transition.renderData.draggable;
100
+
101
+ // 获取两个分支节点中间点作为拖拽标签插入位置
102
+ if (hasBranchDraggingAdder) {
103
+ if (isVertical) {
104
+ const currentOffsetRightX = currentTransform.firstChild
105
+ ? currentTransform.firstChild.bounds.right
106
+ : currentTransform.bounds.right;
107
+ const nextOffsetLeftX =
108
+ (currentTransform.next?.firstChild
109
+ ? currentTransform.next.firstChild.bounds?.left
110
+ : currentTransform.next?.bounds?.left) || 0;
111
+ const currentInputPointY = currentTransform.outputPoint.y;
112
+ if (currentTransform?.next) {
113
+ draggingLabel.push({
114
+ offset: {
115
+ x: (currentOffsetRightX + nextOffsetLeftX) / 2,
116
+ y: currentInputPointY,
117
+ },
118
+ type: FlowTransitionLabelEnum.BRANCH_DRAGGING_LABEL,
119
+ width: nextOffsetLeftX - currentOffsetRightX,
120
+ props: {
121
+ side: LABEL_SIDE_TYPE.NORMAL_BRANCH,
122
+ },
123
+ });
124
+ }
125
+ } else {
126
+ const currentOffsetBottomX = currentTransform.firstChild
127
+ ? currentTransform.firstChild.bounds.bottom
128
+ : currentTransform.bounds.bottom;
129
+ const nextOffsetTopX =
130
+ (currentTransform.next?.firstChild
131
+ ? currentTransform.next.firstChild.bounds?.top
132
+ : currentTransform.next?.bounds?.top) || 0;
133
+ const currentInputPointX = currentTransform.outputPoint.x;
134
+ if (currentTransform?.next) {
135
+ draggingLabel.push({
136
+ offset: {
137
+ x: currentInputPointX,
138
+ y: (currentOffsetBottomX + nextOffsetTopX) / 2,
139
+ },
140
+ type: FlowTransitionLabelEnum.BRANCH_DRAGGING_LABEL,
141
+ width: nextOffsetTopX - currentOffsetBottomX,
142
+ props: {
143
+ side: LABEL_SIDE_TYPE.NORMAL_BRANCH,
144
+ },
145
+ });
146
+ }
147
+ }
148
+ }
149
+
150
+ return [...draggingLabel];
151
+ },
152
+ };
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { ConstantKeys } from '@flowgram-vue/document';
7
+
8
+ export enum LoopTypeEnum {
9
+ LOOP_LEFT_EMPTY_BLOCK = 'loopLeftEmptyBlock',
10
+ LOOP_RIGHT_EMPTY_BLOCK = 'loopRightEmptyBlock',
11
+ LOOP_EMPTY_BRANCH = 'loopEmptyBranch',
12
+ }
13
+
14
+ export const LoopSpacings = {
15
+ SPACING: 16, // 距离下面节点距离
16
+ COLLAPSE_INLINE_SPACING_BOTTOM: 60, // 距离下面节点距离
17
+ [ConstantKeys.INLINE_SPACING_BOTTOM]: 48, // 下边空白
18
+ MIN_INLINE_BLOCK_SPACING: 280, // 最小循环圈宽度
19
+ HORIZONTAL_MIN_INLINE_BLOCK_SPACING: 180, // 水平布局下的最小循环圈高度
20
+ LEFT_EMPTY_BLOCK_WIDTH: 80, // 左边空分支宽度
21
+ EMPTY_BRANCH_SPACING: 20, // 左边空分支宽度
22
+ LOOP_BLOCK_ICON_SPACING: 13, // inlineBlocks 的 inlineBottom
23
+ [ConstantKeys.INLINE_BLOCKS_INLINE_SPACING_BOTTOM]: 23, // inlineBlocks 的 inlineBottom
24
+ INLINE_BLOCKS_INLINE_SPACING_TOP: 30, // inlineBlocks 的 inlineTop
25
+ };
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ export * from './constants';
7
+ export * from './loop-left-empty-block';
8
+ export * from './loop-right-empty-block';
9
+ export * from './loop-empty-branch';
10
+ export * from './loop-inline-blocks';
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { type FlowNodeRegistry, FlowTransitionLabelEnum } from '@flowgram-vue/document';
7
+
8
+ import { LoopSpacings, LoopTypeEnum } from './constants';
9
+
10
+ export const LoopEmptyBranchRegistry: FlowNodeRegistry = {
11
+ type: LoopTypeEnum.LOOP_EMPTY_BRANCH,
12
+ meta: {
13
+ inlineSpacingAfter: 0,
14
+ spacing: LoopSpacings.EMPTY_BRANCH_SPACING,
15
+ size: {
16
+ width: 100,
17
+ height: 0,
18
+ },
19
+ },
20
+ getLabels(transition) {
21
+ const { isVertical } = transition.entity;
22
+ const currentTransform = transition.transform;
23
+ if (isVertical) {
24
+ return [
25
+ {
26
+ type: FlowTransitionLabelEnum.ADDER_LABEL,
27
+ offset: {
28
+ x: currentTransform.inputPoint.x,
29
+ y: currentTransform.bounds.center.y + 8, // 右边空节点
30
+ },
31
+ },
32
+ ];
33
+ }
34
+ return [
35
+ {
36
+ type: FlowTransitionLabelEnum.ADDER_LABEL,
37
+ offset: {
38
+ x: currentTransform.bounds.center.x + 8,
39
+ y: currentTransform.inputPoint.y,
40
+ },
41
+ },
42
+ ];
43
+ },
44
+ onAfterUpdateLocalTransform(transform): void {
45
+ if (transform.entity.isVertical) {
46
+ transform.data.size = {
47
+ width: 100,
48
+ height: 0,
49
+ };
50
+ } else {
51
+ transform.data.size = {
52
+ width: 0,
53
+ height: 100,
54
+ };
55
+ }
56
+ transform.transform.update({
57
+ size: transform.data.size,
58
+ });
59
+ },
60
+ };
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { Point } from '@flowgram-vue/utils';
7
+ import { FlowTextKey } from '@flowgram-vue/renderer';
8
+ import {
9
+ FlowNodeBaseType,
10
+ type FlowNodeRegistry,
11
+ type FlowTransitionLabel,
12
+ FlowTransitionLabelEnum,
13
+ type FlowTransitionLine,
14
+ FlowTransitionLineEnum,
15
+ getDefaultSpacing,
16
+ ConstantKeys,
17
+ } from '@flowgram-vue/document';
18
+
19
+ import { LoopSpacings } from './constants';
20
+
21
+ export const LoopInlineBlocksNodeRegistry: FlowNodeRegistry = {
22
+ type: FlowNodeBaseType.INLINE_BLOCKS,
23
+ meta: {
24
+ inlineSpacingPre: (node) => {
25
+ const inlineBlocksInlineSpacingTop = getDefaultSpacing(
26
+ node.entity,
27
+ ConstantKeys.INLINE_BLOCKS_INLINE_SPACING_TOP,
28
+ LoopSpacings.INLINE_BLOCKS_INLINE_SPACING_TOP
29
+ );
30
+ return inlineBlocksInlineSpacingTop;
31
+ },
32
+ inlineSpacingAfter: (node) => {
33
+ const inlineBlocksInlineSpacingBottom = getDefaultSpacing(
34
+ node.entity,
35
+ ConstantKeys.INLINE_BLOCKS_INLINE_SPACING_BOTTOM,
36
+ LoopSpacings.INLINE_BLOCKS_INLINE_SPACING_BOTTOM
37
+ );
38
+ return inlineBlocksInlineSpacingBottom;
39
+ },
40
+ minInlineBlockSpacing: (node) =>
41
+ node.entity.isVertical
42
+ ? LoopSpacings.MIN_INLINE_BLOCK_SPACING
43
+ : LoopSpacings.HORIZONTAL_MIN_INLINE_BLOCK_SPACING,
44
+ },
45
+ getLines(transition) {
46
+ const currentTransform = transition.transform;
47
+ const parentTransform = currentTransform.parent!;
48
+ const { isVertical } = transition.entity;
49
+
50
+ const lines: FlowTransitionLine[] = [
51
+ // 循环结束线
52
+ {
53
+ type: FlowTransitionLineEnum.STRAIGHT_LINE,
54
+ from: currentTransform.outputPoint,
55
+ to: parentTransform.outputPoint,
56
+ },
57
+ ];
58
+
59
+ // 收起时展示
60
+ if (currentTransform.collapsed) {
61
+ return lines;
62
+ }
63
+
64
+ const [leftBlockTransform] = currentTransform.children;
65
+
66
+ return [
67
+ ...lines,
68
+ // 循环回撤线 - 1 分成两段可以被 viewport 识别出矩阵区域
69
+ {
70
+ type: FlowTransitionLineEnum.ROUNDED_LINE,
71
+ from: currentTransform.outputPoint,
72
+ to: leftBlockTransform.outputPoint,
73
+ vertices: [
74
+ isVertical
75
+ ? { x: leftBlockTransform.inputPoint.x, y: currentTransform.bounds.bottom }
76
+ : { x: currentTransform.bounds.right, y: leftBlockTransform.inputPoint.y },
77
+ ],
78
+ },
79
+ // 循环回撤线 - 2
80
+ {
81
+ type: FlowTransitionLineEnum.ROUNDED_LINE,
82
+ from: leftBlockTransform.outputPoint,
83
+ to: Point.move(
84
+ currentTransform.inputPoint,
85
+ isVertical ? { x: -12, y: 10 } : { x: 10, y: -12 }
86
+ ),
87
+ vertices: [
88
+ isVertical
89
+ ? { x: leftBlockTransform.inputPoint.x, y: currentTransform.bounds.top + 10 }
90
+ : { x: currentTransform.bounds.left + 10, y: leftBlockTransform.inputPoint.y },
91
+ ],
92
+ arrow: true,
93
+ },
94
+ ];
95
+ },
96
+ getLabels(transition) {
97
+ const currentTransform = transition.transform;
98
+ const { isVertical } = transition.entity;
99
+
100
+ const labels: FlowTransitionLabel[] = [];
101
+
102
+ // 收起时展示
103
+ if (currentTransform.collapsed) {
104
+ return labels;
105
+ }
106
+
107
+ const leftBlockTransform = currentTransform.children[0];
108
+ const rightBlockTransform = currentTransform.children[1];
109
+
110
+ if (transition.entity.originParent?.id.startsWith('while_')) {
111
+ // 满足条件时
112
+ labels.push({
113
+ type: FlowTransitionLabelEnum.TEXT_LABEL,
114
+ renderKey: FlowTextKey.LOOP_WHILE_TEXT,
115
+ rotate: isVertical ? '' : '-90deg',
116
+ offset: isVertical
117
+ ? {
118
+ x: (currentTransform.inputPoint.x + rightBlockTransform.inputPoint.x) / 2,
119
+ y: currentTransform.inputPoint.y + 10,
120
+ }
121
+ : {
122
+ x: currentTransform.inputPoint.x + 10,
123
+ y: (currentTransform.inputPoint.y + rightBlockTransform.inputPoint.y) / 2,
124
+ },
125
+ });
126
+ } else {
127
+ // 循环遍历
128
+ labels.push({
129
+ type: FlowTransitionLabelEnum.TEXT_LABEL,
130
+ renderKey: FlowTextKey.LOOP_TRAVERSE_TEXT,
131
+ // rotate: isVertical ? '' : '-90deg',
132
+ offset: isVertical
133
+ ? { x: leftBlockTransform.inputPoint.x, y: currentTransform.bounds.center.y + 5 }
134
+ : { x: currentTransform.bounds.center.x + 5, y: leftBlockTransform.inputPoint.y },
135
+ });
136
+ }
137
+
138
+ return labels;
139
+ },
140
+ };
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { type FlowNodeRegistry } from '@flowgram-vue/document';
7
+
8
+ import { LoopSpacings, LoopTypeEnum } from './constants';
9
+
10
+ export const LoopLeftEmptyBlockRegistry: FlowNodeRegistry = {
11
+ type: LoopTypeEnum.LOOP_LEFT_EMPTY_BLOCK,
12
+ meta: {
13
+ inlineSpacingAfter: 0,
14
+ spacing: 0,
15
+ size: {
16
+ width: LoopSpacings.LEFT_EMPTY_BLOCK_WIDTH,
17
+ height: 0,
18
+ },
19
+ },
20
+ onAfterUpdateLocalTransform(transform): void {
21
+ // 根据布局要置换宽高数据
22
+ if (transform.entity.isVertical) {
23
+ transform.data.size = {
24
+ width: LoopSpacings.LEFT_EMPTY_BLOCK_WIDTH,
25
+ height: 0,
26
+ };
27
+ } else {
28
+ transform.data.size = {
29
+ width: 0,
30
+ height: LoopSpacings.LEFT_EMPTY_BLOCK_WIDTH,
31
+ };
32
+ }
33
+ transform.transform.update({
34
+ size: transform.data.size,
35
+ });
36
+ },
37
+ getLines() {
38
+ return [];
39
+ },
40
+ getLabels() {
41
+ return [];
42
+ },
43
+ };
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { type FlowNodeRegistry } from '@flowgram-vue/document';
7
+
8
+ import { BlockRegistry } from '../block';
9
+ import { LoopTypeEnum } from './constants';
10
+
11
+ export const LoopRightEmptyBlockRegistry: FlowNodeRegistry = {
12
+ ...BlockRegistry,
13
+ type: LoopTypeEnum.LOOP_RIGHT_EMPTY_BLOCK,
14
+ meta: {
15
+ ...BlockRegistry.meta,
16
+ inlineSpacingAfter: 0,
17
+ },
18
+ };
@@ -0,0 +1,198 @@
1
+ /**
2
+ * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
3
+ * SPDX-License-Identifier: MIT
4
+ */
5
+
6
+ import { Point } from '@flowgram-vue/utils';
7
+ import { FlowTextKey } from '@flowgram-vue/renderer';
8
+ import {
9
+ FlowNodeBaseType,
10
+ type FlowNodeEntity,
11
+ type FlowNodeJSON,
12
+ type FlowNodeRegistry,
13
+ FlowTransitionLabelEnum,
14
+ getDefaultSpacing,
15
+ ConstantKeys,
16
+ } from '@flowgram-vue/document';
17
+
18
+ import {
19
+ LoopEmptyBranchRegistry,
20
+ LoopInlineBlocksNodeRegistry,
21
+ LoopLeftEmptyBlockRegistry,
22
+ LoopRightEmptyBlockRegistry,
23
+ LoopSpacings,
24
+ LoopTypeEnum,
25
+ } from './loop-extends';
26
+
27
+ /**
28
+ * 循环节点
29
+ */
30
+ export const LoopRegistry: FlowNodeRegistry = {
31
+ type: 'loop',
32
+ meta: {
33
+ hidden: true,
34
+ inlineSpacingAfter: (node) => {
35
+ if (node.collapsed) {
36
+ return LoopSpacings.COLLAPSE_INLINE_SPACING_BOTTOM;
37
+ }
38
+ const inlineSpacingBottom = getDefaultSpacing(
39
+ node.entity,
40
+ ConstantKeys.INLINE_SPACING_BOTTOM,
41
+ LoopSpacings.INLINE_SPACING_BOTTOM
42
+ );
43
+ return inlineSpacingBottom;
44
+ },
45
+ spacing: LoopSpacings.SPACING,
46
+ },
47
+ /**
48
+ * - loopNode
49
+ * - loopBlockIcon
50
+ * - loopInlineBlocks
51
+ * - loopEmptyBlock 左侧占位区域
52
+ * - loopBlock
53
+ * - xxx
54
+ * - xxx
55
+ * @param node
56
+ * @param json
57
+ */
58
+ onCreate(node: FlowNodeEntity, json: FlowNodeJSON) {
59
+ const { document } = node;
60
+ const loopBlocks = json.blocks || [];
61
+
62
+ const loopIconNode = document.addNode({
63
+ id: `$blockIcon$${node.id}`,
64
+ type: FlowNodeBaseType.BLOCK_ICON,
65
+ originParent: node,
66
+ parent: node,
67
+ });
68
+ const loopInlineBlocks = document.addNode({
69
+ id: `$inlineBlocks$${node.id}`,
70
+ hidden: true,
71
+ type: FlowNodeBaseType.INLINE_BLOCKS,
72
+ originParent: node,
73
+ parent: node,
74
+ });
75
+ const loopEmptyBlockNode = document.addNode({
76
+ id: `$loopLeftEmpty$${node.id}`,
77
+ hidden: true,
78
+ type: LoopTypeEnum.LOOP_LEFT_EMPTY_BLOCK,
79
+ originParent: node,
80
+ parent: loopInlineBlocks,
81
+ });
82
+
83
+ const loopBlockNode = document.addNode({
84
+ id: `$block$${node.id}`,
85
+ hidden: true,
86
+ type: FlowNodeBaseType.BLOCK, // : LoopTypeEnum.LOOP_RIGHT_EMPTY_BLOCK,
87
+ originParent: node,
88
+ parent: loopInlineBlocks,
89
+ });
90
+ const loopBranch = document.addNode({
91
+ id: `$loopRightEmpty$${node.id}`,
92
+ hidden: true,
93
+ type: LoopTypeEnum.LOOP_EMPTY_BRANCH,
94
+ originParent: node,
95
+ parent: loopBlockNode,
96
+ });
97
+ const otherNodes: FlowNodeEntity[] = [];
98
+ loopBlocks.forEach((b) =>
99
+ document.addNode(
100
+ {
101
+ ...b,
102
+ type: b.type!,
103
+ parent: loopBlockNode,
104
+ },
105
+ otherNodes
106
+ )
107
+ );
108
+
109
+ return [
110
+ loopIconNode,
111
+ loopEmptyBlockNode,
112
+ loopInlineBlocks,
113
+ loopBlockNode,
114
+ loopBranch,
115
+ ...otherNodes,
116
+ ];
117
+ },
118
+ getLabels(transition) {
119
+ const currentTransform = transition.transform;
120
+ const { isVertical } = transition.entity;
121
+ return [
122
+ // 循环结束
123
+ {
124
+ type: FlowTransitionLabelEnum.TEXT_LABEL,
125
+ renderKey: FlowTextKey.LOOP_END_TEXT,
126
+ // 循环 label 垂直样式展示,而非 rotate 旋转文案
127
+ props: isVertical
128
+ ? undefined
129
+ : {
130
+ style: {
131
+ maxWidth: '20px',
132
+ lineHeight: '12px',
133
+ whiteSpace: 'pre-wrap',
134
+ },
135
+ },
136
+ offset: Point.move(currentTransform.outputPoint, isVertical ? { y: -26 } : { x: -26 }),
137
+ },
138
+ {
139
+ type: FlowTransitionLabelEnum.ADDER_LABEL,
140
+ offset: currentTransform.outputPoint,
141
+ },
142
+ ];
143
+ },
144
+ // 和前序节点对齐
145
+ getInputPoint(transform) {
146
+ const { isVertical } = transform.entity;
147
+ if (isVertical) {
148
+ return {
149
+ x: transform.pre?.outputPoint.x || transform.firstChild?.outputPoint.x || 0,
150
+ y: transform.bounds.top,
151
+ };
152
+ }
153
+ return {
154
+ x: transform.bounds.left,
155
+ y: transform.pre?.outputPoint.y || transform.firstChild?.outputPoint.y || 0,
156
+ };
157
+ },
158
+ getOutputPoint(transform) {
159
+ const { isVertical } = transform.entity;
160
+ if (isVertical) {
161
+ return {
162
+ x: transform.pre?.outputPoint.x || transform.firstChild?.outputPoint.x || 0,
163
+ y: transform.bounds.bottom,
164
+ };
165
+ }
166
+ return {
167
+ x: transform.bounds.right,
168
+ y: transform.pre?.outputPoint.y || transform.firstChild?.outputPoint.y || 0,
169
+ };
170
+ },
171
+
172
+ extendChildRegistries: [
173
+ {
174
+ type: FlowNodeBaseType.BLOCK_ICON,
175
+ meta: {
176
+ spacing: LoopSpacings.LOOP_BLOCK_ICON_SPACING,
177
+ },
178
+ },
179
+ LoopLeftEmptyBlockRegistry,
180
+ LoopEmptyBranchRegistry,
181
+ LoopRightEmptyBlockRegistry,
182
+ LoopInlineBlocksNodeRegistry,
183
+ ],
184
+
185
+ /**
186
+ * @depreacted
187
+ */
188
+ addChild(node, json, options = {}) {
189
+ const { index } = options;
190
+ const document = node.document;
191
+ return document.addNode({
192
+ ...json,
193
+ ...options,
194
+ parent: document.getNode(`$block$${node.id}`),
195
+ index: typeof index === 'number' ? index + 1 : undefined,
196
+ });
197
+ },
198
+ };