@plait/mind 0.2.0-next.7 → 0.2.0-next.9

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 (98) hide show
  1. package/constants/abstract-node.d.ts +4 -0
  2. package/constants/default.d.ts +1 -2
  3. package/constants/index.d.ts +4 -1
  4. package/constants/node-rule.d.ts +1 -0
  5. package/constants/node-style.d.ts +17 -0
  6. package/constants/node-topic-style.d.ts +4 -0
  7. package/draw/richtext.d.ts +4 -3
  8. package/esm2020/constants/abstract-node.mjs +5 -0
  9. package/esm2020/constants/default.mjs +2 -3
  10. package/esm2020/constants/index.mjs +5 -2
  11. package/esm2020/constants/node-rule.mjs +2 -0
  12. package/esm2020/constants/node-style.mjs +19 -0
  13. package/esm2020/constants/node-topic-style.mjs +5 -0
  14. package/esm2020/draw/abstract.mjs +4 -3
  15. package/esm2020/draw/indented-link.mjs +14 -14
  16. package/esm2020/draw/link/abstract-link.mjs +6 -4
  17. package/esm2020/draw/link/logic-link.mjs +7 -7
  18. package/esm2020/draw/link.mjs +6 -5
  19. package/esm2020/draw/richtext.mjs +7 -7
  20. package/esm2020/draw/shape.mjs +4 -4
  21. package/esm2020/drawer/quick-insert.drawer.mjs +11 -12
  22. package/esm2020/interfaces/abstract.mjs +1 -1
  23. package/esm2020/interfaces/element.mjs +6 -1
  24. package/esm2020/interfaces/node.mjs +1 -1
  25. package/esm2020/interfaces/options.mjs +2 -0
  26. package/esm2020/layout-option.mjs +5 -5
  27. package/esm2020/mind.component.mjs +2 -2
  28. package/esm2020/node.component.mjs +15 -13
  29. package/esm2020/plugins/emoji/emoji.drawer.mjs +3 -4
  30. package/esm2020/plugins/emoji/emoji.mjs +7 -3
  31. package/esm2020/plugins/emoji/index.mjs +1 -2
  32. package/esm2020/plugins/with-abstract.mjs +2 -2
  33. package/esm2020/plugins/with-dnd.mjs +12 -117
  34. package/esm2020/plugins/with-extend-mind.mjs +11 -0
  35. package/esm2020/plugins/with-mind.mjs +9 -7
  36. package/esm2020/public-api.mjs +2 -1
  37. package/esm2020/queries/get-available-sublayouts-by-element.mjs +4 -9
  38. package/esm2020/queries/get-branch-layouts.mjs +4 -4
  39. package/esm2020/queries/get-correct-layout-by-element.mjs +28 -31
  40. package/esm2020/queries/get-layout-by-element.mjs +10 -8
  41. package/esm2020/queries/index.mjs +1 -3
  42. package/esm2020/transforms/abstract-node.mjs +68 -0
  43. package/esm2020/transforms/index.mjs +6 -2
  44. package/esm2020/transforms/layout.mjs +3 -3
  45. package/esm2020/transforms/node.mjs +2 -2
  46. package/esm2020/utils/abstract/common.mjs +90 -70
  47. package/esm2020/utils/abstract/resize.mjs +3 -3
  48. package/esm2020/utils/clipboard.mjs +54 -14
  49. package/esm2020/utils/direction-corrector.mjs +11 -11
  50. package/esm2020/utils/dnd.mjs +118 -0
  51. package/esm2020/utils/draw-placeholder.mjs +5 -5
  52. package/esm2020/utils/drop-target-corrector.mjs +11 -10
  53. package/esm2020/utils/layout.mjs +1 -1
  54. package/esm2020/utils/mind.mjs +23 -58
  55. package/esm2020/utils/node-space.mjs +5 -5
  56. package/esm2020/utils/node-style/branch.mjs +33 -6
  57. package/esm2020/utils/node-style/node.mjs +6 -5
  58. package/esm2020/utils/path.mjs +4 -3
  59. package/esm2020/utils/shape.mjs +3 -3
  60. package/fesm2015/plait-mind.mjs +724 -602
  61. package/fesm2015/plait-mind.mjs.map +1 -1
  62. package/fesm2020/plait-mind.mjs +726 -600
  63. package/fesm2020/plait-mind.mjs.map +1 -1
  64. package/interfaces/abstract.d.ts +3 -0
  65. package/interfaces/element.d.ts +5 -2
  66. package/interfaces/options.d.ts +4 -0
  67. package/layout-option.d.ts +2 -1
  68. package/mind.component.d.ts +2 -2
  69. package/node.component.d.ts +5 -4
  70. package/package.json +1 -1
  71. package/plugins/emoji/emoji.d.ts +2 -1
  72. package/plugins/emoji/emoji.drawer.d.ts +3 -3
  73. package/plugins/emoji/index.d.ts +0 -1
  74. package/plugins/with-dnd.d.ts +0 -9
  75. package/plugins/with-extend-mind.d.ts +10 -0
  76. package/plugins/with-mind.d.ts +1 -1
  77. package/public-api.d.ts +1 -0
  78. package/queries/get-available-sublayouts-by-element.d.ts +2 -6
  79. package/queries/get-branch-layouts.d.ts +2 -1
  80. package/queries/get-correct-layout-by-element.d.ts +2 -1
  81. package/queries/index.d.ts +3 -4
  82. package/styles/styles.scss +0 -3
  83. package/transforms/abstract-node.d.ts +6 -0
  84. package/transforms/index.d.ts +3 -0
  85. package/utils/abstract/common.d.ts +6 -8
  86. package/utils/direction-corrector.d.ts +2 -1
  87. package/utils/dnd.d.ts +16 -0
  88. package/utils/drop-target-corrector.d.ts +2 -1
  89. package/utils/mind.d.ts +3 -3
  90. package/utils/node-space.d.ts +3 -2
  91. package/utils/node-style/branch.d.ts +3 -0
  92. package/utils/shape.d.ts +2 -3
  93. package/constants/node.d.ts +0 -17
  94. package/esm2020/constants/node.mjs +0 -19
  95. package/esm2020/plugins/emoji/with-mind-emoji.mjs +0 -8
  96. package/esm2020/queries/get-layout-parent-by-element.mjs +0 -17
  97. package/plugins/emoji/with-mind-emoji.d.ts +0 -8
  98. package/queries/get-layout-parent-by-element.d.ts +0 -8
@@ -1,8 +1,8 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { Component, ChangeDetectionStrategy, NgModule, Directive, Input } from '@angular/core';
3
3
  import * as i2 from '@plait/core';
4
- import { distanceBetweenPointAndRectangle, PlaitElement, PlaitBoard, PlaitNode, NODE_TO_PARENT, Path, ELEMENT_TO_COMPONENT, Transforms, idCreator, isNullOrUndefined, clearSelectedElement, addSelectedElement, drawRoundRectangle, getRectangleByElements, RectangleClient, getSelectedElements, createG, drawAbstractRoundRectangle, PlaitPluginElementComponent, PlaitPointerType, NODE_TO_INDEX, createText, IS_TEXT_EDITABLE, MERGING, transformPoint, toPoint, depthFirstRecursion, PlaitModule, distanceBetweenPointAndPoint, CLIP_BOARD_FORMAT_KEY, BOARD_TO_HOST, removeSelectedElement, PlaitHistoryBoard, hotkeys } from '@plait/core';
5
- import { AbstractNode, isChildOfAbstract, isIndentedLayout, getAbstractLayout, MindLayoutType, isStandardLayout, isTopLayout, isLeftLayout, isHorizontalLogicLayout, isVerticalLogicLayout, isBottomLayout, isRightLayout, isHorizontalLayout, getNonAbstractChildren, getCorrectStartEnd, ConnectingPosition, GlobalLayout } from '@plait/layouts';
4
+ import { distanceBetweenPointAndRectangle, PlaitBoard, PlaitNode, NODE_TO_PARENT, Path, ELEMENT_TO_COMPONENT, PlaitElement, Transforms, idCreator, isNullOrUndefined, clearSelectedElement, addSelectedElement, drawRoundRectangle, getRectangleByElements, RectangleClient, getSelectedElements, createG, drawAbstractRoundRectangle, PlaitPluginElementComponent, PlaitPointerType, NODE_TO_INDEX, createText, IS_TEXT_EDITABLE, MERGING, transformPoint, toPoint, depthFirstRecursion, PlaitModule, distanceBetweenPointAndPoint, CLIP_BOARD_FORMAT_KEY, BOARD_TO_HOST, removeSelectedElement, PlaitHistoryBoard, hotkeys } from '@plait/core';
5
+ import { MindLayoutType, AbstractNode, getAbstractLayout, isIndentedLayout, isStandardLayout, isHorizontalLogicLayout, isVerticalLogicLayout, isTopLayout, isLeftLayout, isBottomLayout, isRightLayout, isHorizontalLayout, getNonAbstractChildren, getCorrectStartEnd, ConnectingPosition, GlobalLayout } from '@plait/layouts';
6
6
  import { getSizeByText, ROOT_DEFAULT_HEIGHT, TEXT_DEFAULT_HEIGHT, drawRichtext, updateForeignObject, createForeignObject, updateRichText, setFullSelectionAndFocus, getRichtextContentSize, hasEditableTarget, RichtextModule } from '@plait/richtext';
7
7
  import { fromEvent, Subject, timer } from 'rxjs';
8
8
  import { take, takeUntil, filter, debounceTime } from 'rxjs/operators';
@@ -16,34 +16,44 @@ const ELEMENT_TO_NODE = new WeakMap();
16
16
 
17
17
  const BASE = 4;
18
18
  const PRIMARY_COLOR = '#6698FF';
19
- const MINDMAP_KEY = 'plait-mindmap';
20
- const MAX_RADIUS = BASE * 4;
21
19
  const TRANSPARENT = 'transparent';
22
20
  const GRAY_COLOR = '#AAAAAA';
23
21
  const STROKE_WIDTH = 3;
22
+ const BRANCH_WIDTH = 3;
24
23
  const EXTEND_OFFSET = 8;
25
24
  const EXTEND_RADIUS = 16;
26
25
  const QUICK_INSERT_CIRCLE_OFFSET = 9;
27
26
  const QUICK_INSERT_CIRCLE_COLOR = '#6698FF';
28
27
  const QUICK_INSERT_INNER_CROSS_COLOR = 'white';
29
28
 
29
+ const DefaultAbstractNodeStyle = {
30
+ strokeColor: GRAY_COLOR,
31
+ strokeWidth: 2,
32
+ branchColor: GRAY_COLOR,
33
+ branchWidth: 2,
34
+ fill: '#FFFFFF'
35
+ };
36
+ const DefaultNodeStyle = {
37
+ strokeWidth: 3,
38
+ branchWidth: 3,
39
+ fill: '#FFFFFF'
40
+ };
41
+ const DefaultRootStyle = {
42
+ fill: '#F5F5F5',
43
+ strokeColor: '#F5F5F5',
44
+ };
45
+ const BRANCH_COLORS = ['#A287E1', '#6F81DB', '#6EC4C4', '#DFB85D', '#B1C774', '#77C386', '#C28976', '#E48484', '#E482D4', '#69B1E4'];
46
+
30
47
  const TOPIC_COLOR = '#333';
31
48
  const TOPIC_FONT_SIZE = 14;
32
- const NODE_FILL = '#FFFFFF';
33
- const ROOT_NODE_FILL = '#F5F5F5';
34
- const ROOT_NODE_STROKE = '#F5F5F5';
35
49
  const ROOT_TOPIC_FONT_SIZE = 18;
50
+ const TOPIC_DEFAULT_MAX_WORD_COUNT = 34;
51
+
36
52
  const NODE_MIN_WIDTH = 18;
37
- const COLORS = ['#A287E1', '#6F81DB', '#6EC4C4', '#DFB85D', '#B1C774', '#77C386', '#C28976', '#E48484', '#E482D4', '#69B1E4'];
38
- var MindNodeShape;
39
- (function (MindNodeShape) {
40
- MindNodeShape["roundRectangle"] = "round-rectangle";
41
- MindNodeShape["underline"] = "underline";
42
- })(MindNodeShape || (MindNodeShape = {}));
43
- const ABSTRACT_HANDLE_COLOR = '#6698FF80'; //PRIMARY_COLOR 50% 透明度
53
+
54
+ const ABSTRACT_HANDLE_COLOR = '#6698FF80'; //primary color 50% opacity
44
55
  const ABSTRACT_INCLUDED_OUTLINE_OFFSET = 3.5;
45
56
  const ABSTRACT_HANDLE_LENGTH = 10;
46
- const TOPIC_DEFAULT_MAX_WORD_COUNT = 34;
47
57
  const ABSTRACT_HANDLE_MASK_WIDTH = 8;
48
58
 
