@plait/mind 0.2.0-next.8 → 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 (74) 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/esm2020/constants/abstract-node.mjs +5 -0
  8. package/esm2020/constants/default.mjs +2 -3
  9. package/esm2020/constants/index.mjs +5 -2
  10. package/esm2020/constants/node-rule.mjs +2 -0
  11. package/esm2020/constants/node-style.mjs +19 -0
  12. package/esm2020/constants/node-topic-style.mjs +5 -0
  13. package/esm2020/draw/abstract.mjs +4 -3
  14. package/esm2020/draw/indented-link.mjs +14 -14
  15. package/esm2020/draw/link/abstract-link.mjs +6 -4
  16. package/esm2020/draw/link/logic-link.mjs +7 -7
  17. package/esm2020/draw/link.mjs +6 -5
  18. package/esm2020/draw/shape.mjs +4 -4
  19. package/esm2020/drawer/quick-insert.drawer.mjs +11 -12
  20. package/esm2020/interfaces/abstract.mjs +1 -1
  21. package/esm2020/interfaces/element.mjs +6 -1
  22. package/esm2020/interfaces/node.mjs +1 -1
  23. package/esm2020/layout-option.mjs +3 -3
  24. package/esm2020/node.component.mjs +11 -9
  25. package/esm2020/plugins/with-abstract.mjs +2 -2
  26. package/esm2020/plugins/with-dnd.mjs +11 -116
  27. package/esm2020/plugins/with-mind.mjs +7 -5
  28. package/esm2020/queries/get-available-sublayouts-by-element.mjs +4 -9
  29. package/esm2020/queries/get-branch-layouts.mjs +4 -4
  30. package/esm2020/queries/get-correct-layout-by-element.mjs +28 -31
  31. package/esm2020/queries/get-layout-by-element.mjs +10 -8
  32. package/esm2020/queries/index.mjs +1 -3
  33. package/esm2020/transforms/abstract-node.mjs +68 -0
  34. package/esm2020/transforms/index.mjs +6 -2
  35. package/esm2020/transforms/layout.mjs +3 -3
  36. package/esm2020/transforms/node.mjs +2 -2
  37. package/esm2020/utils/abstract/common.mjs +90 -70
  38. package/esm2020/utils/abstract/resize.mjs +3 -3
  39. package/esm2020/utils/clipboard.mjs +54 -14
  40. package/esm2020/utils/direction-corrector.mjs +11 -11
  41. package/esm2020/utils/dnd.mjs +118 -0
  42. package/esm2020/utils/draw-placeholder.mjs +5 -5
  43. package/esm2020/utils/drop-target-corrector.mjs +11 -10
  44. package/esm2020/utils/layout.mjs +1 -1
  45. package/esm2020/utils/mind.mjs +23 -58
  46. package/esm2020/utils/node-style/branch.mjs +33 -6
  47. package/esm2020/utils/node-style/node.mjs +6 -5
  48. package/esm2020/utils/path.mjs +4 -3
  49. package/esm2020/utils/shape.mjs +3 -3
  50. package/fesm2015/plait-mind.mjs +691 -575
  51. package/fesm2015/plait-mind.mjs.map +1 -1
  52. package/fesm2020/plait-mind.mjs +693 -573
  53. package/fesm2020/plait-mind.mjs.map +1 -1
  54. package/interfaces/abstract.d.ts +3 -0
  55. package/interfaces/element.d.ts +5 -2
  56. package/package.json +1 -1
  57. package/plugins/with-dnd.d.ts +0 -9
  58. package/queries/get-available-sublayouts-by-element.d.ts +2 -6
  59. package/queries/get-branch-layouts.d.ts +2 -1
  60. package/queries/get-correct-layout-by-element.d.ts +2 -1
  61. package/queries/index.d.ts +3 -4
  62. package/transforms/abstract-node.d.ts +6 -0
  63. package/transforms/index.d.ts +3 -0
  64. package/utils/abstract/common.d.ts +6 -8
  65. package/utils/direction-corrector.d.ts +2 -1
  66. package/utils/dnd.d.ts +16 -0
  67. package/utils/drop-target-corrector.d.ts +2 -1
  68. package/utils/mind.d.ts +3 -3
  69. package/utils/node-style/branch.d.ts +3 -0
  70. package/utils/shape.d.ts +2 -3
  71. package/constants/node.d.ts +0 -17
  72. package/esm2020/constants/node.mjs +0 -19
  73. package/esm2020/queries/get-layout-parent-by-element.mjs +0 -17
  74. 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,34 +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
- const { root } = findUpElement(element);
79
- const rootLayout = root.layout || getDefaultLayout();
80
- let correctRootLayout = rootLayout;
81
- if (element.isRoot) {
82
- 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;
83
94
  }
84
- const component = PlaitElement.getComponent(element);
85
- let layout = element.layout;
86
- let parentComponent = null;
87
- let parent = component.parent.origin;
88
- while (!layout && parent) {
89
- parentComponent = PlaitElement.getComponent(parent);
90
- layout = parentComponent.node.origin.layout;
91
- parent = parentComponent.parent?.origin;
92
- }
93
- if ((AbstractNode.isAbstract(element) || isChildOfAbstract(MindElement.getNode(element))) &&
94
- isIndentedLayout(layout)) {
95
- return getAbstractLayout(layout);
96
- }
97
- // handle root standard
95
+ const node = MindElement.getNode(element);
96
+ let correctRootLayout = rootLayout;
98
97
  if (rootLayout === MindLayoutType.standard) {
99
- correctRootLayout = component?.node.left ? MindLayoutType.left : MindLayoutType.right;
98
+ correctRootLayout = node.left ? MindLayoutType.left : MindLayoutType.right;
99
+ }
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?.layout;
110
+ }
100
111
  }