49
59
  function getRectangleByNode(node) {
@@ -74,35 +84,35 @@ function hitMindElement(board, point, element) {
74
84
  * 2. correct layout by incorrect layout direction
75
85
  * @param element
76
86
  */
77
- const getCorrectLayoutByElement = (element) => {
78
- var _a;
79
- const { root } = findUpElement(element);
80
- const rootLayout = root.layout || getDefaultLayout();
81
- let correctRootLayout = rootLayout;
82
- if (element.isRoot) {
83
- return correctRootLayout;
87
+ const getCorrectLayoutByElement = (board, element) => {
88
+ const ancestors = MindElement.getAncestors(board, element);
89
+ ancestors.unshift(element);
90
+ const root = ancestors[ancestors.length - 1];
91
+ let rootLayout = getRootLayout(root);
92
+ if (PlaitMind.isMind(element)) {
93
+ return rootLayout;
84
94
  }
85
- const component = PlaitElement.getComponent(element);
86
- let layout = element.layout;
87
- let parentComponent = null;
88
- let parent = component.parent.origin;
89
- while (!layout && parent) {
90
- parentComponent = PlaitElement.getComponent(parent);
91
- layout = parentComponent.node.origin.layout;
92
- parent = (_a = parentComponent.parent) === null || _a === void 0 ? void 0 : _a.origin;
93
- }
94
- if ((AbstractNode.isAbstract(element) || isChildOfAbstract(MindElement.getNode(element))) &&
95
- isIndentedLayout(layout)) {
96
- return getAbstractLayout(layout);
97
- }
98
- // handle root standard
95
+ const node = MindElement.getNode(element);
96
+ let correctRootLayout = rootLayout;
99
97
  if (rootLayout === MindLayoutType.standard) {
100
- correctRootLayout = (component === null || component === void 0 ? void 0 : component.node.left) ? MindLayoutType.left : MindLayoutType.right;
98
+ correctRootLayout = node.left ? MindLayoutType.left : MindLayoutType.right;
101
99
  }
102
- if (parentComponent && parentComponent.node.origin.isRoot) {
100
+ let layout = null;
101
+ const elementWithLayout = ancestors.find(value => value.layout || AbstractNode.isAbstract(value));
102
+ if (elementWithLayout) {
103
+ if (AbstractNode.isAbstract(elementWithLayout)) {
104
+ const parent = MindElement.getParent(elementWithLayout);
105
+ const parentLayout = getCorrectLayoutByElement(board, parent);
106
+ layout = getAbstractLayout(parentLayout);
107
+ }
108
+ else {
109
+ layout = elementWithLayout === null || elementWithLayout === void 0 ? void 0 : elementWithLayout.layout;
110
+ }
111
+ }
112
+ if (layout === MindLayoutType.standard || !layout) {
103
113
  return correctRootLayout;
104
114
  }
105
- if (layout) {
115
+ else {
106
116
  const incorrectDirection = getInCorrectLayoutDirection(correctRootLayout, layout);
107
117
  if (incorrectDirection) {
108
118
  return correctLayoutByDirection(layout, incorrectDirection);
@@ -111,16 +121,13 @@ const getCorrectLayoutByElement = (element) => {
111
121
  return layout;
112
122
  }
113
123
  }
114
- else {
115
- return correctRootLayout;
116
- }
117
124
  };
118
125
 
119
- const getBranchLayouts = (element) => {
126
+ const getBranchLayouts = (board, element) => {
120
127
  const layouts = [];
121
128
  if (element.layout) {
122
- //getCorrectLayoutByElement含有递归操作,getBranchMindmapLayouts本身也有递归操作,有待优化
123
- layouts.unshift(getCorrectLayoutByElement(element));
129
+ // TODO: getCorrectLayoutByElement 含有递归操作,getBranchLayouts 本身也有递归操作,有待优化
130
+ layouts.unshift(getCorrectLayoutByElement(board, element));
124
131
  }
125
132
  let parent = findParentElement(element);
126
133
  while (parent) {
@@ -132,15 +139,10 @@ const getBranchLayouts = (element) => {
132
139
  return layouts;
133
140
  };
134
141
 
135
- /**
136
- * get available sub layouts by element
137
- * @param element
138
- * @returns MindLayoutType[]
139
- */
140
- const getAvailableSubLayoutsByElement = (element) => {
142
+ const getAvailableSubLayoutsByElement = (board, element) => {
141
143
  const parentElement = findParentElement(element);
142
144
  if (parentElement) {
143
- const branchLayouts = getBranchLayouts(parentElement);
145
+ const branchLayouts = getBranchLayouts(board, parentElement);
144
146
  if (branchLayouts[0] === MindLayoutType.standard) {
145
147
  const node = MindElement.getNode(element);
146
148
  branchLayouts[0] = node.left ? MindLayoutType.left : MindLayoutType.right;
@@ -156,20 +158,107 @@ const getAvailableSubLayoutsByElement = (element) => {
156
158
  return undefined;
157
159
  };
158
160
 
159
- /**
160
- * 获取父节点布局类型
161
- * @param element
162
- * @returns MindLayoutType
163
- */
164
- const getLayoutParentByElement = (element) => {
165
- let parent = findParentElement(element);
166
- while (parent) {
167
- if (parent.layout) {
168
- return parent.layout;
161
+ const getBranchDirectionsByLayouts = (branchLayouts) => {
162
+ const branchDirections = [];
163
+ branchLayouts.forEach(l => {
164
+ const directions = LayoutDirectionsMap[l];
165
+ directions.forEach(d => {
166
+ if (!branchDirections.includes(d) && !branchDirections.includes(getLayoutReverseDirection(d))) {
167
+ branchDirections.push(d);
168
+ }
169
+ });
170
+ });
171
+ return branchDirections;
172
+ };
173
+ const isCorrectLayout = (root, layout) => {
174
+ const rootLayout = root.layout || getDefaultLayout();
175
+ return !getInCorrectLayoutDirection(rootLayout, layout);
176
+ };
177
+ const isMixedLayout = (parentLayout, layout) => {
178
+ return (!isIndentedLayout(parentLayout) && isIndentedLayout(layout)) || (isIndentedLayout(parentLayout) && !isIndentedLayout(layout));
179
+ };
180
+ const getInCorrectLayoutDirection = (rootLayout, layout) => {
181
+ const directions = LayoutDirectionsMap[rootLayout];
182
+ const subLayoutDirections = LayoutDirectionsMap[layout];
183
+ if (!subLayoutDirections) {
184
+ throw new Error(`unexpected layout: ${layout} on correct layout`);
185
+ }
186
+ return subLayoutDirections.find(d => directions.includes(getLayoutReverseDirection(d)));
187
+ };
188
+ const correctLayoutByDirection = (layout, direction) => {
189
+ const isHorizontal = direction === LayoutDirection.left || direction === LayoutDirection.right ? true : false;
190
+ let inverseDirectionLayout = MindLayoutType.standard;
191
+ switch (layout) {
192
+ case MindLayoutType.left:
193
+ inverseDirectionLayout = MindLayoutType.right;
194
+ break;
195
+ case MindLayoutType.right:
196
+ inverseDirectionLayout = MindLayoutType.left;
197
+ break;
198
+ case MindLayoutType.downward:
199
+ inverseDirectionLayout = MindLayoutType.upward;
200
+ break;
201
+ case MindLayoutType.upward:
202
+ inverseDirectionLayout = MindLayoutType.downward;
203
+ break;
204
+ case MindLayoutType.rightBottomIndented:
205
+ inverseDirectionLayout = isHorizontal ? MindLayoutType.leftBottomIndented : MindLayoutType.rightTopIndented;
206
+ break;
207
+ case MindLayoutType.leftBottomIndented:
208
+ inverseDirectionLayout = isHorizontal ? MindLayoutType.rightBottomIndented : MindLayoutType.leftTopIndented;
209
+ break;
210
+ case MindLayoutType.rightTopIndented:
211
+ inverseDirectionLayout = isHorizontal ? MindLayoutType.leftTopIndented : MindLayoutType.rightBottomIndented;
212
+ break;
213
+ case MindLayoutType.leftTopIndented:
214
+ inverseDirectionLayout = isHorizontal ? MindLayoutType.rightTopIndented : MindLayoutType.leftBottomIndented;
215
+ break;
216
+ }
217
+ return inverseDirectionLayout;
218
+ };
219
+ const getLayoutDirection$1 = (root) => {
220
+ const layout = root.layout || getDefaultLayout();
221
+ return LayoutDirectionsMap[layout];
222
+ };
223
+ const getDefaultLayout = () => {
224
+ return MindLayoutType.standard;
225
+ };
226
+ const getAvailableSubLayoutsByLayoutDirections = (directions) => {
227
+ const result = [];
228
+ const reverseDirections = directions.map(getLayoutReverseDirection);
229
+ for (const key in MindLayoutType) {
230
+ const layout = MindLayoutType[key];
231
+ const layoutDirections = LayoutDirectionsMap[layout];
232
+ if (layoutDirections) {
233
+ const hasSameDirection = layoutDirections.some(d => directions.includes(d));
234
+ const hasReverseDirection = layoutDirections.some(r => reverseDirections.includes(r));
235
+ if (hasSameDirection && !hasReverseDirection) {
236
+ result.push(layout);
237
+ }
169
238
  }
170
- parent = findParentElement(parent);
171
239
  }
172
- return getDefaultLayout();
240
+ return result;
241
+ };
242
+ const getLayoutReverseDirection = (layoutDirection) => {
243
+ let reverseDirection = LayoutDirection.right;
244
+ switch (layoutDirection) {
245
+ case LayoutDirection.top:
246
+ reverseDirection = LayoutDirection.bottom;
247
+ break;
248
+ case LayoutDirection.bottom:
249
+ reverseDirection = LayoutDirection.top;
250
+ break;
251
+ case LayoutDirection.right:
252
+ reverseDirection = LayoutDirection.left;
253
+ break;
254
+ case LayoutDirection.left:
255
+ reverseDirection = LayoutDirection.right;
256
+ break;
257
+ }
258
+ return reverseDirection;
259
+ };
260
+ const getRootLayout = (root) => {
261
+ return root.layout || getDefaultLayout();
173
262
  };
174
263
 
175
264
  const getLayoutByElement = (element) => {
@@ -177,17 +266,18 @@ const getLayoutByElement = (element) => {
177
266
  if (layout) {
178
267
  return layout;
179
268
  }
180
- if (AbstractNode.isAbstract(element) ||
181
- (isChildOfAbstract(MindElement.getNode(element)) && isIndentedLayout(layout))) {
182
- const parentLayout = getLayoutParentByElement(element);
183
- return getAbstractLayout(parentLayout);
269
+ const parent = MindElement.getParent(element);
270
+ if (AbstractNode.isAbstract(element)) {
271
+ return getAbstractLayout(getLayoutByElement(parent));
272
+ }
273
+ if (parent) {
274
+ return getLayoutByElement(parent);
184
275
  }
185
- return getLayoutParentByElement(element);
276
+ return getDefaultLayout();
186
277
  };
187
278
 
188
279
  const MindQueries = {
189
280
  getAvailableSubLayoutsByElement,
190
- getLayoutParentByElement,
191
281
  getBranchLayouts,
192
282
  getLayoutByElement,
193
283
  getCorrectLayoutByElement
@@ -258,6 +348,11 @@ const MindElement = {
258
348
  return element.data.emojis;
259
349
  }
260
350
  };
351
+ var MindElementShape;
352
+ (function (MindElementShape) {
353
+ MindElementShape["roundRectangle"] = "round-rectangle";
354
+ MindElementShape["underline"] = "underline";
355
+ })(MindElementShape || (MindElementShape = {}));
261
356
 
262
357
  const MindNode = {
263
358
  get(root, path) {
@@ -312,109 +407,6 @@ var AbstractResizeState;
312
407
  AbstractResizeState["end"] = "end";
313
408
  })(AbstractResizeState || (AbstractResizeState = {}));
314
409
 
315
- const getBranchDirectionsByLayouts = (branchLayouts) => {
316
- const branchDirections = [];
317
- branchLayouts.forEach(l => {
318
- const directions = LayoutDirectionsMap[l];
319
- directions.forEach(d => {
320
- if (!branchDirections.includes(d) && !branchDirections.includes(getLayoutReverseDirection(d))) {
321
- branchDirections.push(d);
322
- }
323
- });
324
- });
325
- return branchDirections;
326
- };
327
- const isCorrectLayout = (root, layout) => {
328
- const rootLayout = root.layout || getDefaultLayout();
329
- return !getInCorrectLayoutDirection(rootLayout, layout);
330
- };
331
- const isMixedLayout = (parentLayout, layout) => {
332
- return (!isIndentedLayout(parentLayout) && isIndentedLayout(layout)) || (isIndentedLayout(parentLayout) && !isIndentedLayout(layout));
333
- };
334
- const getInCorrectLayoutDirection = (rootLayout, layout) => {
335
- const directions = LayoutDirectionsMap[rootLayout];
336
- const subLayoutDirections = LayoutDirectionsMap[layout];
337
- if (!subLayoutDirections) {
338
- throw new Error(`unexpected layout: ${layout} on correct layout`);
339
- }
340
- return subLayoutDirections.find(d => directions.includes(getLayoutReverseDirection(d)));
341
- };
342
- const correctLayoutByDirection = (layout, direction) => {
343
- const isHorizontal = direction === LayoutDirection.left || direction === LayoutDirection.right ? true : false;
344
- let inverseDirectionLayout = MindLayoutType.standard;
345
- switch (layout) {
346
- case MindLayoutType.left:
347
- inverseDirectionLayout = MindLayoutType.right;
348
- break;
349
- case MindLayoutType.right:
350
- inverseDirectionLayout = MindLayoutType.left;
351
- break;
352
- case MindLayoutType.downward:
353
- inverseDirectionLayout = MindLayoutType.upward;
354
- break;
355
- case MindLayoutType.upward:
356
- inverseDirectionLayout = MindLayoutType.downward;
357
- break;
358
- case MindLayoutType.rightBottomIndented:
359
- inverseDirectionLayout = isHorizontal ? MindLayoutType.leftBottomIndented : MindLayoutType.rightTopIndented;
360
- break;
361
- case MindLayoutType.leftBottomIndented:
362
- inverseDirectionLayout = isHorizontal ? MindLayoutType.rightBottomIndented : MindLayoutType.leftTopIndented;
363
- break;
364
- case MindLayoutType.rightTopIndented:
365
- inverseDirectionLayout = isHorizontal ? MindLayoutType.leftTopIndented : MindLayoutType.rightBottomIndented;
366
- break;
367
- case MindLayoutType.leftTopIndented:
368
- inverseDirectionLayout = isHorizontal ? MindLayoutType.rightTopIndented : MindLayoutType.leftBottomIndented;
369
- break;
370
- }
371
- return inverseDirectionLayout;
372
- };
373
- const getLayoutDirection$1 = (root) => {
374
- const layout = root.layout || getDefaultLayout();
375
- return LayoutDirectionsMap[layout];
376
- };
377
- const getDefaultLayout = () => {
378
- return MindLayoutType.standard;
379
- };
380
- const getAvailableSubLayoutsByLayoutDirections = (directions) => {
381
- const result = [];
382
- const reverseDirections = directions.map(getLayoutReverseDirection);
383
- for (const key in MindLayoutType) {
384
- const layout = MindLayoutType[key];
385
- const layoutDirections = LayoutDirectionsMap[layout];
386
- if (layoutDirections) {
387
- const hasSameDirection = layoutDirections.some(d => directions.includes(d));
388
- const hasReverseDirection = layoutDirections.some(r => reverseDirections.includes(r));
389
- if (hasSameDirection && !hasReverseDirection) {
390
- result.push(layout);
391
- }
392
- }
393
- }
394
- return result;
395
- };
396
- const getLayoutReverseDirection = (layoutDirection) => {
397
- let reverseDirection = LayoutDirection.right;
398
- switch (layoutDirection) {
399
- case LayoutDirection.top:
400
- reverseDirection = LayoutDirection.bottom;
401
- break;
402
- case LayoutDirection.bottom:
403
- reverseDirection = LayoutDirection.top;
404
- break;
405
- case LayoutDirection.right:
406
- reverseDirection = LayoutDirection.left;
407
- break;
408
- case LayoutDirection.left:
409
- reverseDirection = LayoutDirection.right;
410
- break;
411
- }
412
- return reverseDirection;
413
- };
414
- const getRootLayout = (root) => {
415
- return root.layout || getDefaultLayout();
416
- };
417
-
418
410
  function enterNodeEditing(element) {
419
411
  const component = ELEMENT_TO_COMPONENT.get(element);
420
412
  component.startEditText(false, false);
@@ -434,22 +426,146 @@ const separateChildren = (parentElement) => {
434
426
  leftChildren.push(child);
435
427
  continue;
436
428
  }
437
- if (i < rightNodeCount) {
438
- rightChildren.push(child);
429
+ if (i < rightNodeCount) {
430
+ rightChildren.push(child);
431
+ }
432
+ else {
433
+ leftChildren.push(child);
434
+ }
435
+ }
436
+ return { leftChildren, rightChildren };
437
+ };
438
+ const isSetAbstract = (element) => {
439
+ const parent = MindElement.getParent(element);
440
+ return !!getCorrespondingAbstract(parent, element);
441
+ };
442
+ const canSetAbstract = (element) => {
443
+ return !PlaitElement.isRootElement(element) && !AbstractNode.isAbstract(element) && !isSetAbstract(element);
444
+ };
445
+ const getCorrespondingAbstract = (parent, element) => {
446
+ if (!parent)
447
+ return undefined;
448
+ const elementIndex = parent.children.indexOf(element);
449
+ return parent.children.find(child => {
450
+ return AbstractNode.isAbstract(child) && elementIndex >= child.start && elementIndex <= child.end;
451
+ });
452
+ };
453
+ const getBehindAbstracts = (parent, element) => {
454
+ const index = parent.children.indexOf(element);
455
+ return parent.children.filter(child => AbstractNode.isAbstract(child) && child.start > index);
456
+ };
457
+ const getOverallAbstracts = (board, elements) => {
458
+ const overallAbstracts = [];
459
+ elements
460
+ .filter(value => !AbstractNode.isAbstract(value) && !PlaitMind.isMind(value))
461
+ .forEach(value => {
462
+ const parent = MindElement.getParent(value);
463
+ const abstract = getCorrespondingAbstract(parent, value);
464
+ if (abstract && overallAbstracts.indexOf(abstract) === -1) {
465
+ const { start, end } = abstract;
466
+ const parent = MindElement.getParent(value);
467
+ const isOverall = parent.children.slice(start, end + 1).every(includedElement => elements.indexOf(includedElement) > -1);
468
+ if (isOverall) {
469
+ overallAbstracts.push(abstract);
470
+ }
471
+ }
472
+ });
473
+ return overallAbstracts;
474
+ };
475
+ const insertElementHandleAbstract = (board, path,
476
+ //由此区分拖拽和新增到概要概括最后一个节点
477
+ isExtendPreviousNode = true, abstractRefs = new Map()) => {
478
+ const parent = PlaitNode.parent(board, path);
479
+ const hasPreviousNode = path[path.length - 1] !== 0;
480
+ let behindAbstracts;
481
+ if (!hasPreviousNode) {
482
+ behindAbstracts = parent.children.filter(child => AbstractNode.isAbstract(child));
483
+ }
484
+ else {
485
+ const selectedElement = PlaitNode.get(board, Path.previous(path));
486
+ behindAbstracts = getBehindAbstracts(parent, selectedElement);
487
+ }
488
+ if (behindAbstracts.length) {
489
+ behindAbstracts.forEach(abstract => {
490
+ let newProperties = abstractRefs.get(abstract);
491
+ if (!newProperties) {
492
+ newProperties = { start: 0, end: 0 };
493
+ abstractRefs.set(abstract, newProperties);
494
+ }
495
+ newProperties.start = newProperties.start + 1;
496
+ newProperties.end = newProperties.end + 1;
497
+ });
498
+ }
499
+ if (!hasPreviousNode) {
500
+ return abstractRefs;
501
+ }
502
+ const selectedElement = PlaitNode.get(board, Path.previous(path));
503
+ const correspondingAbstract = getCorrespondingAbstract(parent, selectedElement);
504
+ const isDragToLast = !isExtendPreviousNode && correspondingAbstract && correspondingAbstract.end === path[path.length - 1] - 1;
505
+ if (correspondingAbstract && !isDragToLast) {
506
+ let newProperties = abstractRefs.get(correspondingAbstract);
507
+ if (!newProperties) {
508
+ newProperties = { start: 0, end: 0 };
509
+ abstractRefs.set(correspondingAbstract, newProperties);
510
+ }
511
+ newProperties.end = newProperties.end + 1;
512
+ }
513
+ return abstractRefs;
514
+ };
515
+ const deleteElementHandleAbstract = (board, deletableElements, abstractRefs = new Map()) => {
516
+ deletableElements.forEach(node => {
517
+ if (!PlaitMind.isMind(node)) {
518
+ const parent = PlaitNode.parent(board, PlaitBoard.findPath(board, node));
519
+ const behindAbstracts = getBehindAbstracts(parent, node).filter(abstract => !deletableElements.includes(abstract));
520
+ if (behindAbstracts.length) {
521
+ behindAbstracts.forEach(abstract => {
522
+ let newProperties = abstractRefs.get(abstract);
523
+ if (!newProperties) {
524
+ newProperties = { start: 0, end: 0 };
525
+ abstractRefs.set(abstract, newProperties);
526
+ }
527
+ newProperties.start = newProperties.start - 1;
528
+ newProperties.end = newProperties.end - 1;
529
+ });
530
+ }
531
+ const correspondingAbstract = getCorrespondingAbstract(parent, node);
532
+ if (correspondingAbstract && !deletableElements.includes(correspondingAbstract)) {
533
+ let newProperties = abstractRefs.get(correspondingAbstract);
534
+ if (!newProperties) {
535
+ newProperties = { start: 0, end: 0 };
536
+ abstractRefs.set(correspondingAbstract, newProperties);
537
+ }
538
+ newProperties.end = newProperties.end - 1;
539
+ }
540
+ }
541
+ });
542
+ return abstractRefs;
543
+ };
544
+
545
+ const setAbstractsByRefs = (board, abstractRefs) => {
546
+ abstractRefs.forEach((newProperty, element) => {
547
+ const start = element.start + newProperty.start;
548
+ const end = element.end + newProperty.end;
549
+ const path = PlaitBoard.findPath(board, element);
550
+ if (start > end) {
551
+ Transforms.removeNode(board, path);
439
552
  }
440
553
  else {
441
- leftChildren.push(child);
554
+ Transforms.setNode(board, { start, end }, path);
442
555
  }
443
- }
444
- return { leftChildren, rightChildren };
445
- };
446
- const isSetAbstract = (element) => {
447
- return !!getCorrespondingAbstract(element);
556
+ });
448
557
  };
449
- const canSetAbstract = (element) => {
450
- return !PlaitElement.isRootElement(element) && !AbstractNode.isAbstract(element) && !isSetAbstract(element);
558
+ const setAbstractByStandardLayout = (board, element) => {
559
+ const rightNodeCount = element.rightNodeCount;
560
+ const abstract = element.children.find(child => {
561
+ return AbstractNode.isAbstract(child) && child.end >= rightNodeCount && child.start < rightNodeCount;
562
+ });
563
+ if (abstract) {
564
+ const path = PlaitBoard.findPath(board, abstract);
565
+ Transforms.setNode(board, { end: rightNodeCount - 1 }, path);
566
+ }
451
567
  };
452
- const setAbstract = (board, elements) => {
568
+ const insertAbstract = (board, elements) => {
453
569
  let elementGroup = filterChildElement(elements);
454
570
  const { parentElements, abstractIncludedGroups } = divideElementByParent(elementGroup);
455
571
  abstractIncludedGroups.forEach((group, index) => {
@@ -479,52 +595,109 @@ const setAbstractByElements = (board, groupParent, group) => {
479
595
  };
480
596
  const insertAbstractNode = (board, path, start, end) => {
481
597
  const mindElement = createMindElement('概要', 28, 20, {
482
- strokeColor: GRAY_COLOR,
483
- branchColor: GRAY_COLOR
598
+ strokeColor: DefaultAbstractNodeStyle.strokeColor,
599
+ strokeWidth: DefaultAbstractNodeStyle.branchWidth,
600
+ branchColor: DefaultAbstractNodeStyle.branchColor,
601
+ branchWidth: DefaultAbstractNodeStyle.branchWidth
484
602
  });
485
603
  mindElement.start = start;
486
604
  mindElement.end = end;
487
605
  Transforms.insertNode(board, mindElement, path);
488
606
  };
489
- const handleAbstractIncluded = (board, element) => {
490
- const rightNodeCount = element.rightNodeCount;
491
- const abstract = element.children.find(child => {
492
- return AbstractNode.isAbstract(child) && child.end >= rightNodeCount && child.start < rightNodeCount;
493
- });
494
- if (abstract) {
495
- const path = PlaitBoard.findPath(board, abstract);
496
- Transforms.setNode(board, { end: rightNodeCount - 1 }, path);
607
+
608
+ const setLayout = (board, layout, path) => {
609
+ correctLogicLayoutNode(board, layout, path);
610
+ const element = PlaitNode.get(board, path);
611
+ if (PlaitMind.isMind(element) && isStandardLayout(layout)) {
612
+ MindTransforms.setAbstractByStandardLayout(board, element);
497
613
  }
614
+ Transforms.setNode(board, { layout }, path);
498
615
  };
499
- const getCorrespondingAbstract = (element) => {
500
- const parent = MindElement.getParent(element);
501
- if (!parent)
502
- return undefined;
503
- const elementIndex = parent.children.indexOf(element);
504
- return parent.children.find(child => {
505
- return AbstractNode.isAbstract(child) && elementIndex >= child.start && elementIndex <= child.end;
506
- });
507
- };
508
- const getBehindAbstracts = (element) => {
509
- const parent = MindElement.getParent(element);
510
- const index = parent.children.indexOf(element);
511
- return parent.children.filter(child => AbstractNode.isAbstract(child) && child.start > index);
616
+ const correctLogicLayoutNode = (board, layout, path) => {
617
+ var _a;
618
+ const node = PlaitNode.get(board, path);
619
+ if (node && layout) {
620
+ (_a = node.children) === null || _a === void 0 ? void 0 : _a.forEach((value, index) => {
621
+ var _a;
622
+ if (value.layout) {
623
+ if ((isHorizontalLogicLayout(layout) && isVerticalLogicLayout(value.layout)) ||
624
+ (isVerticalLogicLayout(layout) && isHorizontalLogicLayout(value.layout))) {
625
+ Transforms.setNode(board, { layout: null }, [...path, index]);
626
+ }
627
+ if ((_a = value.children) === null || _a === void 0 ? void 0 : _a.length) {
628
+ correctLogicLayoutNode(board, layout, [...path, index]);
629
+ }
630
+ }
631
+ });
632
+ }
512
633
  };
513
- const insertSiblingElementHandleAbstract = (board, selectedElement) => {
514
- const abstract = getCorrespondingAbstract(selectedElement);
515
- if (abstract) {
516
- PlaitBoard.findPath(board, abstract);
517
- Transforms.setNode(board, { end: abstract.end + 1 }, PlaitBoard.findPath(board, abstract));
634
+
635
+ const setTopic = (board, element, topic, width, height) => {
636
+ const newElement = {
637
+ data: { topic },
638
+ width: width < NODE_MIN_WIDTH * board.viewport.zoom ? NODE_MIN_WIDTH : width / board.viewport.zoom,
639
+ height: height / board.viewport.zoom
640
+ };
641
+ if (MindElement.hasEmojis(element)) {
642
+ newElement.data.emojis = element.data.emojis;
518
643
  }
519
- const abstracts = getBehindAbstracts(selectedElement);
520
- if (abstracts.length) {
521
- moveAbstractPosition(board, abstracts, 1);
644
+ const path = PlaitBoard.findPath(board, element);
645
+ Transforms.setNode(board, newElement, path);
646
+ };
647
+ const setTopicSize = (board, element, width, height) => {
648
+ const newElement = {
649
+ width: width < NODE_MIN_WIDTH * board.viewport.zoom ? NODE_MIN_WIDTH : width / board.viewport.zoom,
650
+ height: height / board.viewport.zoom
651
+ };
652
+ const path = PlaitBoard.findPath(board, element);
653
+ Transforms.setNode(board, newElement, path);
654
+ };
655
+ const addEmoji = (board, element, emojiItem) => {
656
+ const emojis = element.data.emojis || [];
657
+ const newEmojis = [...emojis];
658
+ newEmojis.push(emojiItem);
659
+ const newElement = {
660
+ data: { topic: element.data.topic, emojis: newEmojis }
661
+ };
662
+ const path = PlaitBoard.findPath(board, element);
663
+ Transforms.setNode(board, newElement, path);
664
+ };
665
+ const removeEmoji = (board, element, emojiItem) => {
666
+ const emojis = element.data.emojis.filter(value => value !== emojiItem);
667
+ const newElement = {
668
+ data: { topic: element.data.topic }
669
+ };
670
+ if (emojis.length > 0) {
671
+ newElement.data.emojis = emojis;
522
672
  }
673
+ const path = PlaitBoard.findPath(board, element);
674
+ Transforms.setNode(board, newElement, path);
523
675
  };
524
- const moveAbstractPosition = (board, abstracts, step) => {
525
- abstracts.forEach(abstract => {
526
- Transforms.setNode(board, { start: abstract.start + step, end: abstract.end + step }, PlaitBoard.findPath(board, abstract));
676
+ const replaceEmoji = (board, element, oldEmoji, newEmoji) => {
677
+ const newElement = {
678
+ data: { topic: element.data.topic }
679
+ };
680
+ const newEmojis = element.data.emojis.map(value => {
681
+ if (value === oldEmoji) {
682
+ return newEmoji;
683
+ }
684
+ return value;
527
685
  });
686
+ newElement.data.emojis = newEmojis;
687
+ const path = PlaitBoard.findPath(board, element);
688
+ Transforms.setNode(board, newElement, path);
689
+ };
690
+
691
+ const MindTransforms = {
692
+ setLayout,
693
+ setTopic,
694
+ setTopicSize,
695
+ addEmoji,
696
+ removeEmoji,
697
+ replaceEmoji,
698
+ insertAbstract,
699
+ setAbstractsByRefs,
700
+ setAbstractByStandardLayout
528
701
  };
529
702
 
530
703
  function findParentElement(element) {
@@ -659,13 +832,13 @@ const shouldChangeRightNodeCount = (selectedElement) => {
659
832
  return false;
660
833
  };
661
834
  const createDefaultMindMapElement = (point, rightNodeCount, layout) => {
662
- const root = createMindElement('思维导图', 72, ROOT_DEFAULT_HEIGHT, { shape: MindNodeShape.roundRectangle, layout });
835
+ const root = createMindElement('思维导图', 72, ROOT_DEFAULT_HEIGHT, { shape: MindElementShape.roundRectangle, layout });
663
836
  root.rightNodeCount = rightNodeCount;
664
837
  root.isRoot = true;
665
838
  root.type = 'mindmap';
666
839
  root.points = [point];
667
840
  const children = [1, 1, 1].map(() => {
668
- return createMindElement('新建节点', 56, TEXT_DEFAULT_HEIGHT, { shape: MindNodeShape.roundRectangle });
841
+ return createMindElement('新建节点', 56, TEXT_DEFAULT_HEIGHT, { shape: MindElementShape.roundRectangle });
669
842
  });
670
843
  root.children = children;
671
844
  return root;
@@ -702,11 +875,14 @@ const createMindElement = (text, width, height, options) => {
702
875
  if (options.branchColor) {
703
876
  newElement.branchColor = options.branchColor;
704
877
  }
878
+ if (!isNullOrUndefined(options.branchWidth)) {
879
+ newElement.branchWidth = options.branchWidth;
880
+ }
705
881
  return newElement;
706
882
  };
707
883
  // layoutLevel 用来表示插入兄弟节点还是子节点
708
884
  const insertMindElement = (board, inheritNode, path) => {
709
- let fill, strokeColor, strokeWidth, shape = MindNodeShape.roundRectangle;
885
+ let fill, strokeColor, strokeWidth, shape = MindElementShape.roundRectangle;
710
886
  if (!inheritNode.isRoot) {
711
887
  fill = inheritNode.fill;
712
888
  strokeColor = inheritNode.strokeColor;
@@ -729,63 +905,23 @@ const findLastChild = (child) => {
729
905
  return result;
730
906
  };
731
907
  const deleteSelectedELements = (board, selectedElements) => {
732
- //翻转,从下到上修改,防止找不到 path
733
908
  const deletableElements = filterChildElement(selectedElements).reverse();
734
- const relativeAbstracts = [];
735
- const accumulativeProperties = new WeakMap();
736
- deletableElements.forEach(node => {
737
- if (!PlaitMind.isMind(node)) {
738
- const behindAbstracts = getBehindAbstracts(node).filter(abstract => !deletableElements.includes(abstract));
739
- if (behindAbstracts.length) {
740
- behindAbstracts.forEach(abstract => {
741
- let newProperties = accumulativeProperties.get(abstract);
742
- if (!newProperties) {
743
- newProperties = { start: abstract.start, end: abstract.end };
744
- accumulativeProperties.set(abstract, newProperties);
745
- relativeAbstracts.push(abstract);
746
- }
747
- newProperties.start = newProperties.start - 1;
748
- newProperties.end = newProperties.end - 1;
749
- });
750
- }
751
- const correspondingAbstract = getCorrespondingAbstract(node);
752
- if (correspondingAbstract && !deletableElements.includes(correspondingAbstract)) {
753
- let newProperties = accumulativeProperties.get(correspondingAbstract);
754
- if (!newProperties) {
755
- newProperties = { start: correspondingAbstract.start, end: correspondingAbstract.end };
756
- accumulativeProperties.set(correspondingAbstract, newProperties);
757
- relativeAbstracts.push(correspondingAbstract);
758
- }
759
- newProperties.end = newProperties.end - 1;
760
- }
761
- }
762
- });
763
- const abstractHandles = relativeAbstracts.map(value => {
764
- const newProperties = accumulativeProperties.get(value);
765
- if (newProperties) {
766
- const path = PlaitBoard.findPath(board, value);
767
- return () => {
768
- if (newProperties.start > newProperties.end) {
769
- Transforms.removeNode(board, path);
770
- }
771
- else {
772
- Transforms.setNode(board, newProperties, path);
773
- }
774
- };
775
- }
776
- return () => { };
777
- });
778
- const deletableHandles = deletableElements.map(node => {
779
- const path = PlaitBoard.findPath(board, node);
909
+ const abstractRefs = deleteElementHandleAbstract(board, deletableElements);
910
+ MindTransforms.setAbstractsByRefs(board, abstractRefs);
911
+ //翻转,从下到上修改,防止找不到 path
912
+ deletableElements
913
+ .map(element => {
914
+ const path = PlaitBoard.findPath(board, element);
780
915
  return () => {
781
- if (shouldChangeRightNodeCount(node)) {
782
- changeRightNodeCount(board, path.slice(0, path.length - 1), -1);
916
+ if (shouldChangeRightNodeCount(element)) {
917
+ changeRightNodeCount(board, path.slice(0, 1), -1);
783
918
  }
784
919
  Transforms.removeNode(board, path);
785
920
  };
921
+ })
922
+ .forEach(action => {
923
+ action();
786
924
  });
787
- abstractHandles.forEach(action => action());
788
- deletableHandles.forEach(action => action());
789
925
  };
790
926
  const divideElementByParent = (elements) => {
791
927
  const abstractIncludedGroups = [];
@@ -816,9 +952,12 @@ const getNodeShapeByElement = (element) => {
816
952
  }
817
953
  parent = findParentElement(parent);
818
954
  }
819
- return MindNodeShape.roundRectangle;
955
+ return MindElementShape.roundRectangle;
820
956
  };
821
957
 
958
+ /**
959
+ * Processing of branch color, width, style, etc. of the mind node
960
+ */
822
961
  const getBranchColorByMindElement = (board, element) => {
823
962
  const ancestors = MindElement.getAncestors(board, element);
824
963
  ancestors.unshift(element);
@@ -830,19 +969,40 @@ const getBranchColorByMindElement = (board, element) => {
830
969
  const branch = ancestors[ancestors.length - 2];
831
970
  if (branch) {
832
971
  const index = root.children.indexOf(branch);
833
- const length = COLORS.length;
972
+ const length = BRANCH_COLORS.length;
834
973
  const remainder = index % length;
835
- return COLORS[remainder];
974
+ return BRANCH_COLORS[remainder];
836
975
  }
837
976
  else {
838
977
  throw new Error('root element should not have branch color');
839
978
  }
840
979
  };
980
+ const getBranchWidthByMindElement = (board, element) => {
981
+ const ancestors = MindElement.getAncestors(board, element);
982
+ ancestors.unshift(element);
983
+ const ancestor = ancestors.find(value => value.branchColor);
984
+ if (ancestor && ancestor.branchWidth) {
985
+ return ancestor.branchWidth;
986
+ }
987
+ return BRANCH_WIDTH;
988
+ };
989
+ const getAbstractBranchWidth = (board, element) => {
990
+ if (!isNullOrUndefined(element.branchWidth)) {
991
+ return element.branchWidth;
992
+ }
993
+ return DefaultAbstractNodeStyle.branchWidth;
994
+ };
995
+ const getAbstractBranchColor = (board, element) => {
996
+ if (element.branchColor) {
997
+ return element.branchColor;
998
+ }
999
+ return DefaultAbstractNodeStyle.branchColor;
1000
+ };
841
1001
  const getNextBranchColor = (root) => {
842
1002
  const index = root.children.length;
843
- const length = COLORS.length;
1003
+ const length = BRANCH_COLORS.length;
844
1004
  const remainder = index % length;
845
- return COLORS[remainder];
1005
+ return BRANCH_COLORS[remainder];
846
1006
  };
847
1007
 
848
1008
  const getStrokeByMindElement = (board, element) => {
@@ -856,12 +1016,12 @@ const getStrokeByMindElement = (board, element) => {
856
1016
  const branch = ancestors[ancestors.length - 2];
857
1017
  if (branch) {
858
1018
  const index = root.children.indexOf(branch);
859
- const length = COLORS.length;
1019
+ const length = BRANCH_COLORS.length;
860
1020
  const remainder = index % length;
861
- return COLORS[remainder];
1021
+ return BRANCH_COLORS[remainder];
862
1022
  }
863
1023
  else {
864
- return ROOT_NODE_STROKE;
1024
+ return DefaultRootStyle.strokeColor;
865
1025
  }
866
1026
  };
867
1027
 
@@ -880,7 +1040,7 @@ function isVirtualKey(e) {
880
1040
  function drawLink(board, node, child, defaultStroke = null, isHorizontal = true, needDrawUnderline = true) {
881
1041
  var _a;
882
1042
  let beginX, beginY, endX, endY, beginNode = node, endNode = child;
883
- const layout = MindQueries.getCorrectLayoutByElement(node.origin);
1043
+ const layout = MindQueries.getCorrectLayoutByElement(board, node.origin);
884
1044
  if (isHorizontal) {
885
1045
  if (!isChildRight(node, child)) {
886
1046
  beginNode = child;
@@ -892,7 +1052,7 @@ function drawLink(board, node, child, defaultStroke = null, isHorizontal = true,
892
1052
  endY = endNode.y + endNode.height / 2;
893
1053
  if (node.parent &&
894
1054
  isIndentedLayout(MindQueries.getLayoutByElement((_a = node.parent) === null || _a === void 0 ? void 0 : _a.origin)) &&
895
- getNodeShapeByElement(node.origin) === MindNodeShape.underline) {
1055
+ getNodeShapeByElement(node.origin) === MindElementShape.underline) {
896
1056
  if (isChildRight(node, child)) {
897
1057
  beginY = node.y + node.height - node.vGap;
898
1058
  }
@@ -967,7 +1127,7 @@ function drawLink(board, node, child, defaultStroke = null, isHorizontal = true,
967
1127
  curve = [...line, ...curve];
968
1128
  }
969
1129
  }
970
- if (needDrawUnderline && shape === MindNodeShape.underline) {
1130
+ if (needDrawUnderline && shape === MindElementShape.underline) {
971
1131
  if (child.left) {
972
1132
  const underline = [
973
1133
  [beginX - (beginNode.width - beginNode.hGap * 2), beginY],
@@ -1043,8 +1203,8 @@ const drawPlaceholderDropNodeG = (board, dropTarget, fakeDropNodeG) => {
1043
1203
  }
1044
1204
  };
1045
1205
  const drawCurvePlaceholderDropNodeG = (board, targetRect, detectResult, targetIndex, targetComponent, parentComponent, fakeDropNodeG) => {
1046
- const parentNodeLayout = MindQueries.getCorrectLayoutByElement(parentComponent.node.origin);
1047
- const layout = MindQueries.getCorrectLayoutByElement(targetComponent.node.parent.origin);
1206
+ const parentNodeLayout = MindQueries.getCorrectLayoutByElement(board, parentComponent.node.origin);
1207
+ const layout = MindQueries.getCorrectLayoutByElement(board, targetComponent.node.parent.origin);
1048
1208
  const strokeWidth = targetComponent.node.origin.branchWidth ? targetComponent.node.origin.branchWidth : STROKE_WIDTH;
1049
1209
  let fakeX = targetComponent.node.x, fakeY = targetRect.y - 30, fakeRectangleStartX = targetRect.x, fakeRectangleEndX = targetRect.x + 30, fakeRectangleStartY = fakeY, fakeRectangleEndY = fakeRectangleStartY + 12, width = 30;
1050
1210
  if (isLeftLayout(layout)) {
@@ -1175,8 +1335,8 @@ const drawStraightDropNodeG = (board, targetRect, detectResult, targetComponent,
1175
1335
  height,
1176
1336
  strokeWidth
1177
1337
  };
1178
- const parentLayout = MindQueries.getCorrectLayoutByElement(targetComponent.node.origin.isRoot ? targetComponent.node.origin : targetComponent.node.parent.origin);
1179
- const layout = MindQueries.getCorrectLayoutByElement(targetComponent.node.origin);
1338
+ const parentLayout = MindQueries.getCorrectLayoutByElement(board, targetComponent.node.origin.isRoot ? targetComponent.node.origin : targetComponent.node.parent.origin);
1339
+ const layout = MindQueries.getCorrectLayoutByElement(board, targetComponent.node.origin);
1180
1340
  if (!isMixedLayout(parentLayout, layout)) {
1181
1341
  // 构造一条直线
1182
1342
  let linePoints = [
@@ -1386,29 +1546,29 @@ const directionDetector = (targetNode, centerPoint) => {
1386
1546
  return null;
1387
1547
  };
1388
1548
 
1389
- const directionCorrector = (node, detectResults) => {
1390
- if (!node.origin.isRoot) {
1391
- const parentlayout = MindQueries.getCorrectLayoutByElement(node === null || node === void 0 ? void 0 : node.parent.origin);
1392
- if (isStandardLayout(parentlayout)) {
1549
+ const directionCorrector = (board, node, detectResults) => {
1550
+ if (!node.origin.isRoot && !AbstractNode.isAbstract(node.origin)) {
1551
+ const parentLayout = MindQueries.getCorrectLayoutByElement(board, node === null || node === void 0 ? void 0 : node.parent.origin);
1552
+ if (isStandardLayout(parentLayout)) {
1393
1553
  const idx = node.parent.children.findIndex(x => x === node);
1394
1554
  const isLeft = idx >= (node.parent.origin.rightNodeCount || 0);
1395
1555
  return getAllowedDirection(detectResults, [isLeft ? 'right' : 'left']);
1396
1556
  }
1397
- if (isLeftLayout(parentlayout)) {
1557
+ if (isLeftLayout(parentLayout)) {
1398
1558
  return getAllowedDirection(detectResults, ['right']);
1399
1559
  }
1400
- if (isRightLayout(parentlayout)) {
1560
+ if (isRightLayout(parentLayout)) {
1401
1561
  return getAllowedDirection(detectResults, ['left']);
1402
1562
  }
1403
- if (parentlayout === MindLayoutType.upward) {
1563
+ if (parentLayout === MindLayoutType.upward) {
1404
1564
  return getAllowedDirection(detectResults, ['bottom']);
1405
1565
  }
1406
- if (parentlayout === MindLayoutType.downward) {
1566
+ if (parentLayout === MindLayoutType.downward) {
1407
1567
  return getAllowedDirection(detectResults, ['top']);
1408
1568
  }
1409
1569
  }
1410
1570
  else {
1411
- const layout = MindQueries.getCorrectLayoutByElement(node === null || node === void 0 ? void 0 : node.origin);
1571
+ const layout = MindQueries.getCorrectLayoutByElement(board, node === null || node === void 0 ? void 0 : node.origin);
1412
1572
  if (isStandardLayout(layout)) {
1413
1573
  return getAllowedDirection(detectResults, ['top', 'bottom']);
1414
1574
  }
@@ -1439,17 +1599,18 @@ const getAllowedDirection = (detectResults, illegalDirections) => {
1439
1599
  };
1440
1600
 
1441
1601
  /* 根据布局调整 target 以及 direction */
1442
- const readjustmentDropTarget = (dropTarget) => {
1602
+ const readjustmentDropTarget = (board, dropTarget) => {
1443
1603
  const { target, detectResult } = dropTarget;
1444
1604
  const newDropTarget = { target, detectResult };
1445
1605
  const targetComponent = PlaitElement.getComponent(target);
1446
1606
  if (targetComponent.node.children.length > 0 && dropTarget.detectResult) {
1447
- const layout = MindQueries.getCorrectLayoutByElement(targetComponent.node.origin);
1448
- const parentLayout = MindQueries.getCorrectLayoutByElement(targetComponent.node.origin.isRoot ? targetComponent.node.origin : targetComponent.node.parent.origin);
1607
+ const layout = MindQueries.getCorrectLayoutByElement(board, targetComponent.node.origin);
1608
+ const parentLayout = MindQueries.getCorrectLayoutByElement(board, targetComponent.node.origin.isRoot ? targetComponent.node.origin : targetComponent.node.parent.origin);
1609
+ const children = getNonAbstractChildren(targetComponent.node);
1449
1610
  if (['right', 'left'].includes(dropTarget.detectResult)) {
1450
1611
  if (!isMixedLayout(parentLayout, layout)) {
1451
1612
  if (targetComponent.node.origin.isRoot) {
1452
- const layout = MindQueries.getCorrectLayoutByElement(targetComponent.node.origin);
1613
+ const layout = MindQueries.getCorrectLayoutByElement(board, targetComponent.node.origin);
1453
1614
  // 标准布局,根节点
1454
1615
  if (isStandardLayout(layout)) {
1455
1616
  const rightNodeCount = targetComponent.node.origin.rightNodeCount;
@@ -1483,14 +1644,14 @@ const readjustmentDropTarget = (dropTarget) => {
1483
1644
  return newDropTarget;
1484
1645
  }
1485
1646
  // 剩下是水平布局的默认情况:插入最后一个子节点的下方
1486
- const lastChildNodeIndex = targetComponent.node.children.length - 1;
1647
+ const lastChildNodeIndex = children.length - 1;
1487
1648
  newDropTarget.target = targetComponent.node.children[lastChildNodeIndex].origin;
1488
1649
  newDropTarget.detectResult = 'bottom';
1489
1650
  }
1490
1651
  else {
1491
1652
  // 处理左右布局下的混合布局
1492
1653
  if ([MindLayoutType.left, MindLayoutType.right].includes(parentLayout)) {
1493
- const layout = MindQueries.getCorrectLayoutByElement(targetComponent.node.origin);
1654
+ const layout = MindQueries.getCorrectLayoutByElement(board, targetComponent.node.origin);
1494
1655
  if (isIndentedLayout(layout)) {
1495
1656
  newDropTarget.target = targetComponent.node.children[0].origin;
1496
1657
  newDropTarget.detectResult = isTopLayout(layout) ? 'bottom' : 'top';
@@ -1507,9 +1668,9 @@ const readjustmentDropTarget = (dropTarget) => {
1507
1668
  return newDropTarget;
1508
1669
  }
1509
1670
  // 上下布局,插到右边
1510
- const parentLayout = MindQueries.getCorrectLayoutByElement(targetComponent.node.origin.isRoot ? targetComponent.node.origin : targetComponent.node.parent.origin);
1671
+ const parentLayout = MindQueries.getCorrectLayoutByElement(board, targetComponent.node.origin.isRoot ? targetComponent.node.origin : targetComponent.node.parent.origin);
1511
1672
  if (isVerticalLogicLayout(parentLayout)) {
1512
- const lastChildNodeIndex = targetComponent.node.children.length - 1;
1673
+ const lastChildNodeIndex = children.length - 1;
1513
1674
  newDropTarget.target = targetComponent.node.children[lastChildNodeIndex].origin;
1514
1675
  newDropTarget.detectResult = 'right';
1515
1676
  return newDropTarget;
@@ -1606,7 +1767,7 @@ const getLocationScope = (board, handlePosition, parentChildren, element, parent
1606
1767
  }
1607
1768
  };
1608
1769
  const getHitAbstractHandle = (board, element, point) => {
1609
- const nodeLayout = MindQueries.getCorrectLayoutByElement(element);
1770
+ const nodeLayout = MindQueries.getCorrectLayoutByElement(board, element);
1610
1771
  const isHorizontal = isHorizontalLayout(nodeLayout);
1611
1772
  const parentElement = MindElement.getParent(element);
1612
1773
  const includedElements = parentElement.children.slice(element.start, element.end + 1);
@@ -1693,24 +1854,25 @@ function handleTouchedAbstract(board, touchedAbstract, endPoint) {
1693
1854
  }
1694
1855
 
1695
1856
  function drawIndentedLink(board, node, child, defaultStroke = null, needDrawUnderline = true) {
1696
- const isUnderlineShap = getNodeShapeByElement(child.origin) === MindNodeShape.underline;
1857
+ const branchWidth = getBranchWidthByMindElement(board, child.origin);
1858
+ const branchColor = defaultStroke || getBranchColorByMindElement(board, child.origin);
1859
+ const isUnderlineShape = getNodeShapeByElement(child.origin) === MindElementShape.underline;
1697
1860
  let beginX, beginY, endX, endY, beginNode = node, endNode = child;
1698
1861
  const beginRectangle = getRectangleByNode(beginNode);
1699
1862
  const endRectangle = getRectangleByNode(endNode);
1700
1863
  beginX = beginNode.x + beginNode.width / 2;
1701
1864
  beginY = isChildUp(node, child) ? beginRectangle.y : beginRectangle.y + beginRectangle.height;
1702
1865
  endX = node.left ? endNode.x + endNode.hGap + endRectangle.width : endNode.x + endNode.hGap;
1703
- endY = isUnderlineShap ? endNode.y + endNode.height - endNode.vGap : endNode.y + endNode.height / 2;
1866
+ endY = isUnderlineShape ? endNode.y + endNode.height - endNode.vGap : endNode.y + endNode.height / 2;
1704
1867
  //根据位置,设置正负参数
1705
1868
  let plusMinus = isChildUp(node, child) ? (node.left ? [-1, -1] : [1, -1]) : node.left ? [-1, 1] : [1, 1];
1706
- const layout = MindQueries.getCorrectLayoutByElement(node.origin);
1707
- const strokeWidth = child.origin.branchWidth ? child.origin.branchWidth : STROKE_WIDTH;
1869
+ const layout = MindQueries.getCorrectLayoutByElement(board, node.origin);
1708
1870
  if (beginNode.origin.isRoot) {
1709
1871
  if (layout === MindLayoutType.leftBottomIndented || layout === MindLayoutType.rightBottomIndented) {
1710
- beginY += strokeWidth;
1872
+ beginY += branchWidth;
1711
1873
  }
1712
1874
  if (layout === MindLayoutType.leftTopIndented || layout === MindLayoutType.rightTopIndented) {
1713
- beginY -= strokeWidth;
1875
+ beginY -= branchWidth;
1714
1876
  }
1715
1877
  }
1716
1878
  let curve = [
@@ -1721,13 +1883,12 @@ function drawIndentedLink(board, node, child, defaultStroke = null, needDrawUnde
1721
1883
  [beginX, endY - (endNode.hGap * plusMinus[1]) / 5],
1722
1884
  [beginX + (endNode.hGap * plusMinus[0]) / 4, endY],
1723
1885
  [beginX + (endNode.hGap * plusMinus[0] * 3) / 5, endY],
1724
- isUnderlineShap && needDrawUnderline ? [endX + (endNode.width - endNode.hGap * 2) * plusMinus[0], endY] : [endX, endY],
1725
- isUnderlineShap && needDrawUnderline ? [endX + (endNode.width - endNode.hGap * 2) * plusMinus[0], endY] : [endX, endY],
1726
- isUnderlineShap && needDrawUnderline ? [endX + (endNode.width - endNode.hGap * 2) * plusMinus[0], endY] : [endX, endY]
1886
+ isUnderlineShape && needDrawUnderline ? [endX + (endNode.width - endNode.hGap * 2) * plusMinus[0], endY] : [endX, endY],
1887
+ isUnderlineShape && needDrawUnderline ? [endX + (endNode.width - endNode.hGap * 2) * plusMinus[0], endY] : [endX, endY],
1888
+ isUnderlineShape && needDrawUnderline ? [endX + (endNode.width - endNode.hGap * 2) * plusMinus[0], endY] : [endX, endY]
1727
1889
  ];
1728
- const stroke = defaultStroke || getBranchColorByMindElement(board, child.origin);
1729
1890
  const points = pointsOnBezierCurves(curve);
1730
- return PlaitBoard.getRoughSVG(board).curve(points, { stroke, strokeWidth });
1891
+ return PlaitBoard.getRoughSVG(board).curve(points, { stroke: branchColor, strokeWidth: branchWidth });
1731
1892
  }
1732
1893
 
1733
1894
  var HorizontalPlacement;
@@ -1842,10 +2003,10 @@ const transformPlacement = (placement, direction) => {
1842
2003
 
1843
2004
  function drawLogicLink(board, node, parent, isHorizontal) {
1844
2005
  const branchColor = getBranchColorByMindElement(board, node.origin);
1845
- const strokeWidth = node.origin.branchWidth ? node.origin.branchWidth : STROKE_WIDTH;
2006
+ const branchWidth = getBranchWidthByMindElement(board, node.origin);
1846
2007
  const hasStraightLine = !parent.origin.isRoot;
1847
- const hasUnderlineShape = node.origin.shape === MindNodeShape.underline;
1848
- const hasUnderlineShapeOfParent = parent.origin.shape === MindNodeShape.underline;
2008
+ const hasUnderlineShape = node.origin.shape === MindElementShape.underline;
2009
+ const hasUnderlineShapeOfParent = parent.origin.shape === MindElementShape.underline;
1849
2010
  const nodeClient = getRectangleByNode(node);
1850
2011
  const parentClient = getRectangleByNode(parent);
1851
2012
  const linkDirection = getLayoutDirection(node, isHorizontal);
@@ -1882,13 +2043,17 @@ function drawLogicLink(board, node, parent, isHorizontal) {
1882
2043
  const underlineEnd = movePoint(endPoint, nodeClient.width, linkDirection);
1883
2044
  const underline = hasUnderlineShape && isHorizontal ? [underlineEnd, underlineEnd, underlineEnd] : [];
1884
2045
  const points = pointsOnBezierCurves([...straightLine, ...curve, ...underline]);
1885
- return PlaitBoard.getRoughSVG(board).curve(points, { stroke: branchColor, strokeWidth });
2046
+ return PlaitBoard.getRoughSVG(board).curve(points, { stroke: branchColor, strokeWidth: branchWidth });
1886
2047
  }
1887
2048
 
1888
- function getEmojisRectangle(element) {
2049
+ function getEmojisRectangle(board, element) {
2050
+ const options = board.getMindOptions();
1889
2051
  const count = element.data.emojis.length;
1890
2052
  const fontSize = getEmojiFontSize(element);
1891
- return { width: fontSize * count + (count - 1) * 4, height: element.height };
2053
+ return {
2054
+ width: fontSize * count + count * 2 * options.emojiPadding + (count - 1) * options.spaceBetweenEmojis,
2055
+ height: element.height
2056
+ };
1892
2057
  }
1893
2058
  function getEmojiFontSize(element) {
1894
2059
  if (PlaitMind.isMind(element)) {
@@ -1933,10 +2098,10 @@ const getVerticalSpaceBetweenNodeAndText = (element) => {
1933
2098
  return nodeAndText;
1934
2099
  };
1935
2100
  const NodeSpace = {
1936
- getNodeWidth(element) {
2101
+ getNodeWidth(board, element) {
1937
2102
  const nodeAndText = getHorizontalSpaceBetweenNodeAndText(element);
1938
2103
  if (MindElement.hasEmojis(element)) {
1939
- return nodeAndText + getEmojisRectangle(element).width + getHorizontalSpaceEmojiAndText(element) + element.width + nodeAndText;
2104
+ return nodeAndText + getEmojisRectangle(board, element).width + getHorizontalSpaceEmojiAndText(element) + element.width + nodeAndText;
1940
2105
  }
1941
2106
  return nodeAndText + element.width + nodeAndText;
1942
2107
  },
@@ -1944,10 +2109,10 @@ const NodeSpace = {
1944
2109
  const nodeAndText = getVerticalSpaceBetweenNodeAndText(element);
1945
2110
  return nodeAndText + element.height + nodeAndText;
1946
2111
  },
1947
- getTextHorizontalSpace(element) {
2112
+ getTextHorizontalSpace(board, element) {
1948
2113
  const nodeAndText = getHorizontalSpaceBetweenNodeAndText(element);
1949
2114
  if (MindElement.hasEmojis(element)) {
1950
- return nodeAndText + getEmojisRectangle(element).width + getHorizontalSpaceEmojiAndText(element);
2115
+ return nodeAndText + getEmojisRectangle(board, element).width + getHorizontalSpaceEmojiAndText(element);
1951
2116
  }
1952
2117
  else {
1953
2118
  return nodeAndText;
@@ -1967,9 +2132,9 @@ const NodeSpace = {
1967
2132
  }
1968
2133
  };
1969
2134
 
1970
- function drawMindNodeRichtext(node, viewContainerRef) {
2135
+ function drawMindNodeRichtext(board, node, viewContainerRef) {
1971
2136
  var _a, _b;
1972
- const { x, y } = getRichtextRectangleByNode(node);
2137
+ const { x, y } = getRichtextRectangleByNode(board, node);
1973
2138
  const classList = [];
1974
2139
  if (node.origin.isRoot) {
1975
2140
  classList.push('root-node');
@@ -1984,8 +2149,8 @@ function drawMindNodeRichtext(node, viewContainerRef) {
1984
2149
  // COMPAT: last character can not show in safari browser
1985
2150
  return drawRichtext(x, y, Math.ceil(node.origin.width), Math.ceil(node.origin.height), node.origin.data.topic, viewContainerRef, classList);
1986
2151
  }
1987
- function updateMindNodeTopicSize(node, g, isEditable) {
1988
- const { x, y, width, height } = getRichtextRectangleByNode(node);
2152
+ function updateMindNodeTopicSize(board, node, g, isEditable) {
2153
+ const { x, y, width, height } = getRichtextRectangleByNode(board, node);
1989
2154
  if (isEditable) {
1990
2155
  // add 999, avoid changing lines when paste more text
1991
2156
  updateForeignObject(g, width + 999, height + 999, x, y);
@@ -1995,18 +2160,18 @@ function updateMindNodeTopicSize(node, g, isEditable) {
1995
2160
  updateForeignObject(g, Math.ceil(node.origin.width), Math.ceil(node.origin.height), x, y);
1996
2161
  }
1997
2162
  }
1998
- function getRichtextRectangleByNode(node) {
2163
+ function getRichtextRectangleByNode(board, node) {
1999
2164
  let { x, y, width, height } = getRectangleByNode(node);
2000
- x = x + NodeSpace.getTextHorizontalSpace(node.origin);
2165
+ x = x + NodeSpace.getTextHorizontalSpace(board, node.origin);
2001
2166
  y = y + NodeSpace.getTextVerticalSpace(node.origin);
2002
2167
  return { width, height, x, y };
2003
2168
  }
2004
2169
 
2005
2170
  function drawRectangleNode(board, node) {
2006
2171
  const { x, y, width, height } = getRectangleByNode(node);
2007
- const fill = node.origin.fill ? node.origin.fill : node.origin.isRoot ? ROOT_NODE_FILL : NODE_FILL;
2172
+ const fill = node.origin.fill ? node.origin.fill : node.origin.isRoot ? DefaultRootStyle.fill : DefaultNodeStyle.fill;
2008
2173
  const stroke = getStrokeByMindElement(board, node.origin);
2009
- const strokeWidth = node.origin.strokeWidth ? node.origin.strokeWidth : STROKE_WIDTH;
2174
+ const strokeWidth = node.origin.strokeWidth ? node.origin.strokeWidth : DefaultNodeStyle.strokeWidth;
2010
2175
  const nodeG = drawRoundRectangle(PlaitBoard.getRoughSVG(board), x, y, x + width, y + height, {
2011
2176
  stroke,
2012
2177
  strokeWidth,
@@ -2018,6 +2183,8 @@ function drawRectangleNode(board, node) {
2018
2183
 
2019
2184
  function drawAbstractLink(board, node, isHorizontal) {
2020
2185
  const linkPadding = 15;
2186
+ const branchWidth = getAbstractBranchWidth(board, node.origin);
2187
+ const branchColor = getAbstractBranchColor(board, node.origin);
2021
2188
  const parent = node.parent;
2022
2189
  const abstractRectangle = getRectangleByNode(node);
2023
2190
  let includedElements = parent.children.slice(node.origin.start, node.origin.end + 1).map(node => {
@@ -2047,8 +2214,8 @@ function drawAbstractLink(board, node, isHorizontal) {
2047
2214
  let c2 = movePoint(bezierEndPoint, curveDistance, linkDirection);
2048
2215
  let bezierConnectorPoint = movePoint(abstractConnectorPoint, -linkPadding, linkDirection);
2049
2216
  const link = PlaitBoard.getRoughSVG(board).path(`M${bezierBeginPoint[0]},${bezierBeginPoint[1]} Q${c1[0]},${c1[1]} ${bezierConnectorPoint[0]},${bezierConnectorPoint[1]} Q${c2[0]},${c2[1]} ${bezierEndPoint[0]},${bezierEndPoint[1]} M${abstractConnectorPoint[0]},${abstractConnectorPoint[1]} L${bezierConnectorPoint[0]},${bezierConnectorPoint[1]}`, {
2050
- stroke: GRAY_COLOR,
2051
- strokeWidth: 2
2217
+ stroke: branchColor,
2218
+ strokeWidth: branchWidth
2052
2219
  });
2053
2220
  return link;
2054
2221
  }
@@ -2096,9 +2263,8 @@ class EmojisDrawer {
2096
2263
  this.g.classList.add('emojis');
2097
2264
  let { x, y } = getRectangleByNode(MindElement.getNode(element));
2098
2265
  x = x + NodeSpace.getEmojiHorizontalSpace(element);
2099
- y = y + NodeSpace.getEmojiVerticalSpace(element);
2100
- const { width, height } = getEmojisRectangle(element);
2101
- const foreignObject = createForeignObject(x, y, width, height);
2266
+ const { width, height } = getEmojisRectangle(this.board, element);
2267
+ const foreignObject = createForeignObject(x, y, width, height + NodeSpace.getEmojiVerticalSpace(element) * 2);
2102
2268
  this.g.append(foreignObject);
2103
2269
  const container = document.createElement('div');
2104
2270
  container.classList.add('node-emojis-container');
@@ -2109,117 +2275,25 @@ class EmojisDrawer {
2109
2275
  return drawer;
2110
2276
  });
2111
2277
  this.emojiDrawers.forEach(drawer => {
2112
- container.append(drawer.nativeElement);
2113
- });
2114
- return this.g;
2115
- }
2116
- return undefined;
2117
- }
2118
- destroy() {
2119
- if (this.g) {
2120
- this.g.remove();
2121
- }
2122
- this.emojiDrawers.forEach(drawer => drawer.destroy());
2123
- this.emojiDrawers = [];
2124
- }
2125
- }
2126
-
2127
- const setLayout = (board, layout, path) => {
2128
- correctLogicLayoutNode(board, layout, path);
2129
- const element = PlaitNode.get(board, path);
2130
- if (PlaitMind.isMind(element) && isStandardLayout(layout)) {
2131
- handleAbstractIncluded(board, element);
2132
- }
2133
- Transforms.setNode(board, { layout }, path);
2134
- };
2135
- const correctLogicLayoutNode = (board, layout, path) => {
2136
- var _a;
2137
- const node = PlaitNode.get(board, path);
2138
- if (node && layout) {
2139
- (_a = node.children) === null || _a === void 0 ? void 0 : _a.forEach((value, index) => {
2140
- var _a;
2141
- if (value.layout) {
2142
- if ((isHorizontalLogicLayout(layout) && isVerticalLogicLayout(value.layout)) ||
2143
- (isVerticalLogicLayout(layout) && isHorizontalLogicLayout(value.layout))) {
2144
- Transforms.setNode(board, { layout: null }, [...path, index]);
2145
- }
2146
- if ((_a = value.children) === null || _a === void 0 ? void 0 : _a.length) {
2147
- correctLogicLayoutNode(board, layout, [...path, index]);
2148
- }
2149
- }
2150
- });
2151
- }
2152
- };
2153
-
2154
- const setTopic = (board, element, topic, width, height) => {
2155
- const newElement = {
2156
- data: { topic },
2157
- width: width < NODE_MIN_WIDTH * board.viewport.zoom ? NODE_MIN_WIDTH : width / board.viewport.zoom,
2158
- height: height / board.viewport.zoom
2159
- };
2160
- if (MindElement.hasEmojis(element)) {
2161
- newElement.data.emojis = element.data.emojis;
2162
- }
2163
- const path = PlaitBoard.findPath(board, element);
2164
- Transforms.setNode(board, newElement, path);
2165
- };
2166
- const setTopicSize = (board, element, width, height) => {
2167
- const newElement = {
2168
- width: width < NODE_MIN_WIDTH * board.viewport.zoom ? NODE_MIN_WIDTH : width / board.viewport.zoom,
2169
- height: height / board.viewport.zoom
2170
- };
2171
- const path = PlaitBoard.findPath(board, element);
2172
- Transforms.setNode(board, newElement, path);
2173
- };
2174
- const addEmoji = (board, element, emojiItem) => {
2175
- const emojis = element.data.emojis || [];
2176
- const newEmojis = [...emojis];
2177
- newEmojis.push(emojiItem);
2178
- const newElement = {
2179
- data: { topic: element.data.topic, emojis: newEmojis }
2180
- };
2181
- const path = PlaitBoard.findPath(board, element);
2182
- Transforms.setNode(board, newElement, path);
2183
- };
2184
- const removeEmoji = (board, element, emojiItem) => {
2185
- const emojis = element.data.emojis.filter(value => value !== emojiItem);
2186
- const newElement = {
2187
- data: { topic: element.data.topic }
2188
- };
2189
- if (emojis.length > 0) {
2190
- newElement.data.emojis = emojis;
2191
- }
2192
- const path = PlaitBoard.findPath(board, element);
2193
- Transforms.setNode(board, newElement, path);
2194
- };
2195
- const replaceEmoji = (board, element, oldEmoji, newEmoji) => {
2196
- const newElement = {
2197
- data: { topic: element.data.topic }
2198
- };
2199
- const newEmojis = element.data.emojis.map(value => {
2200
- if (value === oldEmoji) {
2201
- return newEmoji;
2278
+ container.append(drawer.nativeElement);
2279
+ });
2280
+ return this.g;
2202
2281
  }
2203
- return value;
2204
- });
2205
- newElement.data.emojis = newEmojis;
2206
- const path = PlaitBoard.findPath(board, element);
2207
- Transforms.setNode(board, newElement, path);
2208
- };
2209
-
2210
- const MindTransforms = {
2211
- setLayout,
2212
- setTopic,
2213
- setTopicSize,
2214
- addEmoji,
2215
- removeEmoji,
2216
- replaceEmoji
2217
- };
2282
+ return undefined;
2283
+ }
2284
+ destroy() {
2285
+ if (this.g) {
2286
+ this.g.remove();
2287
+ }
2288
+ this.emojiDrawers.forEach(drawer => drawer.destroy());
2289
+ this.emojiDrawers = [];
2290
+ }
2291
+ }
2218
2292
 
2219
2293
  function drawAbstractIncludedOutline(board, roughSVG, element, activeHandlePosition, resizingLocation) {
2220
2294
  const abstractIncludedG = createG();
2221
2295
  const parentElement = MindElement.getParent(element);
2222
- const nodeLayout = MindQueries.getCorrectLayoutByElement(element);
2296
+ const nodeLayout = MindQueries.getCorrectLayoutByElement(board, element);
2223
2297
  const isHorizontal = isHorizontalLayout(nodeLayout);
2224
2298
  const includedElements = parentElement.children.slice(element.start, element.end + 1);
2225
2299
  let abstractRectangle = getRectangleByElements(board, includedElements, true);
@@ -2299,7 +2373,8 @@ function hasAfterDraw(value) {
2299
2373
  }
2300
2374
 
2301
2375
  function findNewChildNodePath(board, element) {
2302
- return PlaitBoard.findPath(board, element).concat((element.children || []).filter(child => !AbstractNode.isAbstract(child)).length);
2376
+ const children = getNonAbstractChildren(element);
2377
+ return PlaitBoard.findPath(board, element).concat(children.length);
2303
2378
  }
2304
2379
  function findNewSiblingNodePath(board, element) {
2305
2380
  const path = PlaitBoard.findPath(board, element);
@@ -2329,14 +2404,14 @@ class QuickInsertDrawer extends BaseDrawer {
2329
2404
  */
2330
2405
  const shape = getNodeShapeByElement(element);
2331
2406
  // 形状是矩形要偏移边框的线宽
2332
- const strokeWidth = element.branchWidth ? element.branchWidth : STROKE_WIDTH;
2407
+ const branchWidth = getBranchWidthByMindElement(this.board, element);
2333
2408
  let offsetBorderLineWidth = 0;
2334
- if (shape === MindNodeShape.roundRectangle && offset === 0) {
2335
- offsetBorderLineWidth = strokeWidth;
2409
+ if (shape === MindElementShape.roundRectangle && offset === 0) {
2410
+ offsetBorderLineWidth = branchWidth;
2336
2411
  }
2337
2412
  let offsetRootBorderLineWidth = 0;
2338
2413
  if (element.isRoot) {
2339
- offsetRootBorderLineWidth = strokeWidth;
2414
+ offsetRootBorderLineWidth = branchWidth;
2340
2415
  }
2341
2416
  // 当没有子节点时,需要缩小的偏移量
2342
2417
  const extraOffset = 3;
@@ -2431,21 +2506,21 @@ class QuickInsertDrawer extends BaseDrawer {
2431
2506
  offsetRootBorderLineWidth
2432
2507
  }
2433
2508
  };
2434
- if (shape === MindNodeShape.roundRectangle || element.isRoot) {
2509
+ if (shape === MindElementShape.roundRectangle || element.isRoot) {
2435
2510
  underlineCoordinates[MindLayoutType.left].startY -= height * 0.5;
2436
2511
  underlineCoordinates[MindLayoutType.left].endY -= height * 0.5;
2437
2512
  underlineCoordinates[MindLayoutType.right].startY -= height * 0.5;
2438
2513
  underlineCoordinates[MindLayoutType.right].endY -= height * 0.5;
2439
2514
  }
2440
2515
  const branchColor = PlaitMind.isMind(element) ? getNextBranchColor(element) : getBranchColorByMindElement(this.board, element);
2441
- let nodeLayout = MindQueries.getCorrectLayoutByElement(element);
2516
+ let nodeLayout = MindQueries.getCorrectLayoutByElement(this.board, element);
2442
2517
  if (element.isRoot && isStandardLayout(nodeLayout)) {
2443
2518
  const root = element;
2444
2519
  nodeLayout = root.children.length >= root.rightNodeCount ? MindLayoutType.left : MindLayoutType.right;
2445
2520
  }
2446
2521
  const underlineCoordinate = underlineCoordinates[nodeLayout];
2447
2522
  if (underlineCoordinate) {
2448
- const underline = PlaitBoard.getRoughSVG(this.board).line(underlineCoordinate.startX, underlineCoordinate.startY, underlineCoordinate.endX, underlineCoordinate.endY, { stroke: branchColor, strokeWidth });
2523
+ const underline = PlaitBoard.getRoughSVG(this.board).line(underlineCoordinate.startX, underlineCoordinate.startY, underlineCoordinate.endX, underlineCoordinate.endY, { stroke: branchColor, strokeWidth: branchWidth });
2449
2524
  const circleCoordinates = {
2450
2525
  startX: underlineCoordinate.endX,
2451
2526
  startY: underlineCoordinate.endY
@@ -2587,7 +2662,7 @@ class MindNodeComponent extends PlaitPluginElementComponent {
2587
2662
  this.destroyShape();
2588
2663
  const shape = getNodeShapeByElement(this.node.origin);
2589
2664
  switch (shape) {
2590
- case MindNodeShape.roundRectangle:
2665
+ case MindElementShape.roundRectangle:
2591
2666
  this.shapeG = drawRectangleNode(this.board, this.node);
2592
2667
  this.g.prepend(this.shapeG);
2593
2668
  break;
@@ -2745,7 +2820,7 @@ class MindNodeComponent extends PlaitPluginElementComponent {
2745
2820
  }
2746
2821
  }
2747
2822
  drawRichtext() {
2748
- const { richtextG, richtextComponentRef, foreignObject } = drawMindNodeRichtext(this.node, this.viewContainerRef);
2823
+ const { richtextG, richtextComponentRef, foreignObject } = drawMindNodeRichtext(this.board, this.node, this.viewContainerRef);
2749
2824
  this.richtextComponentRef = richtextComponentRef;
2750
2825
  this.richtextG = richtextG;
2751
2826
  this.foreignObject = foreignObject;
@@ -2775,9 +2850,9 @@ class MindNodeComponent extends PlaitPluginElementComponent {
2775
2850
  });
2776
2851
  const { x, y, width, height } = getRectangleByNode(this.node);
2777
2852
  const stroke = getBranchColorByMindElement(this.board, this.element);
2778
- const strokeWidth = this.node.origin.branchWidth ? this.node.origin.branchWidth : STROKE_WIDTH;
2853
+ const branchWidth = getBranchWidthByMindElement(this.board, this.element);
2779
2854
  const extendY = y + height / 2;
2780
- const nodeLayout = MindQueries.getCorrectLayoutByElement(this.element);
2855
+ const nodeLayout = MindQueries.getCorrectLayoutByElement(this.board, this.element);
2781
2856
  let extendLineXY = [
2782
2857
  [x + width, extendY],
2783
2858
  [x + width + EXTEND_OFFSET, extendY]
@@ -2789,7 +2864,7 @@ class MindNodeComponent extends PlaitPluginElementComponent {
2789
2864
  let circleOffset = [EXTEND_RADIUS / 2, 0];
2790
2865
  if (isHorizontalLayout(nodeLayout) && !isIndentedLayout(nodeLayout)) {
2791
2866
  extendLineYOffset =
2792
- getNodeShapeByElement(this.node.origin) === MindNodeShape.roundRectangle
2867
+ getNodeShapeByElement(this.node.origin) === MindElementShape.roundRectangle
2793
2868
  ? [0, 0]
2794
2869
  : [height / 2, height / 2];
2795
2870
  if (isLeftLayout(nodeLayout)) {
@@ -2821,7 +2896,7 @@ class MindNodeComponent extends PlaitPluginElementComponent {
2821
2896
  [extendLineXY[1][0] + extendLineXOffset[1], extendLineXY[1][1] + extendLineYOffset[1]]
2822
2897
  ];
2823
2898
  const extendLine = this.roughSVG.line(extendLineXY[0][0], extendLineXY[0][1], extendLineXY[1][0], extendLineXY[1][1], {
2824
- strokeWidth,
2899
+ strokeWidth: branchWidth,
2825
2900
  stroke
2826
2901
  });
2827
2902
  //绘制箭头
@@ -2858,7 +2933,7 @@ class MindNodeComponent extends PlaitPluginElementComponent {
2858
2933
  const hideCircleG = this.roughSVG.circle(extendLineXY[1][0] + circleOffset[0], extendLineXY[1][1] + circleOffset[1], EXTEND_RADIUS - 1, {
2859
2934
  fill: '#fff',
2860
2935
  stroke,
2861
- strokeWidth,
2936
+ strokeWidth: branchWidth,
2862
2937
  fillStyle: 'solid'
2863
2938
  });
2864
2939
  collapseG.appendChild(hideCircleG);
@@ -2888,7 +2963,7 @@ class MindNodeComponent extends PlaitPluginElementComponent {
2888
2963
  }
2889
2964
  updateRichtext() {
2890
2965
  updateRichText(this.node.origin.data.topic, this.richtextComponentRef);
2891
- updateMindNodeTopicSize(this.node, this.richtextG, this.isEditable);
2966
+ updateMindNodeTopicSize(this.board, this.node, this.richtextG, this.isEditable);
2892
2967
  }
2893
2968
  startEditText(isEnd, isClear) {
2894
2969
  if (!this.richtextComponentRef) {
@@ -2898,7 +2973,7 @@ class MindNodeComponent extends PlaitPluginElementComponent {
2898
2973
  this.isEditable = true;
2899
2974
  IS_TEXT_EDITABLE.set(this.board, true);
2900
2975
  this.disabledMaskG();
2901
- updateMindNodeTopicSize(this.node, this.richtextG, this.isEditable);
2976
+ updateMindNodeTopicSize(this.board, this.node, this.richtextG, this.isEditable);
2902
2977
  if (richtextInstance.plaitReadonly) {
2903
2978
  richtextInstance.plaitReadonly = false;
2904
2979
  this.richtextComponentRef.changeDetectorRef.detectChanges();
@@ -3002,7 +3077,7 @@ class MindNodeComponent extends PlaitPluginElementComponent {
3002
3077
  richtextInstance.plaitReadonly = true;
3003
3078
  (_a = this.richtextComponentRef) === null || _a === void 0 ? void 0 : _a.changeDetectorRef.markForCheck();
3004
3079
  this.isEditable = false;
3005
- updateMindNodeTopicSize(this.node, this.richtextG, this.isEditable);
3080
+ updateMindNodeTopicSize(this.board, this.node, this.richtextG, this.isEditable);
3006
3081
  IS_TEXT_EDITABLE.set(this.board, false);
3007
3082
  };
3008
3083
  }
@@ -3045,7 +3120,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImpor
3045
3120
  }]
3046
3121
  }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }, { type: i0.ChangeDetectorRef }, { type: i0.Renderer2 }]; } });
3047
3122
 
3048
- const getLayoutOptions = () => {
3123
+ const getLayoutOptions = (board) => {
3049
3124
  function getMainAxle(element, parent) {
3050
3125
  const strokeWidth = element.strokeWidth || STROKE_WIDTH;
3051
3126
  if (element.isRoot) {
@@ -3068,7 +3143,7 @@ const getLayoutOptions = () => {
3068
3143
  return NodeSpace.getNodeHeight(element);
3069
3144
  },
3070
3145
  getWidth(element) {
3071
- return NodeSpace.getNodeWidth(element);
3146
+ return NodeSpace.getNodeWidth(board, element);
3072
3147
  },
3073
3148
  getHorizontalGap(element, parent) {
3074
3149
  const _layout = (parent && parent.layout) || getRootLayout(element);
@@ -3098,7 +3173,7 @@ const getLayoutOptions = () => {
3098
3173
  }
3099
3174
  },
3100
3175
  getVerticalConnectingPosition(element, parent) {
3101
- if (element.shape === MindNodeShape.underline && parent && isHorizontalLogicLayout(parent.layout)) {
3176
+ if (element.shape === MindElementShape.underline && parent && isHorizontalLogicLayout(parent.layout)) {
3102
3177
  return ConnectingPosition.bottom;
3103
3178
  }
3104
3179
  return undefined;
@@ -3124,7 +3199,7 @@ class PlaitMindComponent extends MindNodeComponent {
3124
3199
  }
3125
3200
  updateMindLayout(element = this.element) {
3126
3201
  const mindLayoutType = element.layout || getDefaultLayout();
3127
- this.root = GlobalLayout.layout(element, getLayoutOptions(), mindLayoutType);
3202
+ this.root = GlobalLayout.layout(element, getLayoutOptions(this.board), mindLayoutType);
3128
3203
  this.updateMindNodeLocation(element);
3129
3204
  }
3130
3205
  updateMindNodeLocation(element) {
@@ -3167,6 +3242,120 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImpor
3167
3242
  }]
3168
3243
  }] });
3169
3244
 
3245
+ const isValidTarget = (origin, target) => {
3246
+ return origin !== target && !isChildElement(origin, target);
3247
+ };
3248
+ const addActiveOnDragOrigin = (activeElement, isOrigin = true) => {
3249
+ const activeComponent = PlaitElement.getComponent(activeElement);
3250
+ if (isOrigin) {
3251
+ activeComponent.g.classList.add('dragging-origin');
3252
+ }
3253
+ else {
3254
+ activeComponent.g.classList.add('dragging-child');
3255
+ }
3256
+ !activeElement.isCollapsed &&
3257
+ activeElement.children.forEach(child => {
3258
+ addActiveOnDragOrigin(child, false);
3259
+ });
3260
+ };
3261
+ const removeActiveOnDragOrigin = (activeElement, isOrigin = true) => {
3262
+ const activeComponent = PlaitElement.getComponent(activeElement);
3263
+ if (isOrigin) {
3264
+ activeComponent.g.classList.remove('dragging-origin');
3265
+ }
3266
+ else {
3267
+ activeComponent.g.classList.remove('dragging-child');
3268
+ }
3269
+ !activeElement.isCollapsed &&
3270
+ activeElement.children.forEach(child => {
3271
+ removeActiveOnDragOrigin(child, false);
3272
+ });
3273
+ };
3274
+ const updatePathByLayoutAndDropTarget = (targetPath, layout, dropTarget) => {
3275
+ // 上下布局:左右是兄弟节点,上下是子节点
3276
+ if (isVerticalLogicLayout(layout)) {
3277
+ if (isTopLayout(layout) && dropTarget.detectResult === 'top') {
3278
+ targetPath.push(dropTarget.target.children.length);
3279
+ }
3280
+ if (isBottomLayout(layout) && dropTarget.detectResult === 'bottom') {
3281
+ targetPath.push(dropTarget.target.children.length);
3282
+ }
3283
+ // 如果是左,位置不变,右则插入到下一个兄弟节点
3284
+ if (dropTarget.detectResult === 'right') {
3285
+ targetPath = Path.next(targetPath);
3286
+ }
3287
+ }
3288
+ // 水平布局/标准布局:上下是兄弟节点,左右是子节点
3289
+ if (isHorizontalLogicLayout(layout)) {
3290
+ if (dropTarget.detectResult === 'right') {
3291
+ targetPath.push(dropTarget.target.children.length);
3292
+ }
3293
+ if (dropTarget.detectResult === 'left') {
3294
+ targetPath.push(dropTarget.target.children.length);
3295
+ }
3296
+ // 如果是上,位置不变,下插入到下一个兄弟节点
3297
+ if (dropTarget.detectResult === 'bottom') {
3298
+ targetPath = Path.next(targetPath);
3299
+ }
3300
+ }
3301
+ // 缩进布局:上下是兄弟节点,左右是子节点,但上(左上/右上),探测到上是子节点,下则位置不变,反之同理。
3302
+ if (isIndentedLayout(layout)) {
3303
+ if (isTopLayout(layout) && dropTarget.detectResult === 'top') {
3304
+ targetPath = Path.next(targetPath);
3305
+ }
3306
+ if (isBottomLayout(layout) && dropTarget.detectResult === 'bottom') {
3307
+ targetPath = Path.next(targetPath);
3308
+ }
3309
+ if (isLeftLayout(layout) && dropTarget.detectResult === 'left') {
3310
+ targetPath.push(dropTarget.target.children.length);
3311
+ }
3312
+ if (isRightLayout(layout) && dropTarget.detectResult === 'right') {
3313
+ targetPath.push(dropTarget.target.children.length);
3314
+ }
3315
+ }
3316
+ return targetPath;
3317
+ };
3318
+ const updateRightNodeCount = (board, activeComponent, targetComponent, detectResult) => {
3319
+ var _a;
3320
+ let rightNodeCount;
3321
+ const mindElement = findUpElement(targetComponent.node.origin).root;
3322
+ const mindComponent = ELEMENT_TO_COMPONENT.get(mindElement);
3323
+ const activeIndex = mindComponent === null || mindComponent === void 0 ? void 0 : mindComponent.root.children.indexOf(activeComponent.node);
3324
+ const targetIndex = mindComponent === null || mindComponent === void 0 ? void 0 : mindComponent.root.children.indexOf(targetComponent.node);
3325
+ const isActiveOnRight = activeIndex !== -1 && activeIndex <= activeComponent.parent.origin.rightNodeCount - 1;
3326
+ const isTargetOnRight = targetComponent.parent && targetIndex !== -1 && targetIndex <= targetComponent.parent.origin.rightNodeCount - 1;
3327
+ const isBothOnRight = isActiveOnRight && isTargetOnRight;
3328
+ const rootChildCount = (_a = mindComponent.root.children) === null || _a === void 0 ? void 0 : _a.length;
3329
+ const rootRightNodeCount = mindComponent === null || mindComponent === void 0 ? void 0 : mindComponent.root.origin.rightNodeCount;
3330
+ if (!isBothOnRight) {
3331
+ if (isActiveOnRight) {
3332
+ rightNodeCount = rootChildCount < rootRightNodeCount ? rootChildCount - 1 : rootRightNodeCount - 1;
3333
+ Transforms.setNode(board, { rightNodeCount }, PlaitBoard.findPath(board, activeComponent.parent.origin));
3334
+ }
3335
+ if (isTargetOnRight && detectResult !== 'right') {
3336
+ rightNodeCount = rootChildCount < rootRightNodeCount ? rootRightNodeCount : rootRightNodeCount + 1;
3337
+ Transforms.setNode(board, { rightNodeCount }, PlaitBoard.findPath(board, targetComponent.parent.origin));
3338
+ }
3339
+ //二级子节点拖动到根节点左侧
3340
+ if (targetComponent.node.origin.isRoot && detectResult === 'left' && activeIndex === -1) {
3341
+ rightNodeCount = rootChildCount;
3342
+ Transforms.setNode(board, { rightNodeCount }, PlaitBoard.findPath(board, targetComponent.element));
3343
+ }
3344
+ }
3345
+ };
3346
+ const IS_DRAGGING = new WeakMap();
3347
+ const isDragging = (board) => {
3348
+ return !!IS_DRAGGING.get(board);
3349
+ };
3350
+ const setIsDragging = (board, state) => {
3351
+ IS_DRAGGING.set(board, state);
3352
+ };
3353
+ const updateAbstractInDnd = (board, deletableElements, originPath) => {
3354
+ const refs = insertElementHandleAbstract(board, originPath, false);
3355
+ deleteElementHandleAbstract(board, deletableElements, refs);
3356
+ MindTransforms.setAbstractsByRefs(board, refs);
3357
+ };
3358
+
3170
3359
  const DRAG_MOVE_BUFFER = 5;
3171
3360
  const withDnd = (board) => {
3172
3361
  const { mousedown, mousemove, globalMouseup, keydown } = board;
@@ -3241,7 +3430,7 @@ const withDnd = (board) => {
3241
3430
  const activeComponent = PlaitElement.getComponent(activeElement);
3242
3431
  const roughSVG = PlaitBoard.getRoughSVG(board);
3243
3432
  const fakeDraggingNode = Object.assign(Object.assign({}, activeComponent.node), { children: [], x: activeComponent.node.x + offsetX, y: activeComponent.node.y + offsetY });
3244
- const textRectangle = getRichtextRectangleByNode(activeComponent.node);
3433
+ const textRectangle = getRichtextRectangleByNode(board, activeComponent.node);
3245
3434
  const fakeNodeG = drawRectangleNode(board, fakeDraggingNode);
3246
3435
  const richtextG = (_a = activeComponent.richtextG) === null || _a === void 0 ? void 0 : _a.cloneNode(true);
3247
3436
  updateForeignObject(richtextG, textRectangle.width + BASE * 10, textRectangle.height, textRectangle.x + offsetX, textRectangle.y + offsetY);
@@ -3264,7 +3453,7 @@ const withDnd = (board) => {
3264
3453
  }
3265
3454
  const directions = directionDetector(node, detectCenterPoint);
3266
3455
  if (directions) {
3267
- detectResult = directionCorrector(node, directions);
3456
+ detectResult = directionCorrector(board, node, directions);
3268
3457
  }
3269
3458
  dropTarget = null;
3270
3459
  if (detectResult && isValidTarget(activeComponent.node.origin, node.origin)) {
@@ -3274,7 +3463,7 @@ const withDnd = (board) => {
3274
3463
  }
3275
3464
  });
3276
3465
  if (dropTarget === null || dropTarget === void 0 ? void 0 : dropTarget.target) {
3277
- dropTarget = readjustmentDropTarget(dropTarget);
3466
+ dropTarget = readjustmentDropTarget(board, dropTarget);
3278
3467
  drawPlaceholderDropNodeG(board, dropTarget, fakeDropNodeG);
3279
3468
  }
3280
3469
  }
@@ -3286,12 +3475,13 @@ const withDnd = (board) => {
3286
3475
  const activeComponent = PlaitElement.getComponent(activeElement);
3287
3476
  const targetComponent = PlaitElement.getComponent(dropTarget.target);
3288
3477
  let targetPath = PlaitBoard.findPath(board, targetComponent.element);
3289
- const mindmapElement = findUpElement(dropTarget.target).root;
3290
- const mindmapComponent = ELEMENT_TO_COMPONENT.get(mindmapElement);
3291
- const layout = MindQueries.getCorrectLayoutByElement(mindmapComponent === null || mindmapComponent === void 0 ? void 0 : mindmapComponent.root.origin);
3478
+ const mindElement = findUpElement(dropTarget.target).root;
3479
+ const mindComponent = ELEMENT_TO_COMPONENT.get(mindElement);
3480
+ const layout = MindQueries.getCorrectLayoutByElement(board, mindComponent === null || mindComponent === void 0 ? void 0 : mindComponent.root.origin);
3292
3481
  targetPath = updatePathByLayoutAndDropTarget(targetPath, layout, dropTarget);
3293
3482
  const originPath = PlaitBoard.findPath(board, activeComponent.element);
3294
3483
  let newElement = { isCollapsed: false }, rightTargetPath = PlaitBoard.findPath(board, targetComponent.element);
3484
+ updateAbstractInDnd(board, [activeElement], targetPath);
3295
3485
  if (isStandardLayout(layout)) {
3296
3486
  updateRightNodeCount(board, activeComponent, targetComponent, dropTarget.detectResult);
3297
3487
  }
@@ -3324,122 +3514,45 @@ const withDnd = (board) => {
3324
3514
  };
3325
3515
  return board;
3326
3516
  };
3327
- const isValidTarget = (origin, target) => {
3328
- return origin !== target && !isChildElement(origin, target);
3329
- };
3330
- const addActiveOnDragOrigin = (activeElement, isOrigin = true) => {
3331
- const activeComponent = PlaitElement.getComponent(activeElement);
3332
- if (isOrigin) {
3333
- activeComponent.g.classList.add('dragging-origin');
3334
- }
3335
- else {
3336
- activeComponent.g.classList.add('dragging-child');
3337
- }
3338
- !activeElement.isCollapsed &&
3339
- activeElement.children.forEach(child => {
3340
- addActiveOnDragOrigin(child, false);
3341
- });
3342
- };
3343
- const removeActiveOnDragOrigin = (activeElement, isOrigin = true) => {
3344
- const activeComponent = PlaitElement.getComponent(activeElement);
3345
- if (isOrigin) {
3346
- activeComponent.g.classList.remove('dragging-origin');
3347
- }
3348
- else {
3349
- activeComponent.g.classList.remove('dragging-child');
3350
- }
3351
- !activeElement.isCollapsed &&
3352
- activeElement.children.forEach(child => {
3353
- removeActiveOnDragOrigin(child, false);
3354
- });
3355
- };
3356
- const updatePathByLayoutAndDropTarget = (targetPath, layout, dropTarget) => {
3357
- // 上下布局:左右是兄弟节点,上下是子节点
3358
- if (isVerticalLogicLayout(layout)) {
3359
- if (isTopLayout(layout) && dropTarget.detectResult === 'top') {
3360
- targetPath.push(dropTarget.target.children.length);
3361
- }
3362
- if (isBottomLayout(layout) && dropTarget.detectResult === 'bottom') {
3363
- targetPath.push(dropTarget.target.children.length);
3364
- }
3365
- // 如果是左,位置不变,右则插入到下一个兄弟节点
3366
- if (dropTarget.detectResult === 'right') {
3367
- targetPath = Path.next(targetPath);
3368
- }
3369
- }
3370
- // 水平布局/标准布局:上下是兄弟节点,左右是子节点
3371
- if (isHorizontalLogicLayout(layout)) {
3372
- if (dropTarget.detectResult === 'right') {
3373
- targetPath.push(dropTarget.target.children.length);
3374
- }
3375
- if (dropTarget.detectResult === 'left') {
3376
- targetPath.push(dropTarget.target.children.length);
3377
- }
3378
- // 如果是上,位置不变,下插入到下一个兄弟节点
3379
- if (dropTarget.detectResult === 'bottom') {
3380
- targetPath = Path.next(targetPath);
3381
- }
3382
- }
3383
- // 缩进布局:上下是兄弟节点,左右是子节点,但上(左上/右上),探测到上是子节点,下则位置不变,反之同理。
3384
- if (isIndentedLayout(layout)) {
3385
- if (isTopLayout(layout) && dropTarget.detectResult === 'top') {
3386
- targetPath = Path.next(targetPath);
3387
- }
3388
- if (isBottomLayout(layout) && dropTarget.detectResult === 'bottom') {
3389
- targetPath = Path.next(targetPath);
3390
- }
3391
- if (isLeftLayout(layout) && dropTarget.detectResult === 'left') {
3392
- targetPath.push(dropTarget.target.children.length);
3393
- }
3394
- if (isRightLayout(layout) && dropTarget.detectResult === 'right') {
3395
- targetPath.push(dropTarget.target.children.length);
3396
- }
3397
- }
3398
- return targetPath;
3399
- };
3400
- const updateRightNodeCount = (board, activeComponent, targetComponent, detectResult) => {
3401
- var _a;
3402
- let rightNodeCount;
3403
- const mindmapElement = findUpElement(targetComponent.node.origin).root;
3404
- const mindmapComponent = ELEMENT_TO_COMPONENT.get(mindmapElement);
3405
- const activeIndex = mindmapComponent === null || mindmapComponent === void 0 ? void 0 : mindmapComponent.root.children.indexOf(activeComponent.node);
3406
- const targetIndex = mindmapComponent === null || mindmapComponent === void 0 ? void 0 : mindmapComponent.root.children.indexOf(targetComponent.node);
3407
- const isActiveOnRight = activeIndex !== -1 && activeIndex <= activeComponent.parent.origin.rightNodeCount - 1;
3408
- const isTargetOnRight = targetComponent.parent && targetIndex !== -1 && targetIndex <= targetComponent.parent.origin.rightNodeCount - 1;
3409
- const isBothOnRight = isActiveOnRight && isTargetOnRight;
3410
- const rootChildCount = (_a = mindmapComponent.root.children) === null || _a === void 0 ? void 0 : _a.length;
3411
- const rootRightNodeCount = mindmapComponent === null || mindmapComponent === void 0 ? void 0 : mindmapComponent.root.origin.rightNodeCount;
3412
- if (!isBothOnRight) {
3413
- if (isActiveOnRight) {
3414
- rightNodeCount = rootChildCount < rootRightNodeCount ? rootChildCount - 1 : rootRightNodeCount - 1;
3415
- Transforms.setNode(board, { rightNodeCount }, PlaitBoard.findPath(board, activeComponent.parent.origin));
3416
- }
3417
- if (isTargetOnRight && detectResult !== 'right') {
3418
- rightNodeCount = rootChildCount < rootRightNodeCount ? rootRightNodeCount : rootRightNodeCount + 1;
3419
- Transforms.setNode(board, { rightNodeCount }, PlaitBoard.findPath(board, targetComponent.parent.origin));
3420
- }
3421
- //二级子节点拖动到根节点左侧
3422
- if (targetComponent.node.origin.isRoot && detectResult === 'left' && activeIndex === -1) {
3423
- rightNodeCount = rootChildCount;
3424
- Transforms.setNode(board, { rightNodeCount }, PlaitBoard.findPath(board, targetComponent.element));
3425
- }
3426
- }
3427
- };
3428
- const IS_DRAGGING = new WeakMap();
3429
- const isDragging = (board) => {
3430
- return !!IS_DRAGGING.get(board);
3431
- };
3432
- const setIsDragging = (board, state) => {
3433
- IS_DRAGGING.set(board, state);
3434
- };
3435
3517
 
3436
3518
  const buildClipboardData = (board, selectedElements) => {
3437
3519
  let result = [];
3438
- const selectedMindNodes = selectedElements.map(value => MindElement.getNode(value));
3439
- const nodesRectangle = getRectangleByElements(board, selectedElements, true);
3440
- selectedElements.forEach((node, index) => {
3520
+ // get overall abstract
3521
+ const overallAbstracts = getOverallAbstracts(board, selectedElements);
3522
+ // keep correct order
3523
+ const newSelectedElements = selectedElements.filter((value) => !overallAbstracts.includes(value));
3524
+ newSelectedElements.push(...overallAbstracts);
3525
+ // get correct start and end in selected elements
3526
+ function getCorrectStartEnd(abstract) {
3527
+ const parent = MindElement.getParent(abstract);
3528
+ const startElement = parent.children[abstract.start];
3529
+ const index = selectedElements.indexOf(startElement);
3530
+ return { start: index, end: index + (abstract.end - abstract.start) };
3531
+ }
3532
+ const selectedMindNodes = newSelectedElements.map(value => MindElement.getNode(value));
3533
+ const nodesRectangle = getRectangleByElements(board, newSelectedElements, true);
3534
+ newSelectedElements.forEach((element, index) => {
3535
+ // handle relative location
3441
3536
  const nodeRectangle = getRectangleByNode(selectedMindNodes[index]);
3442
- result.push(Object.assign(Object.assign({}, node), { points: [[nodeRectangle.x - nodesRectangle.x, nodeRectangle.y - nodesRectangle.y]] }));
3537
+ const points = [[nodeRectangle.x - nodesRectangle.x, nodeRectangle.y - nodesRectangle.y]];
3538
+ // handle invalid abstract
3539
+ if (AbstractNode.isAbstract(element) && overallAbstracts.includes(element)) {
3540
+ const { start, end } = getCorrectStartEnd(element);
3541
+ result.push(Object.assign(Object.assign({}, element), { points,
3542
+ start,
3543
+ end }));
3544
+ }
3545
+ else {
3546
+ if (AbstractNode.isAbstract(element)) {
3547
+ let newElement = Object.assign(Object.assign({}, element), { points });
3548
+ delete newElement.start;
3549
+ delete newElement.end;
3550
+ result.push(newElement);
3551
+ }
3552
+ else {
3553
+ result.push(Object.assign(Object.assign({}, element), { points: points }));
3554
+ }
3555
+ }
3443
3556
  });
3444
3557
  return result;
3445
3558
  };
@@ -3465,17 +3578,22 @@ const insertClipboardData = (board, elements, targetPoint) => {
3465
3578
  let newElement, path;
3466
3579
  const selectedElements = getSelectedElements(board);
3467
3580
  let newELements = [];
3581
+ const hasTargetParent = selectedElements.length === 1;
3582
+ const targetParent = selectedElements[0];
3583
+ const targetParentPath = targetParent && PlaitBoard.findPath(board, targetParent);
3584
+ const nonAbstractChildrenLength = targetParent && getNonAbstractChildren(targetParent).length;
3468
3585
  elements.forEach((item, index) => {
3469
3586
  newElement = copyNewNode(item);
3470
- if (selectedElements.length === 1) {
3587
+ if (hasTargetParent) {
3471
3588
  if (item.isRoot) {
3472
3589
  newElement = transformRootToNode(board, newElement);
3473
3590
  }
3474
- if (AbstractNode.isAbstract(item)) {
3475
- newElement = transformAbstractToNode(newElement);
3591
+ // handle abstract start and end
3592
+ if (AbstractNode.isAbstract(newElement)) {
3593
+ newElement.start = newElement.start + nonAbstractChildrenLength;
3594
+ newElement.end = newElement.end + nonAbstractChildrenLength;
3476
3595
  }
3477
- const selectedElementPath = PlaitBoard.findPath(board, selectedElements[0]);
3478
- path = selectedElementPath.concat((selectedElements[0].children || []).length + index);
3596
+ path = [...targetParentPath, nonAbstractChildrenLength + index];
3479
3597
  }
3480
3598
  else {
3481
3599
  const point = [targetPoint[0] + item.points[0][0], targetPoint[1] + item.points[0][1]];
@@ -3501,14 +3619,6 @@ const insertClipboardText = (board, parentElement, text, width, height) => {
3501
3619
  return;
3502
3620
  };
3503
3621
 
3504
- const withEmoji = (board) => {
3505
- const newBoard = board;
3506
- newBoard.drawEmoji = (emoji, element) => {
3507
- throw new Error('Not implement drawEmoji method error.');
3508
- };
3509
- return newBoard;
3510
- };
3511
-
3512
3622
  const withAbstract = (board) => {
3513
3623
  const newBoard = board;
3514
3624
  const { mousedown, mousemove, mouseup } = board;
@@ -3543,7 +3653,7 @@ const withAbstract = (board) => {
3543
3653
  event.preventDefault();
3544
3654
  const abstractComponent = PlaitElement.getComponent(activeAbstractElement);
3545
3655
  const element = abstractComponent.element;
3546
- const nodeLayout = MindQueries.getCorrectLayoutByElement(activeAbstractElement);
3656
+ const nodeLayout = MindQueries.getCorrectLayoutByElement(board, activeAbstractElement);
3547
3657
  const isHorizontal = isHorizontalLayout(nodeLayout);
3548
3658
  const parentElement = MindElement.getParent(element);
3549
3659
  let children = parentElement.children;
@@ -3609,6 +3719,17 @@ const withAbstract = (board) => {
3609
3719
  return board;
3610
3720
  };
3611
3721
 
3722
+ const withExtendMind = (board) => {
3723
+ const newBoard = board;
3724
+ newBoard.drawEmoji = (emoji, element) => {
3725
+ throw new Error('Not implement drawEmoji method error.');
3726
+ };
3727
+ newBoard.getMindOptions = () => {
3728
+ return { spaceBetweenEmojis: 4, emojiPadding: 0 };
3729
+ };
3730
+ return newBoard;
3731
+ };
3732
+
3612
3733
  const withMind = (board) => {
3613
3734
  const { drawElement, dblclick, keydown, insertFragment, setFragment, deleteFragment, isHitSelection, getRectangle, isMovable, isRecursion } = board;
3614
3735
  board.drawElement = (context) => {
@@ -3673,7 +3794,8 @@ const withMind = (board) => {
3673
3794
  if (shouldChangeRightNodeCount(selectedElement)) {
3674
3795
  changeRightNodeCount(board, selectedElementPath.slice(0, 1), 1);
3675
3796
  }
3676
- insertSiblingElementHandleAbstract(board, selectedElement);
3797
+ const abstractRefs = insertElementHandleAbstract(board, Path.next(selectedElementPath));
3798
+ MindTransforms.setAbstractsByRefs(board, abstractRefs);
3677
3799
  insertMindElement(board, selectedElement, findNewSiblingNodePath(board, selectedElement));
3678
3800
  }
3679
3801
  return;
@@ -3777,7 +3899,7 @@ const withMind = (board) => {
3777
3899
  deleteSelectedELements(board, selectedElements);
3778
3900
  deleteFragment(data);
3779
3901
  };
3780
- return withEmoji(withAbstract(withDnd(board)));
3902
+ return withExtendMind(withAbstract(withDnd(board)));
3781
3903
  };
3782
3904
 
3783
3905
  class MindEmojiBaseComponent {
@@ -3819,5 +3941,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImpor
3819
3941
  * Generated bundle index. Do not edit.
3820
3942
  */
3821
3943
 
3822
- export { ABSTRACT_HANDLE_COLOR, ABSTRACT_HANDLE_LENGTH, ABSTRACT_HANDLE_MASK_WIDTH, ABSTRACT_INCLUDED_OUTLINE_OFFSET, AbstractHandlePosition, AbstractResizeState, BASE, COLORS, ELEMENT_TO_NODE, EXTEND_OFFSET, EXTEND_RADIUS, GRAY_COLOR, LayoutDirection, LayoutDirectionsMap, MAX_RADIUS, MINDMAP_KEY, MindElement, MindEmojiBaseComponent, MindModule, MindNode, MindNodeComponent, MindNodeShape, MindQueries, MindTransforms, NODE_FILL, NODE_MIN_WIDTH, PRIMARY_COLOR, PlaitMind, PlaitMindComponent, QUICK_INSERT_CIRCLE_COLOR, QUICK_INSERT_CIRCLE_OFFSET, QUICK_INSERT_INNER_CROSS_COLOR, ROOT_NODE_FILL, ROOT_NODE_STROKE, ROOT_TOPIC_FONT_SIZE, STROKE_WIDTH, TOPIC_COLOR, TOPIC_DEFAULT_MAX_WORD_COUNT, TOPIC_FONT_SIZE, TRANSPARENT, canSetAbstract, changeRightNodeCount, copyNewNode, correctLayoutByDirection, createDefaultMindMapElement, createMindElement, deleteSelectedELements, directionCorrector, directionDetector, divideElementByParent, drawCurvePlaceholderDropNodeG, drawIndentNodeG, drawPlaceholderDropNodeG, drawStraightDropNodeG, extractNodesText, filterChildElement, findLastChild, findLocationLeftIndex, findParentElement, findUpElement, getAbstractHandleRectangle, getAllowedDirection, getAvailableSubLayoutsByLayoutDirections, getBehindAbstracts, getBranchColorByMindElement, getBranchDirectionsByLayouts, getChildrenCount, getCorrespondingAbstract, getDefaultLayout, getEmojiFontSize, getEmojisRectangle, getHitAbstractHandle, getHorizontalFakeY, getInCorrectLayoutDirection, getIndentedFakePoint, getLayoutDirection$1 as getLayoutDirection, getLayoutReverseDirection, getLocationScope, getNextBranchColor, getNodeShapeByElement, getRectangleByNode, getRectangleByResizingLocation, getRootLayout, getStrokeByMindElement, handleAbstractIncluded, handleTouchedAbstract, hitMindElement, insertAbstractNode, insertMindElement, insertSiblingElementHandleAbstract, isChildElement, isChildRight, isChildUp, isCorrectLayout, isMixedLayout, isSetAbstract, isVirtualKey, moveAbstractPosition, readjustmentDropTarget, separateChildren, setAbstract, setAbstractByElements, shouldChangeRightNodeCount, transformAbstractToNode, transformNodeToRoot, transformRootToNode, withEmoji, withMind };
3944
+ export { ABSTRACT_HANDLE_COLOR, ABSTRACT_HANDLE_LENGTH, ABSTRACT_HANDLE_MASK_WIDTH, ABSTRACT_INCLUDED_OUTLINE_OFFSET, AbstractHandlePosition, AbstractResizeState, BASE, BRANCH_COLORS, BRANCH_WIDTH, DefaultAbstractNodeStyle, DefaultNodeStyle, DefaultRootStyle, ELEMENT_TO_NODE, EXTEND_OFFSET, EXTEND_RADIUS, GRAY_COLOR, LayoutDirection, LayoutDirectionsMap, MindElement, MindElementShape, MindEmojiBaseComponent, MindModule, MindNode, MindNodeComponent, MindQueries, MindTransforms, NODE_MIN_WIDTH, PRIMARY_COLOR, PlaitMind, PlaitMindComponent, QUICK_INSERT_CIRCLE_COLOR, QUICK_INSERT_CIRCLE_OFFSET, QUICK_INSERT_INNER_CROSS_COLOR, ROOT_TOPIC_FONT_SIZE, STROKE_WIDTH, TOPIC_COLOR, TOPIC_DEFAULT_MAX_WORD_COUNT, TOPIC_FONT_SIZE, TRANSPARENT, canSetAbstract, changeRightNodeCount, copyNewNode, correctLayoutByDirection, createDefaultMindMapElement, createMindElement, deleteElementHandleAbstract, deleteSelectedELements, directionCorrector, directionDetector, divideElementByParent, drawCurvePlaceholderDropNodeG, drawIndentNodeG, drawPlaceholderDropNodeG, drawStraightDropNodeG, extractNodesText, filterChildElement, findLastChild, findLocationLeftIndex, findParentElement, findUpElement, getAbstractBranchColor, getAbstractBranchWidth, getAbstractHandleRectangle, getAllowedDirection, getAvailableSubLayoutsByLayoutDirections, getBehindAbstracts, getBranchColorByMindElement, getBranchDirectionsByLayouts, getBranchWidthByMindElement, getChildrenCount, getCorrespondingAbstract, getDefaultLayout, getEmojiFontSize, getEmojisRectangle, getHitAbstractHandle, getHorizontalFakeY, getInCorrectLayoutDirection, getIndentedFakePoint, getLayoutDirection$1 as getLayoutDirection, getLayoutReverseDirection, getLocationScope, getNextBranchColor, getNodeShapeByElement, getOverallAbstracts, getRectangleByNode, getRectangleByResizingLocation, getRootLayout, getStrokeByMindElement, handleTouchedAbstract, hitMindElement, insertElementHandleAbstract, insertMindElement, isChildElement, isChildRight, isChildUp, isCorrectLayout, isMixedLayout, isSetAbstract, isVirtualKey, readjustmentDropTarget, separateChildren, shouldChangeRightNodeCount, transformAbstractToNode, transformNodeToRoot, transformRootToNode, withExtendMind, withMind };
3823
3945
  //# sourceMappingURL=plait-mind.mjs.map