101
- if (parentComponent && parentComponent.node.origin.isRoot) {
112
+ if (layout === MindLayoutType.standard || !layout) {
102
113
  return correctRootLayout;
103
114
  }
104
- if (layout) {
115
+ else {
105
116
  const incorrectDirection = getInCorrectLayoutDirection(correctRootLayout, layout);
106
117
  if (incorrectDirection) {
107
118
  return correctLayoutByDirection(layout, incorrectDirection);
@@ -110,16 +121,13 @@ const getCorrectLayoutByElement = (element) => {
110
121
  return layout;
111
122
  }
112
123
  }
113
- else {
114
- return correctRootLayout;
115
- }
116
124
  };
117
125
 
118
- const getBranchLayouts = (element) => {
126
+ const getBranchLayouts = (board, element) => {
119
127
  const layouts = [];
120
128
  if (element.layout) {
121
- //getCorrectLayoutByElement含有递归操作,getBranchMindmapLayouts本身也有递归操作,有待优化
122
- layouts.unshift(getCorrectLayoutByElement(element));
129
+ // TODO: getCorrectLayoutByElement 含有递归操作,getBranchLayouts 本身也有递归操作,有待优化
130
+ layouts.unshift(getCorrectLayoutByElement(board, element));
123
131
  }
124
132
  let parent = findParentElement(element);
125
133
  while (parent) {
@@ -131,15 +139,10 @@ const getBranchLayouts = (element) => {
131
139
  return layouts;
132
140
  };
133
141
 
134
- /**
135
- * get available sub layouts by element
136
- * @param element
137
- * @returns MindLayoutType[]
138
- */
139
- const getAvailableSubLayoutsByElement = (element) => {
142
+ const getAvailableSubLayoutsByElement = (board, element) => {
140
143
  const parentElement = findParentElement(element);
141
144
  if (parentElement) {
142
- const branchLayouts = getBranchLayouts(parentElement);
145
+ const branchLayouts = getBranchLayouts(board, parentElement);
143
146
  if (branchLayouts[0] === MindLayoutType.standard) {
144
147
  const node = MindElement.getNode(element);
145
148
  branchLayouts[0] = node.left ? MindLayoutType.left : MindLayoutType.right;
@@ -155,20 +158,107 @@ const getAvailableSubLayoutsByElement = (element) => {
155
158
  return undefined;
156
159
  };
157
160
 
158
- /**
159
- * 获取父节点布局类型
160
- * @param element
161
- * @returns MindLayoutType
162
- */
163
- const getLayoutParentByElement = (element) => {
164
- let parent = findParentElement(element);
165
- while (parent) {
166
- if (parent.layout) {
167
- 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
+ }
168
238
  }
169
- parent = findParentElement(parent);
170
239
  }
171
- 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();
172
262
  };
173
263
 
174
264
  const getLayoutByElement = (element) => {
@@ -176,17 +266,18 @@ const getLayoutByElement = (element) => {
176
266
  if (layout) {
177
267
  return layout;
178
268
  }
179
- if (AbstractNode.isAbstract(element) ||
180
- (isChildOfAbstract(MindElement.getNode(element)) && isIndentedLayout(layout))) {
181
- const parentLayout = getLayoutParentByElement(element);
182
- 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);
183
275
  }
184
- return getLayoutParentByElement(element);
276
+ return getDefaultLayout();
185
277
  };
186
278
 
187
279
  const MindQueries = {
188
280
  getAvailableSubLayoutsByElement,
189
- getLayoutParentByElement,
190
281
  getBranchLayouts,
191
282
  getLayoutByElement,
192
283
  getCorrectLayoutByElement
@@ -257,6 +348,11 @@ const MindElement = {
257
348
  return element.data.emojis;
258
349
  }
259
350
  };
351
+ var MindElementShape;
352
+ (function (MindElementShape) {
353
+ MindElementShape["roundRectangle"] = "round-rectangle";
354
+ MindElementShape["underline"] = "underline";
355
+ })(MindElementShape || (MindElementShape = {}));
260
356
 
261
357
  const MindNode = {
262
358
  get(root, path) {
@@ -311,109 +407,6 @@ var AbstractResizeState;
311
407
  AbstractResizeState["end"] = "end";
312
408
  })(AbstractResizeState || (AbstractResizeState = {}));
313
409
 
314
- const getBranchDirectionsByLayouts = (branchLayouts) => {
315
- const branchDirections = [];
316
- branchLayouts.forEach(l => {
317
- const directions = LayoutDirectionsMap[l];
318
- directions.forEach(d => {
319
- if (!branchDirections.includes(d) && !branchDirections.includes(getLayoutReverseDirection(d))) {
320
- branchDirections.push(d);
321
- }
322
- });
323
- });
324
- return branchDirections;
325
- };
326
- const isCorrectLayout = (root, layout) => {
327
- const rootLayout = root.layout || getDefaultLayout();
328
- return !getInCorrectLayoutDirection(rootLayout, layout);
329
- };
330
- const isMixedLayout = (parentLayout, layout) => {
331
- return (!isIndentedLayout(parentLayout) && isIndentedLayout(layout)) || (isIndentedLayout(parentLayout) && !isIndentedLayout(layout));
332
- };
333
- const getInCorrectLayoutDirection = (rootLayout, layout) => {
334
- const directions = LayoutDirectionsMap[rootLayout];
335
- const subLayoutDirections = LayoutDirectionsMap[layout];
336
- if (!subLayoutDirections) {
337
- throw new Error(`unexpected layout: ${layout} on correct layout`);
338
- }
339
- return subLayoutDirections.find(d => directions.includes(getLayoutReverseDirection(d)));
340
- };
341
- const correctLayoutByDirection = (layout, direction) => {
342
- const isHorizontal = direction === LayoutDirection.left || direction === LayoutDirection.right ? true : false;
343
- let inverseDirectionLayout = MindLayoutType.standard;
344
- switch (layout) {
345
- case MindLayoutType.left:
346
- inverseDirectionLayout = MindLayoutType.right;
347
- break;
348
- case MindLayoutType.right:
349
- inverseDirectionLayout = MindLayoutType.left;
350
- break;
351
- case MindLayoutType.downward:
352
- inverseDirectionLayout = MindLayoutType.upward;
353
- break;
354
- case MindLayoutType.upward:
355
- inverseDirectionLayout = MindLayoutType.downward;
356
- break;
357
- case MindLayoutType.rightBottomIndented:
358
- inverseDirectionLayout = isHorizontal ? MindLayoutType.leftBottomIndented : MindLayoutType.rightTopIndented;
359
- break;
360
- case MindLayoutType.leftBottomIndented:
361
- inverseDirectionLayout = isHorizontal ? MindLayoutType.rightBottomIndented : MindLayoutType.leftTopIndented;
362
- break;
363
- case MindLayoutType.rightTopIndented:
364
- inverseDirectionLayout = isHorizontal ? MindLayoutType.leftTopIndented : MindLayoutType.rightBottomIndented;
365
- break;
366
- case MindLayoutType.leftTopIndented:
367
- inverseDirectionLayout = isHorizontal ? MindLayoutType.rightTopIndented : MindLayoutType.leftBottomIndented;
368
- break;
369
- }
370
- return inverseDirectionLayout;
371
- };
372
- const getLayoutDirection$1 = (root) => {
373
- const layout = root.layout || getDefaultLayout();
374
- return LayoutDirectionsMap[layout];
375
- };
376
- const getDefaultLayout = () => {
377
- return MindLayoutType.standard;
378
- };
379
- const getAvailableSubLayoutsByLayoutDirections = (directions) => {
380
- const result = [];
381
- const reverseDirections = directions.map(getLayoutReverseDirection);
382
- for (const key in MindLayoutType) {
383
- const layout = MindLayoutType[key];
384
- const layoutDirections = LayoutDirectionsMap[layout];
385
- if (layoutDirections) {
386
- const hasSameDirection = layoutDirections.some(d => directions.includes(d));
387
- const hasReverseDirection = layoutDirections.some(r => reverseDirections.includes(r));
388
- if (hasSameDirection && !hasReverseDirection) {
389
- result.push(layout);
390
- }
391
- }
392
- }
393
- return result;
394
- };
395
- const getLayoutReverseDirection = (layoutDirection) => {
396
- let reverseDirection = LayoutDirection.right;
397
- switch (layoutDirection) {
398
- case LayoutDirection.top:
399
- reverseDirection = LayoutDirection.bottom;
400
- break;
401
- case LayoutDirection.bottom:
402
- reverseDirection = LayoutDirection.top;
403
- break;
404
- case LayoutDirection.right:
405
- reverseDirection = LayoutDirection.left;
406
- break;
407
- case LayoutDirection.left:
408
- reverseDirection = LayoutDirection.right;
409
- break;
410
- }
411
- return reverseDirection;
412
- };
413
- const getRootLayout = (root) => {
414
- return root.layout || getDefaultLayout();
415
- };
416
-
417
410
  function enterNodeEditing(element) {
418
411
  const component = ELEMENT_TO_COMPONENT.get(element);
419
412
  component.startEditText(false, false);
@@ -433,22 +426,146 @@ const separateChildren = (parentElement) => {
433
426
  leftChildren.push(child);
434
427
  continue;
435
428
  }
436
- if (i < rightNodeCount) {
437
- 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);
438
552
  }
439
553
  else {
440
- leftChildren.push(child);
554
+ Transforms.setNode(board, { start, end }, path);
441
555
  }
442
- }
443
- return { leftChildren, rightChildren };
444
- };
445
- const isSetAbstract = (element) => {
446
- return !!getCorrespondingAbstract(element);
556
+ });
447
557
  };
448
- const canSetAbstract = (element) => {
449
- 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
+ }
450
567
  };
451
- const setAbstract = (board, elements) => {
568
+ const insertAbstract = (board, elements) => {
452
569
  let elementGroup = filterChildElement(elements);
453
570
  const { parentElements, abstractIncludedGroups } = divideElementByParent(elementGroup);
454
571
  abstractIncludedGroups.forEach((group, index) => {
@@ -478,52 +595,107 @@ const setAbstractByElements = (board, groupParent, group) => {
478
595
  };
479
596
  const insertAbstractNode = (board, path, start, end) => {
480
597
  const mindElement = createMindElement('概要', 28, 20, {
481
- strokeColor: GRAY_COLOR,
482
- branchColor: GRAY_COLOR
598
+ strokeColor: DefaultAbstractNodeStyle.strokeColor,
599
+ strokeWidth: DefaultAbstractNodeStyle.branchWidth,
600
+ branchColor: DefaultAbstractNodeStyle.branchColor,
601
+ branchWidth: DefaultAbstractNodeStyle.branchWidth
483
602
  });
484
603
  mindElement.start = start;
485
604
  mindElement.end = end;
486
605
  Transforms.insertNode(board, mindElement, path);
487
606
  };
488
- const handleAbstractIncluded = (board, element) => {
489
- const rightNodeCount = element.rightNodeCount;
490
- const abstract = element.children.find(child => {
491
- return AbstractNode.isAbstract(child) && child.end >= rightNodeCount && child.start < rightNodeCount;
492
- });
493
- if (abstract) {
494
- const path = PlaitBoard.findPath(board, abstract);
495
- 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);
496
613
  }
614
+ Transforms.setNode(board, { layout }, path);
497
615
  };
498
- const getCorrespondingAbstract = (element) => {
499
- const parent = MindElement.getParent(element);
500
- if (!parent)
501
- return undefined;
502
- const elementIndex = parent.children.indexOf(element);
503
- return parent.children.find(child => {
504
- return AbstractNode.isAbstract(child) && elementIndex >= child.start && elementIndex <= child.end;
505
- });
506
- };
507
- const getBehindAbstracts = (element) => {
508
- const parent = MindElement.getParent(element);
509
- const index = parent.children.indexOf(element);
510
- return parent.children.filter(child => AbstractNode.isAbstract(child) && child.start > index);
616
+ const correctLogicLayoutNode = (board, layout, path) => {
617
+ const node = PlaitNode.get(board, path);
618
+ if (node && layout) {
619
+ node.children?.forEach((value, index) => {
620
+ if (value.layout) {
621
+ if ((isHorizontalLogicLayout(layout) && isVerticalLogicLayout(value.layout)) ||
622
+ (isVerticalLogicLayout(layout) && isHorizontalLogicLayout(value.layout))) {
623
+ Transforms.setNode(board, { layout: null }, [...path, index]);
624
+ }
625
+ if (value.children?.length) {
626
+ correctLogicLayoutNode(board, layout, [...path, index]);
627
+ }
628
+ }
629
+ });
630
+ }
511
631
  };
512
- const insertSiblingElementHandleAbstract = (board, selectedElement) => {
513
- const abstract = getCorrespondingAbstract(selectedElement);
514
- if (abstract) {
515
- PlaitBoard.findPath(board, abstract);
516
- Transforms.setNode(board, { end: abstract.end + 1 }, PlaitBoard.findPath(board, abstract));
632
+
633
+ const setTopic = (board, element, topic, width, height) => {
634
+ const newElement = {
635
+ data: { topic },
636
+ width: width < NODE_MIN_WIDTH * board.viewport.zoom ? NODE_MIN_WIDTH : width / board.viewport.zoom,
637
+ height: height / board.viewport.zoom
638
+ };
639
+ if (MindElement.hasEmojis(element)) {
640
+ newElement.data.emojis = element.data.emojis;
517
641
  }
518
- const abstracts = getBehindAbstracts(selectedElement);
519
- if (abstracts.length) {
520
- moveAbstractPosition(board, abstracts, 1);
642
+ const path = PlaitBoard.findPath(board, element);
643
+ Transforms.setNode(board, newElement, path);
644
+ };
645
+ const setTopicSize = (board, element, width, height) => {
646
+ const newElement = {
647
+ width: width < NODE_MIN_WIDTH * board.viewport.zoom ? NODE_MIN_WIDTH : width / board.viewport.zoom,
648
+ height: height / board.viewport.zoom
649
+ };
650
+ const path = PlaitBoard.findPath(board, element);
651
+ Transforms.setNode(board, newElement, path);
652
+ };
653
+ const addEmoji = (board, element, emojiItem) => {
654
+ const emojis = element.data.emojis || [];
655
+ const newEmojis = [...emojis];
656
+ newEmojis.push(emojiItem);
657
+ const newElement = {
658
+ data: { topic: element.data.topic, emojis: newEmojis }
659
+ };
660
+ const path = PlaitBoard.findPath(board, element);
661
+ Transforms.setNode(board, newElement, path);
662
+ };
663
+ const removeEmoji = (board, element, emojiItem) => {
664
+ const emojis = element.data.emojis.filter(value => value !== emojiItem);
665
+ const newElement = {
666
+ data: { topic: element.data.topic }
667
+ };
668
+ if (emojis.length > 0) {
669
+ newElement.data.emojis = emojis;
521
670
  }
671
+ const path = PlaitBoard.findPath(board, element);
672
+ Transforms.setNode(board, newElement, path);
522
673
  };
523
- const moveAbstractPosition = (board, abstracts, step) => {
524
- abstracts.forEach(abstract => {
525
- Transforms.setNode(board, { start: abstract.start + step, end: abstract.end + step }, PlaitBoard.findPath(board, abstract));
674
+ const replaceEmoji = (board, element, oldEmoji, newEmoji) => {
675
+ const newElement = {
676
+ data: { topic: element.data.topic }
677
+ };
678
+ const newEmojis = element.data.emojis.map(value => {
679
+ if (value === oldEmoji) {
680
+ return newEmoji;
681
+ }
682
+ return value;
526
683
  });
684
+ newElement.data.emojis = newEmojis;
685
+ const path = PlaitBoard.findPath(board, element);
686
+ Transforms.setNode(board, newElement, path);
687
+ };
688
+
689
+ const MindTransforms = {
690
+ setLayout,
691
+ setTopic,
692
+ setTopicSize,
693
+ addEmoji,
694
+ removeEmoji,
695
+ replaceEmoji,
696
+ insertAbstract,
697
+ setAbstractsByRefs,
698
+ setAbstractByStandardLayout
527
699
  };
528
700
 
529
701
  function findParentElement(element) {
@@ -663,13 +835,13 @@ const shouldChangeRightNodeCount = (selectedElement) => {
663
835
  return false;
664
836
  };
665
837
  const createDefaultMindMapElement = (point, rightNodeCount, layout) => {
666
- const root = createMindElement('思维导图', 72, ROOT_DEFAULT_HEIGHT, { shape: MindNodeShape.roundRectangle, layout });
838
+ const root = createMindElement('思维导图', 72, ROOT_DEFAULT_HEIGHT, { shape: MindElementShape.roundRectangle, layout });
667
839
  root.rightNodeCount = rightNodeCount;
668
840
  root.isRoot = true;
669
841
  root.type = 'mindmap';
670
842
  root.points = [point];
671
843
  const children = [1, 1, 1].map(() => {
672
- return createMindElement('新建节点', 56, TEXT_DEFAULT_HEIGHT, { shape: MindNodeShape.roundRectangle });
844
+ return createMindElement('新建节点', 56, TEXT_DEFAULT_HEIGHT, { shape: MindElementShape.roundRectangle });
673
845
  });
674
846
  root.children = children;
675
847
  return root;
@@ -706,11 +878,14 @@ const createMindElement = (text, width, height, options) => {
706
878
  if (options.branchColor) {
707
879
  newElement.branchColor = options.branchColor;
708
880
  }
881
+ if (!isNullOrUndefined(options.branchWidth)) {
882
+ newElement.branchWidth = options.branchWidth;
883
+ }
709
884
  return newElement;
710
885
  };
711
886
  // layoutLevel 用来表示插入兄弟节点还是子节点
712
887
  const insertMindElement = (board, inheritNode, path) => {
713
- let fill, strokeColor, strokeWidth, shape = MindNodeShape.roundRectangle;
888
+ let fill, strokeColor, strokeWidth, shape = MindElementShape.roundRectangle;
714
889
  if (!inheritNode.isRoot) {
715
890
  fill = inheritNode.fill;
716
891
  strokeColor = inheritNode.strokeColor;
@@ -733,63 +908,23 @@ const findLastChild = (child) => {
733
908
  return result;
734
909
  };
735
910
  const deleteSelectedELements = (board, selectedElements) => {
736
- //翻转,从下到上修改,防止找不到 path
737
911
  const deletableElements = filterChildElement(selectedElements).reverse();
738
- const relativeAbstracts = [];
739
- const accumulativeProperties = new WeakMap();
740
- deletableElements.forEach(node => {
741
- if (!PlaitMind.isMind(node)) {
742
- const behindAbstracts = getBehindAbstracts(node).filter(abstract => !deletableElements.includes(abstract));
743
- if (behindAbstracts.length) {
744
- behindAbstracts.forEach(abstract => {
745
- let newProperties = accumulativeProperties.get(abstract);
746
- if (!newProperties) {
747
- newProperties = { start: abstract.start, end: abstract.end };
748
- accumulativeProperties.set(abstract, newProperties);
749
- relativeAbstracts.push(abstract);
750
- }
751
- newProperties.start = newProperties.start - 1;
752
- newProperties.end = newProperties.end - 1;
753
- });
754
- }
755
- const correspondingAbstract = getCorrespondingAbstract(node);
756
- if (correspondingAbstract && !deletableElements.includes(correspondingAbstract)) {
757
- let newProperties = accumulativeProperties.get(correspondingAbstract);
758
- if (!newProperties) {
759
- newProperties = { start: correspondingAbstract.start, end: correspondingAbstract.end };
760
- accumulativeProperties.set(correspondingAbstract, newProperties);
761
- relativeAbstracts.push(correspondingAbstract);
762
- }
763
- newProperties.end = newProperties.end - 1;
764
- }
765
- }
766
- });
767
- const abstractHandles = relativeAbstracts.map(value => {
768
- const newProperties = accumulativeProperties.get(value);
769
- if (newProperties) {
770
- const path = PlaitBoard.findPath(board, value);
771
- return () => {
772
- if (newProperties.start > newProperties.end) {
773
- Transforms.removeNode(board, path);
774
- }
775
- else {
776
- Transforms.setNode(board, newProperties, path);
777
- }
778
- };
779
- }
780
- return () => { };
781
- });
782
- const deletableHandles = deletableElements.map(node => {
783
- const path = PlaitBoard.findPath(board, node);
912
+ const abstractRefs = deleteElementHandleAbstract(board, deletableElements);
913
+ MindTransforms.setAbstractsByRefs(board, abstractRefs);
914
+ //翻转,从下到上修改,防止找不到 path
915
+ deletableElements
916
+ .map(element => {
917
+ const path = PlaitBoard.findPath(board, element);
784
918
  return () => {
785
- if (shouldChangeRightNodeCount(node)) {
786
- changeRightNodeCount(board, path.slice(0, path.length - 1), -1);
919
+ if (shouldChangeRightNodeCount(element)) {
920
+ changeRightNodeCount(board, path.slice(0, 1), -1);
787
921
  }
788
922
  Transforms.removeNode(board, path);
789
923
  };
924
+ })
925
+ .forEach(action => {
926
+ action();
790
927
  });
791
- abstractHandles.forEach(action => action());
792
- deletableHandles.forEach(action => action());
793
928
  };
794
929
  const divideElementByParent = (elements) => {
795
930
  const abstractIncludedGroups = [];
@@ -820,9 +955,12 @@ const getNodeShapeByElement = (element) => {
820
955
  }
821
956
  parent = findParentElement(parent);
822
957
  }
823
- return MindNodeShape.roundRectangle;
958
+ return MindElementShape.roundRectangle;
824
959
  };
825
960
 
961
+ /**
962
+ * Processing of branch color, width, style, etc. of the mind node
963
+ */
826
964
  const getBranchColorByMindElement = (board, element) => {
827
965
  const ancestors = MindElement.getAncestors(board, element);
828
966
  ancestors.unshift(element);
@@ -834,19 +972,40 @@ const getBranchColorByMindElement = (board, element) => {
834
972
  const branch = ancestors[ancestors.length - 2];
835
973
  if (branch) {
836
974
  const index = root.children.indexOf(branch);
837
- const length = COLORS.length;
975
+ const length = BRANCH_COLORS.length;
838
976
  const remainder = index % length;
839
- return COLORS[remainder];
977
+ return BRANCH_COLORS[remainder];
840
978
  }
841
979
  else {
842
980
  throw new Error('root element should not have branch color');
843
981
  }
844
982
  };
983
+ const getBranchWidthByMindElement = (board, element) => {
984
+ const ancestors = MindElement.getAncestors(board, element);
985
+ ancestors.unshift(element);
986
+ const ancestor = ancestors.find(value => value.branchColor);
987
+ if (ancestor && ancestor.branchWidth) {
988
+ return ancestor.branchWidth;
989
+ }
990
+ return BRANCH_WIDTH;
991
+ };
992
+ const getAbstractBranchWidth = (board, element) => {
993
+ if (!isNullOrUndefined(element.branchWidth)) {
994
+ return element.branchWidth;
995
+ }
996
+ return DefaultAbstractNodeStyle.branchWidth;
997
+ };
998
+ const getAbstractBranchColor = (board, element) => {
999
+ if (element.branchColor) {
1000
+ return element.branchColor;
1001
+ }
1002
+ return DefaultAbstractNodeStyle.branchColor;
1003
+ };
845
1004
  const getNextBranchColor = (root) => {
846
1005
  const index = root.children.length;
847
- const length = COLORS.length;
1006
+ const length = BRANCH_COLORS.length;
848
1007
  const remainder = index % length;
849
- return COLORS[remainder];
1008
+ return BRANCH_COLORS[remainder];
850
1009
  };
851
1010
 
852
1011
  const getStrokeByMindElement = (board, element) => {
@@ -860,12 +1019,12 @@ const getStrokeByMindElement = (board, element) => {
860
1019
  const branch = ancestors[ancestors.length - 2];
861
1020
  if (branch) {
862
1021
  const index = root.children.indexOf(branch);
863
- const length = COLORS.length;
1022
+ const length = BRANCH_COLORS.length;
864
1023
  const remainder = index % length;
865
- return COLORS[remainder];
1024
+ return BRANCH_COLORS[remainder];
866
1025
  }
867
1026
  else {
868
- return ROOT_NODE_STROKE;
1027
+ return DefaultRootStyle.strokeColor;
869
1028
  }
870
1029
  };
871
1030
 
@@ -883,7 +1042,7 @@ function isVirtualKey(e) {
883
1042
 
884
1043
  function drawLink(board, node, child, defaultStroke = null, isHorizontal = true, needDrawUnderline = true) {
885
1044
  let beginX, beginY, endX, endY, beginNode = node, endNode = child;
886
- const layout = MindQueries.getCorrectLayoutByElement(node.origin);
1045
+ const layout = MindQueries.getCorrectLayoutByElement(board, node.origin);
887
1046
  if (isHorizontal) {
888
1047
  if (!isChildRight(node, child)) {
889
1048
  beginNode = child;
@@ -895,7 +1054,7 @@ function drawLink(board, node, child, defaultStroke = null, isHorizontal = true,
895
1054
  endY = endNode.y + endNode.height / 2;
896
1055
  if (node.parent &&
897
1056
  isIndentedLayout(MindQueries.getLayoutByElement(node.parent?.origin)) &&
898
- getNodeShapeByElement(node.origin) === MindNodeShape.underline) {
1057
+ getNodeShapeByElement(node.origin) === MindElementShape.underline) {
899
1058
  if (isChildRight(node, child)) {
900
1059
  beginY = node.y + node.height - node.vGap;
901
1060
  }
@@ -970,7 +1129,7 @@ function drawLink(board, node, child, defaultStroke = null, isHorizontal = true,
970
1129
  curve = [...line, ...curve];
971
1130
  }
972
1131
  }
973
- if (needDrawUnderline && shape === MindNodeShape.underline) {
1132
+ if (needDrawUnderline && shape === MindElementShape.underline) {
974
1133
  if (child.left) {
975
1134
  const underline = [
976
1135
  [beginX - (beginNode.width - beginNode.hGap * 2), beginY],
@@ -1046,8 +1205,8 @@ const drawPlaceholderDropNodeG = (board, dropTarget, fakeDropNodeG) => {
1046
1205
  }
1047
1206
  };
1048
1207
  const drawCurvePlaceholderDropNodeG = (board, targetRect, detectResult, targetIndex, targetComponent, parentComponent, fakeDropNodeG) => {
1049
- const parentNodeLayout = MindQueries.getCorrectLayoutByElement(parentComponent.node.origin);
1050
- const layout = MindQueries.getCorrectLayoutByElement(targetComponent.node.parent.origin);
1208
+ const parentNodeLayout = MindQueries.getCorrectLayoutByElement(board, parentComponent.node.origin);
1209
+ const layout = MindQueries.getCorrectLayoutByElement(board, targetComponent.node.parent.origin);
1051
1210
  const strokeWidth = targetComponent.node.origin.branchWidth ? targetComponent.node.origin.branchWidth : STROKE_WIDTH;
1052
1211
  let fakeX = targetComponent.node.x, fakeY = targetRect.y - 30, fakeRectangleStartX = targetRect.x, fakeRectangleEndX = targetRect.x + 30, fakeRectangleStartY = fakeY, fakeRectangleEndY = fakeRectangleStartY + 12, width = 30;
1053
1212
  if (isLeftLayout(layout)) {
@@ -1178,8 +1337,8 @@ const drawStraightDropNodeG = (board, targetRect, detectResult, targetComponent,
1178
1337
  height,
1179
1338
  strokeWidth
1180
1339
  };
1181
- const parentLayout = MindQueries.getCorrectLayoutByElement(targetComponent.node.origin.isRoot ? targetComponent.node.origin : targetComponent.node.parent.origin);
1182
- const layout = MindQueries.getCorrectLayoutByElement(targetComponent.node.origin);
1340
+ const parentLayout = MindQueries.getCorrectLayoutByElement(board, targetComponent.node.origin.isRoot ? targetComponent.node.origin : targetComponent.node.parent.origin);
1341
+ const layout = MindQueries.getCorrectLayoutByElement(board, targetComponent.node.origin);
1183
1342
  if (!isMixedLayout(parentLayout, layout)) {
1184
1343
  // 构造一条直线
1185
1344
  let linePoints = [
@@ -1389,29 +1548,29 @@ const directionDetector = (targetNode, centerPoint) => {
1389
1548
  return null;
1390
1549
  };
1391
1550
 
1392
- const directionCorrector = (node, detectResults) => {
1393
- if (!node.origin.isRoot) {
1394
- const parentlayout = MindQueries.getCorrectLayoutByElement(node?.parent.origin);
1395
- if (isStandardLayout(parentlayout)) {
1551
+ const directionCorrector = (board, node, detectResults) => {
1552
+ if (!node.origin.isRoot && !AbstractNode.isAbstract(node.origin)) {
1553
+ const parentLayout = MindQueries.getCorrectLayoutByElement(board, node?.parent.origin);
1554
+ if (isStandardLayout(parentLayout)) {
1396
1555
  const idx = node.parent.children.findIndex(x => x === node);
1397
1556
  const isLeft = idx >= (node.parent.origin.rightNodeCount || 0);
1398
1557
  return getAllowedDirection(detectResults, [isLeft ? 'right' : 'left']);
1399
1558
  }
1400
- if (isLeftLayout(parentlayout)) {
1559
+ if (isLeftLayout(parentLayout)) {
1401
1560
  return getAllowedDirection(detectResults, ['right']);
1402
1561
  }
1403
- if (isRightLayout(parentlayout)) {
1562
+ if (isRightLayout(parentLayout)) {
1404
1563
  return getAllowedDirection(detectResults, ['left']);
1405
1564
  }
1406
- if (parentlayout === MindLayoutType.upward) {
1565
+ if (parentLayout === MindLayoutType.upward) {
1407
1566
  return getAllowedDirection(detectResults, ['bottom']);
1408
1567
  }
1409
- if (parentlayout === MindLayoutType.downward) {
1568
+ if (parentLayout === MindLayoutType.downward) {
1410
1569
  return getAllowedDirection(detectResults, ['top']);
1411
1570
  }
1412
1571
  }
1413
1572
  else {
1414
- const layout = MindQueries.getCorrectLayoutByElement(node?.origin);
1573
+ const layout = MindQueries.getCorrectLayoutByElement(board, node?.origin);
1415
1574
  if (isStandardLayout(layout)) {
1416
1575
  return getAllowedDirection(detectResults, ['top', 'bottom']);
1417
1576
  }
@@ -1442,17 +1601,18 @@ const getAllowedDirection = (detectResults, illegalDirections) => {
1442
1601
  };
1443
1602
 
1444
1603
  /* 根据布局调整 target 以及 direction */
1445
- const readjustmentDropTarget = (dropTarget) => {
1604
+ const readjustmentDropTarget = (board, dropTarget) => {
1446
1605
  const { target, detectResult } = dropTarget;
1447
1606
  const newDropTarget = { target, detectResult };
1448
1607
  const targetComponent = PlaitElement.getComponent(target);
1449
1608
  if (targetComponent.node.children.length > 0 && dropTarget.detectResult) {
1450
- const layout = MindQueries.getCorrectLayoutByElement(targetComponent.node.origin);
1451
- const parentLayout = MindQueries.getCorrectLayoutByElement(targetComponent.node.origin.isRoot ? targetComponent.node.origin : targetComponent.node.parent.origin);
1609
+ const layout = MindQueries.getCorrectLayoutByElement(board, targetComponent.node.origin);
1610
+ const parentLayout = MindQueries.getCorrectLayoutByElement(board, targetComponent.node.origin.isRoot ? targetComponent.node.origin : targetComponent.node.parent.origin);
1611
+ const children = getNonAbstractChildren(targetComponent.node);
1452
1612
  if (['right', 'left'].includes(dropTarget.detectResult)) {
1453
1613
  if (!isMixedLayout(parentLayout, layout)) {
1454
1614
  if (targetComponent.node.origin.isRoot) {
1455
- const layout = MindQueries.getCorrectLayoutByElement(targetComponent.node.origin);
1615
+ const layout = MindQueries.getCorrectLayoutByElement(board, targetComponent.node.origin);
1456
1616
  // 标准布局,根节点
1457
1617
  if (isStandardLayout(layout)) {
1458
1618
  const rightNodeCount = targetComponent.node.origin.rightNodeCount;
@@ -1486,14 +1646,14 @@ const readjustmentDropTarget = (dropTarget) => {
1486
1646
  return newDropTarget;
1487
1647
  }
1488
1648
  // 剩下是水平布局的默认情况:插入最后一个子节点的下方
1489
- const lastChildNodeIndex = targetComponent.node.children.length - 1;
1649
+ const lastChildNodeIndex = children.length - 1;
1490
1650
  newDropTarget.target = targetComponent.node.children[lastChildNodeIndex].origin;
1491
1651
  newDropTarget.detectResult = 'bottom';
1492
1652
  }
1493
1653
  else {
1494
1654
  // 处理左右布局下的混合布局
1495
1655
  if ([MindLayoutType.left, MindLayoutType.right].includes(parentLayout)) {
1496
- const layout = MindQueries.getCorrectLayoutByElement(targetComponent.node.origin);
1656
+ const layout = MindQueries.getCorrectLayoutByElement(board, targetComponent.node.origin);
1497
1657
  if (isIndentedLayout(layout)) {
1498
1658
  newDropTarget.target = targetComponent.node.children[0].origin;
1499
1659
  newDropTarget.detectResult = isTopLayout(layout) ? 'bottom' : 'top';
@@ -1510,9 +1670,9 @@ const readjustmentDropTarget = (dropTarget) => {
1510
1670
  return newDropTarget;
1511
1671
  }
1512
1672
  // 上下布局,插到右边
1513
- const parentLayout = MindQueries.getCorrectLayoutByElement(targetComponent.node.origin.isRoot ? targetComponent.node.origin : targetComponent.node.parent.origin);
1673
+ const parentLayout = MindQueries.getCorrectLayoutByElement(board, targetComponent.node.origin.isRoot ? targetComponent.node.origin : targetComponent.node.parent.origin);
1514
1674
  if (isVerticalLogicLayout(parentLayout)) {
1515
- const lastChildNodeIndex = targetComponent.node.children.length - 1;
1675
+ const lastChildNodeIndex = children.length - 1;
1516
1676
  newDropTarget.target = targetComponent.node.children[lastChildNodeIndex].origin;
1517
1677
  newDropTarget.detectResult = 'right';
1518
1678
  return newDropTarget;
@@ -1623,7 +1783,7 @@ const getLocationScope = (board, handlePosition, parentChildren, element, parent
1623
1783
  }
1624
1784
  };
1625
1785
  const getHitAbstractHandle = (board, element, point) => {
1626
- const nodeLayout = MindQueries.getCorrectLayoutByElement(element);
1786
+ const nodeLayout = MindQueries.getCorrectLayoutByElement(board, element);
1627
1787
  const isHorizontal = isHorizontalLayout(nodeLayout);
1628
1788
  const parentElement = MindElement.getParent(element);
1629
1789
  const includedElements = parentElement.children.slice(element.start, element.end + 1);
@@ -1710,24 +1870,25 @@ function handleTouchedAbstract(board, touchedAbstract, endPoint) {
1710
1870
  }
1711
1871
 
1712
1872
  function drawIndentedLink(board, node, child, defaultStroke = null, needDrawUnderline = true) {
1713
- const isUnderlineShap = getNodeShapeByElement(child.origin) === MindNodeShape.underline;
1873
+ const branchWidth = getBranchWidthByMindElement(board, child.origin);
1874
+ const branchColor = defaultStroke || getBranchColorByMindElement(board, child.origin);
1875
+ const isUnderlineShape = getNodeShapeByElement(child.origin) === MindElementShape.underline;
1714
1876
  let beginX, beginY, endX, endY, beginNode = node, endNode = child;
1715
1877
  const beginRectangle = getRectangleByNode(beginNode);
1716
1878
  const endRectangle = getRectangleByNode(endNode);
1717
1879
  beginX = beginNode.x + beginNode.width / 2;
1718
1880
  beginY = isChildUp(node, child) ? beginRectangle.y : beginRectangle.y + beginRectangle.height;
1719
1881
  endX = node.left ? endNode.x + endNode.hGap + endRectangle.width : endNode.x + endNode.hGap;
1720
- endY = isUnderlineShap ? endNode.y + endNode.height - endNode.vGap : endNode.y + endNode.height / 2;
1882
+ endY = isUnderlineShape ? endNode.y + endNode.height - endNode.vGap : endNode.y + endNode.height / 2;
1721
1883
  //根据位置,设置正负参数
1722
1884
  let plusMinus = isChildUp(node, child) ? (node.left ? [-1, -1] : [1, -1]) : node.left ? [-1, 1] : [1, 1];
1723
- const layout = MindQueries.getCorrectLayoutByElement(node.origin);
1724
- const strokeWidth = child.origin.branchWidth ? child.origin.branchWidth : STROKE_WIDTH;
1885
+ const layout = MindQueries.getCorrectLayoutByElement(board, node.origin);
1725
1886
  if (beginNode.origin.isRoot) {
1726
1887
  if (layout === MindLayoutType.leftBottomIndented || layout === MindLayoutType.rightBottomIndented) {
1727
- beginY += strokeWidth;
1888
+ beginY += branchWidth;
1728
1889
  }
1729
1890
  if (layout === MindLayoutType.leftTopIndented || layout === MindLayoutType.rightTopIndented) {
1730
- beginY -= strokeWidth;
1891
+ beginY -= branchWidth;
1731
1892
  }
1732
1893
  }
1733
1894
  let curve = [
@@ -1738,13 +1899,12 @@ function drawIndentedLink(board, node, child, defaultStroke = null, needDrawUnde
1738
1899
  [beginX, endY - (endNode.hGap * plusMinus[1]) / 5],
1739
1900
  [beginX + (endNode.hGap * plusMinus[0]) / 4, endY],
1740
1901
  [beginX + (endNode.hGap * plusMinus[0] * 3) / 5, endY],
1741
- isUnderlineShap && needDrawUnderline ? [endX + (endNode.width - endNode.hGap * 2) * plusMinus[0], endY] : [endX, endY],
1742
- isUnderlineShap && needDrawUnderline ? [endX + (endNode.width - endNode.hGap * 2) * plusMinus[0], endY] : [endX, endY],
1743
- isUnderlineShap && needDrawUnderline ? [endX + (endNode.width - endNode.hGap * 2) * plusMinus[0], endY] : [endX, endY]
1902
+ isUnderlineShape && needDrawUnderline ? [endX + (endNode.width - endNode.hGap * 2) * plusMinus[0], endY] : [endX, endY],
1903
+ isUnderlineShape && needDrawUnderline ? [endX + (endNode.width - endNode.hGap * 2) * plusMinus[0], endY] : [endX, endY],
1904
+ isUnderlineShape && needDrawUnderline ? [endX + (endNode.width - endNode.hGap * 2) * plusMinus[0], endY] : [endX, endY]
1744
1905
  ];
1745
- const stroke = defaultStroke || getBranchColorByMindElement(board, child.origin);
1746
1906
  const points = pointsOnBezierCurves(curve);
1747
- return PlaitBoard.getRoughSVG(board).curve(points, { stroke, strokeWidth });
1907
+ return PlaitBoard.getRoughSVG(board).curve(points, { stroke: branchColor, strokeWidth: branchWidth });
1748
1908
  }
1749
1909
 
1750
1910
  var HorizontalPlacement;
@@ -1859,10 +2019,10 @@ const transformPlacement = (placement, direction) => {
1859
2019
 
1860
2020
  function drawLogicLink(board, node, parent, isHorizontal) {
1861
2021
  const branchColor = getBranchColorByMindElement(board, node.origin);
1862
- const strokeWidth = node.origin.branchWidth ? node.origin.branchWidth : STROKE_WIDTH;
2022
+ const branchWidth = getBranchWidthByMindElement(board, node.origin);
1863
2023
  const hasStraightLine = !parent.origin.isRoot;
1864
- const hasUnderlineShape = node.origin.shape === MindNodeShape.underline;
1865
- const hasUnderlineShapeOfParent = parent.origin.shape === MindNodeShape.underline;
2024
+ const hasUnderlineShape = node.origin.shape === MindElementShape.underline;
2025
+ const hasUnderlineShapeOfParent = parent.origin.shape === MindElementShape.underline;
1866
2026
  const nodeClient = getRectangleByNode(node);
1867
2027
  const parentClient = getRectangleByNode(parent);
1868
2028
  const linkDirection = getLayoutDirection(node, isHorizontal);
@@ -1899,7 +2059,7 @@ function drawLogicLink(board, node, parent, isHorizontal) {
1899
2059
  const underlineEnd = movePoint(endPoint, nodeClient.width, linkDirection);
1900
2060
  const underline = hasUnderlineShape && isHorizontal ? [underlineEnd, underlineEnd, underlineEnd] : [];
1901
2061
  const points = pointsOnBezierCurves([...straightLine, ...curve, ...underline]);
1902
- return PlaitBoard.getRoughSVG(board).curve(points, { stroke: branchColor, strokeWidth });
2062
+ return PlaitBoard.getRoughSVG(board).curve(points, { stroke: branchColor, strokeWidth: branchWidth });
1903
2063
  }
1904
2064
 
1905
2065
  function getEmojisRectangle(board, element) {
@@ -2024,9 +2184,9 @@ function getRichtextRectangleByNode(board, node) {
2024
2184
 
2025
2185
  function drawRectangleNode(board, node) {
2026
2186
  const { x, y, width, height } = getRectangleByNode(node);
2027
- const fill = node.origin.fill ? node.origin.fill : node.origin.isRoot ? ROOT_NODE_FILL : NODE_FILL;
2187
+ const fill = node.origin.fill ? node.origin.fill : node.origin.isRoot ? DefaultRootStyle.fill : DefaultNodeStyle.fill;
2028
2188
  const stroke = getStrokeByMindElement(board, node.origin);
2029
- const strokeWidth = node.origin.strokeWidth ? node.origin.strokeWidth : STROKE_WIDTH;
2189
+ const strokeWidth = node.origin.strokeWidth ? node.origin.strokeWidth : DefaultNodeStyle.strokeWidth;
2030
2190
  const nodeG = drawRoundRectangle(PlaitBoard.getRoughSVG(board), x, y, x + width, y + height, {
2031
2191
  stroke,
2032
2192
  strokeWidth,
@@ -2038,6 +2198,8 @@ function drawRectangleNode(board, node) {
2038
2198
 
2039
2199
  function drawAbstractLink(board, node, isHorizontal) {
2040
2200
  const linkPadding = 15;
2201
+ const branchWidth = getAbstractBranchWidth(board, node.origin);
2202
+ const branchColor = getAbstractBranchColor(board, node.origin);
2041
2203
  const parent = node.parent;
2042
2204
  const abstractRectangle = getRectangleByNode(node);
2043
2205
  let includedElements = parent.children.slice(node.origin.start, node.origin.end + 1).map(node => {
@@ -2067,8 +2229,8 @@ function drawAbstractLink(board, node, isHorizontal) {
2067
2229
  let c2 = movePoint(bezierEndPoint, curveDistance, linkDirection);
2068
2230
  let bezierConnectorPoint = movePoint(abstractConnectorPoint, -linkPadding, linkDirection);
2069
2231
  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]}`, {
2070
- stroke: GRAY_COLOR,
2071
- strokeWidth: 2
2232
+ stroke: branchColor,
2233
+ strokeWidth: branchWidth
2072
2234
  });
2073
2235
  return link;
2074
2236
  }
@@ -2123,120 +2285,30 @@ class EmojisDrawer {
2123
2285
  container.classList.add('node-emojis-container');
2124
2286
  foreignObject.append(container);
2125
2287
  this.emojiDrawers = element.data.emojis.map(emojiItem => {
2126
- const drawer = new EmojiDrawer(this.board, this.viewContainerRef);
2127
- drawer.draw(emojiItem, element);
2128
- return drawer;
2129
- });
2130
- this.emojiDrawers.forEach(drawer => {
2131
- container.append(drawer.nativeElement);
2132
- });
2133
- return this.g;
2134
- }
2135
- return undefined;
2136
- }
2137
- destroy() {
2138
- if (this.g) {
2139
- this.g.remove();
2140
- }
2141
- this.emojiDrawers.forEach(drawer => drawer.destroy());
2142
- this.emojiDrawers = [];
2143
- }
2144
- }
2145
-
2146
- const setLayout = (board, layout, path) => {
2147
- correctLogicLayoutNode(board, layout, path);
2148
- const element = PlaitNode.get(board, path);
2149
- if (PlaitMind.isMind(element) && isStandardLayout(layout)) {
2150
- handleAbstractIncluded(board, element);
2151
- }
2152
- Transforms.setNode(board, { layout }, path);
2153
- };
2154
- const correctLogicLayoutNode = (board, layout, path) => {
2155
- const node = PlaitNode.get(board, path);
2156
- if (node && layout) {
2157
- node.children?.forEach((value, index) => {
2158
- if (value.layout) {
2159
- if ((isHorizontalLogicLayout(layout) && isVerticalLogicLayout(value.layout)) ||
2160
- (isVerticalLogicLayout(layout) && isHorizontalLogicLayout(value.layout))) {
2161
- Transforms.setNode(board, { layout: null }, [...path, index]);
2162
- }
2163
- if (value.children?.length) {
2164
- correctLogicLayoutNode(board, layout, [...path, index]);
2165
- }
2166
- }
2167
- });
2168
- }
2169
- };
2170
-
2171
- const setTopic = (board, element, topic, width, height) => {
2172
- const newElement = {
2173
- data: { topic },
2174
- width: width < NODE_MIN_WIDTH * board.viewport.zoom ? NODE_MIN_WIDTH : width / board.viewport.zoom,
2175
- height: height / board.viewport.zoom
2176
- };
2177
- if (MindElement.hasEmojis(element)) {
2178
- newElement.data.emojis = element.data.emojis;
2179
- }
2180
- const path = PlaitBoard.findPath(board, element);
2181
- Transforms.setNode(board, newElement, path);
2182
- };
2183
- const setTopicSize = (board, element, width, height) => {
2184
- const newElement = {
2185
- width: width < NODE_MIN_WIDTH * board.viewport.zoom ? NODE_MIN_WIDTH : width / board.viewport.zoom,
2186
- height: height / board.viewport.zoom
2187
- };
2188
- const path = PlaitBoard.findPath(board, element);
2189
- Transforms.setNode(board, newElement, path);
2190
- };
2191
- const addEmoji = (board, element, emojiItem) => {
2192
- const emojis = element.data.emojis || [];
2193
- const newEmojis = [...emojis];
2194
- newEmojis.push(emojiItem);
2195
- const newElement = {
2196
- data: { topic: element.data.topic, emojis: newEmojis }
2197
- };
2198
- const path = PlaitBoard.findPath(board, element);
2199
- Transforms.setNode(board, newElement, path);
2200
- };
2201
- const removeEmoji = (board, element, emojiItem) => {
2202
- const emojis = element.data.emojis.filter(value => value !== emojiItem);
2203
- const newElement = {
2204
- data: { topic: element.data.topic }
2205
- };
2206
- if (emojis.length > 0) {
2207
- newElement.data.emojis = emojis;
2288
+ const drawer = new EmojiDrawer(this.board, this.viewContainerRef);
2289
+ drawer.draw(emojiItem, element);
2290
+ return drawer;
2291
+ });
2292
+ this.emojiDrawers.forEach(drawer => {
2293
+ container.append(drawer.nativeElement);
2294
+ });
2295
+ return this.g;
2296
+ }
2297
+ return undefined;
2208
2298
  }
2209
- const path = PlaitBoard.findPath(board, element);
2210
- Transforms.setNode(board, newElement, path);
2211
- };
2212
- const replaceEmoji = (board, element, oldEmoji, newEmoji) => {
2213
- const newElement = {
2214
- data: { topic: element.data.topic }
2215
- };
2216
- const newEmojis = element.data.emojis.map(value => {
2217
- if (value === oldEmoji) {
2218
- return newEmoji;
2299
+ destroy() {
2300
+ if (this.g) {
2301
+ this.g.remove();
2219
2302
  }
2220
- return value;
2221
- });
2222
- newElement.data.emojis = newEmojis;
2223
- const path = PlaitBoard.findPath(board, element);
2224
- Transforms.setNode(board, newElement, path);
2225
- };
2226
-
2227
- const MindTransforms = {
2228
- setLayout,
2229
- setTopic,
2230
- setTopicSize,
2231
- addEmoji,
2232
- removeEmoji,
2233
- replaceEmoji
2234
- };
2303
+ this.emojiDrawers.forEach(drawer => drawer.destroy());
2304
+ this.emojiDrawers = [];
2305
+ }
2306
+ }
2235
2307
 
2236
2308
  function drawAbstractIncludedOutline(board, roughSVG, element, activeHandlePosition, resizingLocation) {
2237
2309
  const abstractIncludedG = createG();
2238
2310
  const parentElement = MindElement.getParent(element);
2239
- const nodeLayout = MindQueries.getCorrectLayoutByElement(element);
2311
+ const nodeLayout = MindQueries.getCorrectLayoutByElement(board, element);
2240
2312
  const isHorizontal = isHorizontalLayout(nodeLayout);
2241
2313
  const includedElements = parentElement.children.slice(element.start, element.end + 1);
2242
2314
  let abstractRectangle = getRectangleByElements(board, includedElements, true);
@@ -2316,7 +2388,8 @@ function hasAfterDraw(value) {
2316
2388
  }
2317
2389
 
2318
2390
  function findNewChildNodePath(board, element) {
2319
- return PlaitBoard.findPath(board, element).concat((element.children || []).filter(child => !AbstractNode.isAbstract(child)).length);
2391
+ const children = getNonAbstractChildren(element);
2392
+ return PlaitBoard.findPath(board, element).concat(children.length);
2320
2393
  }
2321
2394
  function findNewSiblingNodePath(board, element) {
2322
2395
  const path = PlaitBoard.findPath(board, element);
@@ -2346,14 +2419,14 @@ class QuickInsertDrawer extends BaseDrawer {
2346
2419
  */
2347
2420
  const shape = getNodeShapeByElement(element);
2348
2421
  // 形状是矩形要偏移边框的线宽
2349
- const strokeWidth = element.branchWidth ? element.branchWidth : STROKE_WIDTH;
2422
+ const branchWidth = getBranchWidthByMindElement(this.board, element);
2350
2423
  let offsetBorderLineWidth = 0;
2351
- if (shape === MindNodeShape.roundRectangle && offset === 0) {
2352
- offsetBorderLineWidth = strokeWidth;
2424
+ if (shape === MindElementShape.roundRectangle && offset === 0) {
2425
+ offsetBorderLineWidth = branchWidth;
2353
2426
  }
2354
2427
  let offsetRootBorderLineWidth = 0;
2355
2428
  if (element.isRoot) {
2356
- offsetRootBorderLineWidth = strokeWidth;
2429
+ offsetRootBorderLineWidth = branchWidth;
2357
2430
  }
2358
2431
  // 当没有子节点时,需要缩小的偏移量
2359
2432
  const extraOffset = 3;
@@ -2448,21 +2521,21 @@ class QuickInsertDrawer extends BaseDrawer {
2448
2521
  offsetRootBorderLineWidth
2449
2522
  }
2450
2523
  };
2451
- if (shape === MindNodeShape.roundRectangle || element.isRoot) {
2524
+ if (shape === MindElementShape.roundRectangle || element.isRoot) {
2452
2525
  underlineCoordinates[MindLayoutType.left].startY -= height * 0.5;
2453
2526
  underlineCoordinates[MindLayoutType.left].endY -= height * 0.5;
2454
2527
  underlineCoordinates[MindLayoutType.right].startY -= height * 0.5;
2455
2528
  underlineCoordinates[MindLayoutType.right].endY -= height * 0.5;
2456
2529
  }
2457
2530
  const branchColor = PlaitMind.isMind(element) ? getNextBranchColor(element) : getBranchColorByMindElement(this.board, element);
2458
- let nodeLayout = MindQueries.getCorrectLayoutByElement(element);
2531
+ let nodeLayout = MindQueries.getCorrectLayoutByElement(this.board, element);
2459
2532
  if (element.isRoot && isStandardLayout(nodeLayout)) {
2460
2533
  const root = element;
2461
2534
  nodeLayout = root.children.length >= root.rightNodeCount ? MindLayoutType.left : MindLayoutType.right;
2462
2535
  }
2463
2536
  const underlineCoordinate = underlineCoordinates[nodeLayout];
2464
2537
  if (underlineCoordinate) {
2465
- const underline = PlaitBoard.getRoughSVG(this.board).line(underlineCoordinate.startX, underlineCoordinate.startY, underlineCoordinate.endX, underlineCoordinate.endY, { stroke: branchColor, strokeWidth });
2538
+ const underline = PlaitBoard.getRoughSVG(this.board).line(underlineCoordinate.startX, underlineCoordinate.startY, underlineCoordinate.endX, underlineCoordinate.endY, { stroke: branchColor, strokeWidth: branchWidth });
2466
2539
  const circleCoordinates = {
2467
2540
  startX: underlineCoordinate.endX,
2468
2541
  startY: underlineCoordinate.endY
@@ -2602,7 +2675,7 @@ class MindNodeComponent extends PlaitPluginElementComponent {
2602
2675
  this.destroyShape();
2603
2676
  const shape = getNodeShapeByElement(this.node.origin);
2604
2677
  switch (shape) {
2605
- case MindNodeShape.roundRectangle:
2678
+ case MindElementShape.roundRectangle:
2606
2679
  this.shapeG = drawRectangleNode(this.board, this.node);
2607
2680
  this.g.prepend(this.shapeG);
2608
2681
  break;
@@ -2789,9 +2862,9 @@ class MindNodeComponent extends PlaitPluginElementComponent {
2789
2862
  });
2790
2863
  const { x, y, width, height } = getRectangleByNode(this.node);
2791
2864
  const stroke = getBranchColorByMindElement(this.board, this.element);
2792
- const strokeWidth = this.node.origin.branchWidth ? this.node.origin.branchWidth : STROKE_WIDTH;
2865
+ const branchWidth = getBranchWidthByMindElement(this.board, this.element);
2793
2866
  const extendY = y + height / 2;
2794
- const nodeLayout = MindQueries.getCorrectLayoutByElement(this.element);
2867
+ const nodeLayout = MindQueries.getCorrectLayoutByElement(this.board, this.element);
2795
2868
  let extendLineXY = [
2796
2869
  [x + width, extendY],
2797
2870
  [x + width + EXTEND_OFFSET, extendY]
@@ -2803,7 +2876,7 @@ class MindNodeComponent extends PlaitPluginElementComponent {
2803
2876
  let circleOffset = [EXTEND_RADIUS / 2, 0];
2804
2877
  if (isHorizontalLayout(nodeLayout) && !isIndentedLayout(nodeLayout)) {
2805
2878
  extendLineYOffset =
2806
- getNodeShapeByElement(this.node.origin) === MindNodeShape.roundRectangle
2879
+ getNodeShapeByElement(this.node.origin) === MindElementShape.roundRectangle
2807
2880
  ? [0, 0]
2808
2881
  : [height / 2, height / 2];
2809
2882
  if (isLeftLayout(nodeLayout)) {
@@ -2835,7 +2908,7 @@ class MindNodeComponent extends PlaitPluginElementComponent {
2835
2908
  [extendLineXY[1][0] + extendLineXOffset[1], extendLineXY[1][1] + extendLineYOffset[1]]
2836
2909
  ];
2837
2910
  const extendLine = this.roughSVG.line(extendLineXY[0][0], extendLineXY[0][1], extendLineXY[1][0], extendLineXY[1][1], {
2838
- strokeWidth,
2911
+ strokeWidth: branchWidth,
2839
2912
  stroke
2840
2913
  });
2841
2914
  //绘制箭头
@@ -2872,7 +2945,7 @@ class MindNodeComponent extends PlaitPluginElementComponent {
2872
2945
  const hideCircleG = this.roughSVG.circle(extendLineXY[1][0] + circleOffset[0], extendLineXY[1][1] + circleOffset[1], EXTEND_RADIUS - 1, {
2873
2946
  fill: '#fff',
2874
2947
  stroke,
2875
- strokeWidth,
2948
+ strokeWidth: branchWidth,
2876
2949
  fillStyle: 'solid'
2877
2950
  });
2878
2951
  collapseG.appendChild(hideCircleG);
@@ -3109,7 +3182,7 @@ const getLayoutOptions = (board) => {
3109
3182
  }
3110
3183
  },
3111
3184
  getVerticalConnectingPosition(element, parent) {
3112
- if (element.shape === MindNodeShape.underline && parent && isHorizontalLogicLayout(parent.layout)) {
3185
+ if (element.shape === MindElementShape.underline && parent && isHorizontalLogicLayout(parent.layout)) {
3113
3186
  return ConnectingPosition.bottom;
3114
3187
  }
3115
3188
  return undefined;
@@ -3178,6 +3251,119 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImpor
3178
3251
  }]
3179
3252
  }] });
3180
3253
 
3254
+ const isValidTarget = (origin, target) => {
3255
+ return origin !== target && !isChildElement(origin, target);
3256
+ };
3257
+ const addActiveOnDragOrigin = (activeElement, isOrigin = true) => {
3258
+ const activeComponent = PlaitElement.getComponent(activeElement);
3259
+ if (isOrigin) {
3260
+ activeComponent.g.classList.add('dragging-origin');
3261
+ }
3262
+ else {
3263
+ activeComponent.g.classList.add('dragging-child');
3264
+ }
3265
+ !activeElement.isCollapsed &&
3266
+ activeElement.children.forEach(child => {
3267
+ addActiveOnDragOrigin(child, false);
3268
+ });
3269
+ };
3270
+ const removeActiveOnDragOrigin = (activeElement, isOrigin = true) => {
3271
+ const activeComponent = PlaitElement.getComponent(activeElement);
3272
+ if (isOrigin) {
3273
+ activeComponent.g.classList.remove('dragging-origin');
3274
+ }
3275
+ else {
3276
+ activeComponent.g.classList.remove('dragging-child');
3277
+ }
3278
+ !activeElement.isCollapsed &&
3279
+ activeElement.children.forEach(child => {
3280
+ removeActiveOnDragOrigin(child, false);
3281
+ });
3282
+ };
3283
+ const updatePathByLayoutAndDropTarget = (targetPath, layout, dropTarget) => {
3284
+ // 上下布局:左右是兄弟节点,上下是子节点
3285
+ if (isVerticalLogicLayout(layout)) {
3286
+ if (isTopLayout(layout) && dropTarget.detectResult === 'top') {
3287
+ targetPath.push(dropTarget.target.children.length);
3288
+ }
3289
+ if (isBottomLayout(layout) && dropTarget.detectResult === 'bottom') {
3290
+ targetPath.push(dropTarget.target.children.length);
3291
+ }
3292
+ // 如果是左,位置不变,右则插入到下一个兄弟节点
3293
+ if (dropTarget.detectResult === 'right') {
3294
+ targetPath = Path.next(targetPath);
3295
+ }
3296
+ }
3297
+ // 水平布局/标准布局:上下是兄弟节点,左右是子节点
3298
+ if (isHorizontalLogicLayout(layout)) {
3299
+ if (dropTarget.detectResult === 'right') {
3300
+ targetPath.push(dropTarget.target.children.length);
3301
+ }
3302
+ if (dropTarget.detectResult === 'left') {
3303
+ targetPath.push(dropTarget.target.children.length);
3304
+ }
3305
+ // 如果是上,位置不变,下插入到下一个兄弟节点
3306
+ if (dropTarget.detectResult === 'bottom') {
3307
+ targetPath = Path.next(targetPath);
3308
+ }
3309
+ }
3310
+ // 缩进布局:上下是兄弟节点,左右是子节点,但上(左上/右上),探测到上是子节点,下则位置不变,反之同理。
3311
+ if (isIndentedLayout(layout)) {
3312
+ if (isTopLayout(layout) && dropTarget.detectResult === 'top') {
3313
+ targetPath = Path.next(targetPath);
3314
+ }
3315
+ if (isBottomLayout(layout) && dropTarget.detectResult === 'bottom') {
3316
+ targetPath = Path.next(targetPath);
3317
+ }
3318
+ if (isLeftLayout(layout) && dropTarget.detectResult === 'left') {
3319
+ targetPath.push(dropTarget.target.children.length);
3320
+ }
3321
+ if (isRightLayout(layout) && dropTarget.detectResult === 'right') {
3322
+ targetPath.push(dropTarget.target.children.length);
3323
+ }
3324
+ }
3325
+ return targetPath;
3326
+ };
3327
+ const updateRightNodeCount = (board, activeComponent, targetComponent, detectResult) => {
3328
+ let rightNodeCount;
3329
+ const mindElement = findUpElement(targetComponent.node.origin).root;
3330
+ const mindComponent = ELEMENT_TO_COMPONENT.get(mindElement);
3331
+ const activeIndex = mindComponent?.root.children.indexOf(activeComponent.node);
3332
+ const targetIndex = mindComponent?.root.children.indexOf(targetComponent.node);
3333
+ const isActiveOnRight = activeIndex !== -1 && activeIndex <= activeComponent.parent.origin.rightNodeCount - 1;
3334
+ const isTargetOnRight = targetComponent.parent && targetIndex !== -1 && targetIndex <= targetComponent.parent.origin.rightNodeCount - 1;
3335
+ const isBothOnRight = isActiveOnRight && isTargetOnRight;
3336
+ const rootChildCount = mindComponent.root.children?.length;
3337
+ const rootRightNodeCount = mindComponent?.root.origin.rightNodeCount;
3338
+ if (!isBothOnRight) {
3339
+ if (isActiveOnRight) {
3340
+ rightNodeCount = rootChildCount < rootRightNodeCount ? rootChildCount - 1 : rootRightNodeCount - 1;
3341
+ Transforms.setNode(board, { rightNodeCount }, PlaitBoard.findPath(board, activeComponent.parent.origin));
3342
+ }
3343
+ if (isTargetOnRight && detectResult !== 'right') {
3344
+ rightNodeCount = rootChildCount < rootRightNodeCount ? rootRightNodeCount : rootRightNodeCount + 1;
3345
+ Transforms.setNode(board, { rightNodeCount }, PlaitBoard.findPath(board, targetComponent.parent.origin));
3346
+ }
3347
+ //二级子节点拖动到根节点左侧
3348
+ if (targetComponent.node.origin.isRoot && detectResult === 'left' && activeIndex === -1) {
3349
+ rightNodeCount = rootChildCount;
3350
+ Transforms.setNode(board, { rightNodeCount }, PlaitBoard.findPath(board, targetComponent.element));
3351
+ }
3352
+ }
3353
+ };
3354
+ const IS_DRAGGING = new WeakMap();
3355
+ const isDragging = (board) => {
3356
+ return !!IS_DRAGGING.get(board);
3357
+ };
3358
+ const setIsDragging = (board, state) => {
3359
+ IS_DRAGGING.set(board, state);
3360
+ };
3361
+ const updateAbstractInDnd = (board, deletableElements, originPath) => {
3362
+ const refs = insertElementHandleAbstract(board, originPath, false);
3363
+ deleteElementHandleAbstract(board, deletableElements, refs);
3364
+ MindTransforms.setAbstractsByRefs(board, refs);
3365
+ };
3366
+
3181
3367
  const DRAG_MOVE_BUFFER = 5;
3182
3368
  const withDnd = (board) => {
3183
3369
  const { mousedown, mousemove, globalMouseup, keydown } = board;
@@ -3279,7 +3465,7 @@ const withDnd = (board) => {
3279
3465
  }
3280
3466
  const directions = directionDetector(node, detectCenterPoint);
3281
3467
  if (directions) {
3282
- detectResult = directionCorrector(node, directions);
3468
+ detectResult = directionCorrector(board, node, directions);
3283
3469
  }
3284
3470
  dropTarget = null;
3285
3471
  if (detectResult && isValidTarget(activeComponent.node.origin, node.origin)) {
@@ -3289,7 +3475,7 @@ const withDnd = (board) => {
3289
3475
  }
3290
3476
  });
3291
3477
  if (dropTarget?.target) {
3292
- dropTarget = readjustmentDropTarget(dropTarget);
3478
+ dropTarget = readjustmentDropTarget(board, dropTarget);
3293
3479
  drawPlaceholderDropNodeG(board, dropTarget, fakeDropNodeG);
3294
3480
  }
3295
3481
  }
@@ -3301,12 +3487,13 @@ const withDnd = (board) => {
3301
3487
  const activeComponent = PlaitElement.getComponent(activeElement);
3302
3488
  const targetComponent = PlaitElement.getComponent(dropTarget.target);
3303
3489
  let targetPath = PlaitBoard.findPath(board, targetComponent.element);
3304
- const mindmapElement = findUpElement(dropTarget.target).root;
3305
- const mindmapComponent = ELEMENT_TO_COMPONENT.get(mindmapElement);
3306
- const layout = MindQueries.getCorrectLayoutByElement(mindmapComponent?.root.origin);
3490
+ const mindElement = findUpElement(dropTarget.target).root;
3491
+ const mindComponent = ELEMENT_TO_COMPONENT.get(mindElement);
3492
+ const layout = MindQueries.getCorrectLayoutByElement(board, mindComponent?.root.origin);
3307
3493
  targetPath = updatePathByLayoutAndDropTarget(targetPath, layout, dropTarget);
3308
3494
  const originPath = PlaitBoard.findPath(board, activeComponent.element);
3309
3495
  let newElement = { isCollapsed: false }, rightTargetPath = PlaitBoard.findPath(board, targetComponent.element);
3496
+ updateAbstractInDnd(board, [activeElement], targetPath);
3310
3497
  if (isStandardLayout(layout)) {
3311
3498
  updateRightNodeCount(board, activeComponent, targetComponent, dropTarget.detectResult);
3312
3499
  }
@@ -3339,124 +3526,51 @@ const withDnd = (board) => {
3339
3526
  };
3340
3527
  return board;
3341
3528
  };
3342
- const isValidTarget = (origin, target) => {
3343
- return origin !== target && !isChildElement(origin, target);
3344
- };
3345
- const addActiveOnDragOrigin = (activeElement, isOrigin = true) => {
3346
- const activeComponent = PlaitElement.getComponent(activeElement);
3347
- if (isOrigin) {
3348
- activeComponent.g.classList.add('dragging-origin');
3349
- }
3350
- else {
3351
- activeComponent.g.classList.add('dragging-child');
3352
- }
3353
- !activeElement.isCollapsed &&
3354
- activeElement.children.forEach(child => {
3355
- addActiveOnDragOrigin(child, false);
3356
- });
3357
- };
3358
- const removeActiveOnDragOrigin = (activeElement, isOrigin = true) => {
3359
- const activeComponent = PlaitElement.getComponent(activeElement);
3360
- if (isOrigin) {
3361
- activeComponent.g.classList.remove('dragging-origin');
3362
- }
3363
- else {
3364
- activeComponent.g.classList.remove('dragging-child');
3365
- }
3366
- !activeElement.isCollapsed &&
3367
- activeElement.children.forEach(child => {
3368
- removeActiveOnDragOrigin(child, false);
3369
- });
3370
- };
3371
- const updatePathByLayoutAndDropTarget = (targetPath, layout, dropTarget) => {
3372
- // 上下布局:左右是兄弟节点,上下是子节点
3373
- if (isVerticalLogicLayout(layout)) {
3374
- if (isTopLayout(layout) && dropTarget.detectResult === 'top') {
3375
- targetPath.push(dropTarget.target.children.length);
3376
- }
3377
- if (isBottomLayout(layout) && dropTarget.detectResult === 'bottom') {
3378
- targetPath.push(dropTarget.target.children.length);
3379
- }
3380
- // 如果是左,位置不变,右则插入到下一个兄弟节点
3381
- if (dropTarget.detectResult === 'right') {
3382
- targetPath = Path.next(targetPath);
3383
- }
3384
- }
3385
- // 水平布局/标准布局:上下是兄弟节点,左右是子节点
3386
- if (isHorizontalLogicLayout(layout)) {
3387
- if (dropTarget.detectResult === 'right') {
3388
- targetPath.push(dropTarget.target.children.length);
3389
- }
3390
- if (dropTarget.detectResult === 'left') {
3391
- targetPath.push(dropTarget.target.children.length);
3392
- }
3393
- // 如果是上,位置不变,下插入到下一个兄弟节点
3394
- if (dropTarget.detectResult === 'bottom') {
3395
- targetPath = Path.next(targetPath);
3396
- }
3397
- }
3398
- // 缩进布局:上下是兄弟节点,左右是子节点,但上(左上/右上),探测到上是子节点,下则位置不变,反之同理。
3399
- if (isIndentedLayout(layout)) {
3400
- if (isTopLayout(layout) && dropTarget.detectResult === 'top') {
3401
- targetPath = Path.next(targetPath);
3402
- }
3403
- if (isBottomLayout(layout) && dropTarget.detectResult === 'bottom') {
3404
- targetPath = Path.next(targetPath);
3405
- }
3406
- if (isLeftLayout(layout) && dropTarget.detectResult === 'left') {
3407
- targetPath.push(dropTarget.target.children.length);
3408
- }
3409
- if (isRightLayout(layout) && dropTarget.detectResult === 'right') {
3410
- targetPath.push(dropTarget.target.children.length);
3411
- }
3412
- }
3413
- return targetPath;
3414
- };
3415
- const updateRightNodeCount = (board, activeComponent, targetComponent, detectResult) => {
3416
- let rightNodeCount;
3417
- const mindmapElement = findUpElement(targetComponent.node.origin).root;
3418
- const mindmapComponent = ELEMENT_TO_COMPONENT.get(mindmapElement);
3419
- const activeIndex = mindmapComponent?.root.children.indexOf(activeComponent.node);
3420
- const targetIndex = mindmapComponent?.root.children.indexOf(targetComponent.node);
3421
- const isActiveOnRight = activeIndex !== -1 && activeIndex <= activeComponent.parent.origin.rightNodeCount - 1;
3422
- const isTargetOnRight = targetComponent.parent && targetIndex !== -1 && targetIndex <= targetComponent.parent.origin.rightNodeCount - 1;
3423
- const isBothOnRight = isActiveOnRight && isTargetOnRight;
3424
- const rootChildCount = mindmapComponent.root.children?.length;
3425
- const rootRightNodeCount = mindmapComponent?.root.origin.rightNodeCount;
3426
- if (!isBothOnRight) {
3427
- if (isActiveOnRight) {
3428
- rightNodeCount = rootChildCount < rootRightNodeCount ? rootChildCount - 1 : rootRightNodeCount - 1;
3429
- Transforms.setNode(board, { rightNodeCount }, PlaitBoard.findPath(board, activeComponent.parent.origin));
3430
- }
3431
- if (isTargetOnRight && detectResult !== 'right') {
3432
- rightNodeCount = rootChildCount < rootRightNodeCount ? rootRightNodeCount : rootRightNodeCount + 1;
3433
- Transforms.setNode(board, { rightNodeCount }, PlaitBoard.findPath(board, targetComponent.parent.origin));
3434
- }
3435
- //二级子节点拖动到根节点左侧
3436
- if (targetComponent.node.origin.isRoot && detectResult === 'left' && activeIndex === -1) {
3437
- rightNodeCount = rootChildCount;
3438
- Transforms.setNode(board, { rightNodeCount }, PlaitBoard.findPath(board, targetComponent.element));
3439
- }
3440
- }
3441
- };
3442
- const IS_DRAGGING = new WeakMap();
3443
- const isDragging = (board) => {
3444
- return !!IS_DRAGGING.get(board);
3445
- };
3446
- const setIsDragging = (board, state) => {
3447
- IS_DRAGGING.set(board, state);
3448
- };
3449
3529
 
3450
3530
  const buildClipboardData = (board, selectedElements) => {
3451
3531
  let result = [];
3452
- const selectedMindNodes = selectedElements.map(value => MindElement.getNode(value));
3453
- const nodesRectangle = getRectangleByElements(board, selectedElements, true);
3454
- selectedElements.forEach((node, index) => {
3532
+ // get overall abstract
3533
+ const overallAbstracts = getOverallAbstracts(board, selectedElements);
3534
+ // keep correct order
3535
+ const newSelectedElements = selectedElements.filter((value) => !overallAbstracts.includes(value));
3536
+ newSelectedElements.push(...overallAbstracts);
3537
+ // get correct start and end in selected elements
3538
+ function getCorrectStartEnd(abstract) {
3539
+ const parent = MindElement.getParent(abstract);
3540
+ const startElement = parent.children[abstract.start];
3541
+ const index = selectedElements.indexOf(startElement);
3542
+ return { start: index, end: index + (abstract.end - abstract.start) };
3543
+ }
3544
+ const selectedMindNodes = newSelectedElements.map(value => MindElement.getNode(value));
3545
+ const nodesRectangle = getRectangleByElements(board, newSelectedElements, true);
3546
+ newSelectedElements.forEach((element, index) => {
3547
+ // handle relative location
3455
3548
  const nodeRectangle = getRectangleByNode(selectedMindNodes[index]);
3456
- result.push({
3457
- ...node,
3458
- points: [[nodeRectangle.x - nodesRectangle.x, nodeRectangle.y - nodesRectangle.y]]
3459
- });
3549
+ const points = [[nodeRectangle.x - nodesRectangle.x, nodeRectangle.y - nodesRectangle.y]];
3550
+ // handle invalid abstract
3551
+ if (AbstractNode.isAbstract(element) && overallAbstracts.includes(element)) {
3552
+ const { start, end } = getCorrectStartEnd(element);
3553
+ result.push({
3554
+ ...element,
3555
+ points,
3556
+ start,
3557
+ end
3558
+ });
3559
+ }
3560
+ else {
3561
+ if (AbstractNode.isAbstract(element)) {
3562
+ let newElement = { ...element, points };
3563
+ delete newElement.start;
3564
+ delete newElement.end;
3565
+ result.push(newElement);
3566
+ }
3567
+ else {
3568
+ result.push({
3569
+ ...element,
3570
+ points: points
3571
+ });
3572
+ }
3573
+ }
3460
3574
  });
3461
3575
  return result;
3462
3576
  };
@@ -3482,17 +3596,22 @@ const insertClipboardData = (board, elements, targetPoint) => {
3482
3596
  let newElement, path;
3483
3597
  const selectedElements = getSelectedElements(board);
3484
3598
  let newELements = [];
3599
+ const hasTargetParent = selectedElements.length === 1;
3600
+ const targetParent = selectedElements[0];
3601
+ const targetParentPath = targetParent && PlaitBoard.findPath(board, targetParent);
3602
+ const nonAbstractChildrenLength = targetParent && getNonAbstractChildren(targetParent).length;
3485
3603
  elements.forEach((item, index) => {
3486
3604
  newElement = copyNewNode(item);
3487
- if (selectedElements.length === 1) {
3605
+ if (hasTargetParent) {
3488
3606
  if (item.isRoot) {
3489
3607
  newElement = transformRootToNode(board, newElement);
3490
3608
  }
3491
- if (AbstractNode.isAbstract(item)) {
3492
- newElement = transformAbstractToNode(newElement);
3609
+ // handle abstract start and end
3610
+ if (AbstractNode.isAbstract(newElement)) {
3611
+ newElement.start = newElement.start + nonAbstractChildrenLength;
3612
+ newElement.end = newElement.end + nonAbstractChildrenLength;
3493
3613
  }
3494
- const selectedElementPath = PlaitBoard.findPath(board, selectedElements[0]);
3495
- path = selectedElementPath.concat((selectedElements[0].children || []).length + index);
3614
+ path = [...targetParentPath, nonAbstractChildrenLength + index];
3496
3615
  }
3497
3616
  else {
3498
3617
  const point = [targetPoint[0] + item.points[0][0], targetPoint[1] + item.points[0][1]];
@@ -3552,7 +3671,7 @@ const withAbstract = (board) => {
3552
3671
  event.preventDefault();
3553
3672
  const abstractComponent = PlaitElement.getComponent(activeAbstractElement);
3554
3673
  const element = abstractComponent.element;
3555
- const nodeLayout = MindQueries.getCorrectLayoutByElement(activeAbstractElement);
3674
+ const nodeLayout = MindQueries.getCorrectLayoutByElement(board, activeAbstractElement);
3556
3675
  const isHorizontal = isHorizontalLayout(nodeLayout);
3557
3676
  const parentElement = MindElement.getParent(element);
3558
3677
  let children = parentElement.children;
@@ -3692,7 +3811,8 @@ const withMind = (board) => {
3692
3811
  if (shouldChangeRightNodeCount(selectedElement)) {
3693
3812
  changeRightNodeCount(board, selectedElementPath.slice(0, 1), 1);
3694
3813
  }
3695
- insertSiblingElementHandleAbstract(board, selectedElement);
3814
+ const abstractRefs = insertElementHandleAbstract(board, Path.next(selectedElementPath));
3815
+ MindTransforms.setAbstractsByRefs(board, abstractRefs);
3696
3816
  insertMindElement(board, selectedElement, findNewSiblingNodePath(board, selectedElement));
3697
3817
  }
3698
3818
  return;
@@ -3838,5 +3958,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImpor
3838
3958
  * Generated bundle index. Do not edit.
3839
3959
  */
3840
3960
 
3841
- 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, withExtendMind, withMind };
3961
+ 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 };
3842
3962
  //# sourceMappingURL=plait-mind.mjs.map