@plait/mind 0.8.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/README.md +132 -13
  2. package/base/base.drawer.d.ts +4 -3
  3. package/constants/default.d.ts +1 -1
  4. package/constants/node-topic-style.d.ts +1 -0
  5. package/drawer/node-active.drawer.d.ts +13 -0
  6. package/drawer/node-collapse.drawer.d.ts +8 -0
  7. package/drawer/{emojis.drawer.d.ts → node-emojis.drawer.d.ts} +1 -1
  8. package/drawer/{quick-insert.drawer.d.ts → node-insert.drawer.d.ts} +2 -2
  9. package/esm2020/base/base.drawer.mjs +13 -1
  10. package/esm2020/constants/default.mjs +2 -2
  11. package/esm2020/constants/node-rule.mjs +1 -1
  12. package/esm2020/constants/node-topic-style.mjs +2 -1
  13. package/esm2020/drawer/node-active.drawer.mjs +43 -0
  14. package/esm2020/drawer/node-collapse.drawer.mjs +108 -0
  15. package/esm2020/drawer/node-emojis.drawer.mjs +72 -0
  16. package/esm2020/drawer/node-insert.drawer.mjs +98 -0
  17. package/esm2020/interfaces/element.mjs +5 -2
  18. package/esm2020/mind.component.mjs +2 -1
  19. package/esm2020/mind.module.mjs +5 -5
  20. package/esm2020/node.component.mjs +57 -424
  21. package/esm2020/plugins/with-abstract-resize.mjs +3 -3
  22. package/esm2020/plugins/with-mind-create.mjs +23 -15
  23. package/esm2020/plugins/with-mind.mjs +9 -8
  24. package/esm2020/plugins/with-node-dnd.mjs +7 -4
  25. package/esm2020/plugins/with-node-hover.mjs +65 -0
  26. package/esm2020/transforms/node.mjs +10 -7
  27. package/esm2020/utils/abstract/resize.mjs +4 -6
  28. package/esm2020/utils/dnd/common.mjs +8 -2
  29. package/esm2020/utils/draw/node-dnd.mjs +3 -3
  30. package/esm2020/utils/mind.mjs +4 -4
  31. package/esm2020/utils/node/adjust-node.mjs +4 -5
  32. package/esm2020/utils/node/common.mjs +3 -3
  33. package/esm2020/utils/node/create-node.mjs +4 -3
  34. package/fesm2015/plait-mind.mjs +567 -857
  35. package/fesm2015/plait-mind.mjs.map +1 -1
  36. package/fesm2020/plait-mind.mjs +567 -845
  37. package/fesm2020/plait-mind.mjs.map +1 -1
  38. package/interfaces/element.d.ts +1 -0
  39. package/mind.module.d.ts +2 -2
  40. package/node.component.d.ts +15 -31
  41. package/package.json +1 -1
  42. package/plugins/with-mind-create.d.ts +3 -5
  43. package/plugins/with-node-dnd.d.ts +1 -1
  44. package/plugins/with-node-hover.d.ts +5 -0
  45. package/styles/mixins.scss +13 -15
  46. package/styles/styles.scss +12 -16
  47. package/utils/abstract/resize.d.ts +2 -2
  48. package/utils/node/common.d.ts +1 -1
  49. package/esm2020/drawer/emojis.drawer.mjs +0 -72
  50. package/esm2020/drawer/quick-insert.drawer.mjs +0 -211
  51. package/esm2020/utils/draw/node-topic.mjs +0 -32
  52. package/utils/draw/node-topic.d.ts +0 -16
@@ -1,55 +1,19 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Component, ChangeDetectionStrategy, NgModule, Directive, Input, HostListener } from '@angular/core';
2
+ import { Component, ChangeDetectionStrategy, NgModule, NgZone, Directive, Input, HostListener } from '@angular/core';
3
3
  import * as i2 from '@plait/core';
4
- import { DefaultThemeColor, ColorfulThemeColor, SoftThemeColor, RetroThemeColor, DarkThemeColor, StarryThemeColor, distanceBetweenPointAndRectangle, RectangleClient, PlaitElement, PlaitBoard, idCreator, isNullOrUndefined, Transforms, clearSelectedElement, addSelectedElement, depthFirstRecursion, Path, drawRoundRectangle, drawLinearPath, createG, updateForeignObject, PlaitNode, getRectangleByElements, getSelectedElements, NODE_TO_PARENT, createForeignObject, drawAbstractRoundRectangle, PlaitPluginElementComponent, PlaitPointerType, NODE_TO_INDEX, createText, IS_TEXT_EDITABLE, MERGING, transformPoint, toPoint, PlaitModule, distanceBetweenPointAndPoint, CLIP_BOARD_FORMAT_KEY, isMainPointer, BOARD_TO_HOST, PlaitPluginKey, throttleRAF, BoardTransforms, removeSelectedElement, PlaitHistoryBoard, hotkeys } from '@plait/core';
4
+ import { DefaultThemeColor, ColorfulThemeColor, SoftThemeColor, RetroThemeColor, DarkThemeColor, StarryThemeColor, RectangleClient, PlaitElement, idCreator, isNullOrUndefined, Transforms, clearSelectedElement, addSelectedElement, PlaitBoard, depthFirstRecursion, Path, drawLinearPath, createG, updateForeignObject, PlaitNode, drawRoundRectangle, getRectangleByElements, getSelectedElements, NODE_TO_PARENT, distanceBetweenPointAndRectangle, createForeignObject, drawAbstractRoundRectangle, createText, PlaitPointerType, PlaitPluginElementComponent, NODE_TO_INDEX, PlaitModule, transformPoint, toPoint, distanceBetweenPointAndPoint, CLIP_BOARD_FORMAT_KEY, isMainPointer, BOARD_TO_HOST, PlaitPluginKey, throttleRAF, BoardTransforms, removeSelectedElement, PlaitHistoryBoard, hotkeys } from '@plait/core';
5
5
  import { MindLayoutType, isIndentedLayout, getNonAbstractChildren, isStandardLayout, AbstractNode, isLeftLayout, isRightLayout, isVerticalLogicLayout, isHorizontalLogicLayout, isTopLayout, isBottomLayout, isHorizontalLayout, getCorrectStartEnd, getAbstractLayout, ConnectingPosition, GlobalLayout } from '@plait/layouts';
6
- import { getSizeByText, ROOT_DEFAULT_HEIGHT, TEXT_DEFAULT_HEIGHT, drawRichtext, updateRichText, setFullSelectionAndFocus, getRichtextContentSize, hasEditableTarget, RichtextModule } from '@plait/richtext';
7
- import { fromEvent, Subject, timer } from 'rxjs';
8
- import { take, takeUntil, filter, debounceTime } from 'rxjs/operators';
9
- import { Node, Path as Path$1, Editor, Operation } from 'slate';
6
+ import { getTextSize, TEXT_DEFAULT_HEIGHT, TextManage, TextModule } from '@plait/text';
7
+ import { fromEvent, Subject } from 'rxjs';
8
+ import { Node, Path as Path$1 } from 'slate';
10
9
  import { isKeyHotkey } from 'is-hotkey';
11
10
  import { pointsOnBezierCurves } from 'points-on-curve';
11
+ import { take, filter } from 'rxjs/operators';
12
12
  import * as i1 from '@angular/common';
13
13
  import { CommonModule } from '@angular/common';
14
14
 
15
15
  const ELEMENT_TO_NODE = new WeakMap();
16
16
 
17
- const BASE = 4;
18
- const PRIMARY_COLOR = '#6698FF';
19
- const TRANSPARENT = 'transparent';
20
- const GRAY_COLOR = '#AAAAAA';
21
- const STROKE_WIDTH = 3;
22
- const BRANCH_WIDTH = 3;
23
- const EXTEND_OFFSET = 8;
24
- const EXTEND_RADIUS = 16;
25
- const QUICK_INSERT_CIRCLE_OFFSET = 9;
26
- const QUICK_INSERT_CIRCLE_COLOR = '#6698FF';
27
- const QUICK_INSERT_INNER_CROSS_COLOR = 'white';
28
-
29
- const DefaultAbstractNodeStyle = {
30
- strokeColor: GRAY_COLOR,
31
- strokeWidth: 2,
32
- branchColor: GRAY_COLOR,
33
- branchWidth: 2
34
- };
35
- const DefaultNodeStyle = {
36
- strokeWidth: 3,
37
- branchWidth: 3,
38
- fill: 'none'
39
- };
40
-
41
- const TOPIC_COLOR = '#333';
42
- const TOPIC_FONT_SIZE = 14;
43
- const ROOT_TOPIC_FONT_SIZE = 18;
44
- const TOPIC_DEFAULT_MAX_WORD_COUNT = 34;
45
-
46
- const NODE_MIN_WIDTH = 18;
47
-
48
- const ABSTRACT_HANDLE_COLOR = '#6698FF80'; //primary color 50% opacity
49
- const ABSTRACT_INCLUDED_OUTLINE_OFFSET = 3.5;
50
- const ABSTRACT_HANDLE_LENGTH = 10;
51
- const ABSTRACT_HANDLE_MASK_WIDTH = 8;
52
-
53
17
  const MindNode = {
54
18
  get(root, path) {
55
19
  let node = root;
@@ -185,36 +149,17 @@ const MindThemeColor = {
185
149
  }
186
150
  };
187
151
 
188
- function getRectangleByNode(node) {
189
- const x = node.x + node.hGap;
190
- let y = node.y + node.vGap;
191
- const width = node.width - node.hGap * 2;
192
- const height = node.height - node.vGap * 2;
193
- return {
194
- x,
195
- y,
196
- width,
197
- height
198
- };
199
- }
200
- function getRectangleByElement(board, originPoint, element) {
201
- const nodeRectangle = {
202
- x: originPoint[0],
203
- y: originPoint[1],
204
- width: NodeSpace.getNodeWidth(board, element),
205
- height: NodeSpace.getNodeHeight(board, element)
206
- };
207
- return nodeRectangle;
208
- }
209
- function isHitMindElement(board, point, element) {
210
- const node = MindElement.getNode(element);
211
- if (node && distanceBetweenPointAndRectangle(point[0], point[1], getRectangleByNode(node)) === 0) {
212
- return true;
213
- }
214
- else {
215
- return false;
216
- }
217
- }
152
+ const BASE = 4;
153
+ const PRIMARY_COLOR = '#6698FF';
154
+ const TRANSPARENT = 'transparent';
155
+ const GRAY_COLOR = '#AAAAAA';
156
+ const STROKE_WIDTH = 3;
157
+ const BRANCH_WIDTH = 3;
158
+ const EXTEND_OFFSET = 8;
159
+ const EXTEND_DIAMETER = 16;
160
+ const QUICK_INSERT_CIRCLE_OFFSET = 9;
161
+ const QUICK_INSERT_CIRCLE_COLOR = '#6698FF';
162
+ const QUICK_INSERT_INNER_CROSS_COLOR = 'white';
218
163
 
219
164
  function getEmojisWidthHeight(board, element) {
220
165
  const options = board.getMindOptions();
@@ -234,6 +179,79 @@ function getEmojiFontSize(element) {
234
179
  }
235
180
  }
236
181
 
182
+ const NodeDefaultSpace = {
183
+ horizontal: {
184
+ nodeAndText: BASE * 3,
185
+ emojiAndText: BASE * 1.5
186
+ },
187
+ vertical: {
188
+ nodeAndText: BASE * 1.5
189
+ }
190
+ };
191
+ const RootDefaultSpace = {
192
+ horizontal: {
193
+ nodeAndText: BASE * 4,
194
+ emojiAndText: BASE * 2
195
+ },
196
+ vertical: {
197
+ nodeAndText: BASE * 2
198
+ }
199
+ };
200
+ const getHorizontalSpaceBetweenNodeAndText = (board, element) => {
201
+ const isMind = PlaitMind.isMind(element);
202
+ const nodeAndText = isMind ? RootDefaultSpace.horizontal.nodeAndText : NodeDefaultSpace.horizontal.nodeAndText;
203
+ return nodeAndText;
204
+ };
205
+ const getVerticalSpaceBetweenNodeAndText = (element) => {
206
+ const isMind = PlaitMind.isMind(element);
207
+ const nodeAndText = isMind ? RootDefaultSpace.vertical.nodeAndText : NodeDefaultSpace.vertical.nodeAndText;
208
+ return nodeAndText;
209
+ };
210
+ const getSpaceEmojiAndText = (element) => {
211
+ const isMind = PlaitMind.isMind(element);
212
+ const emojiAndText = isMind ? RootDefaultSpace.horizontal.emojiAndText : NodeDefaultSpace.horizontal.emojiAndText;
213
+ return emojiAndText;
214
+ };
215
+ const NodeSpace = {
216
+ getNodeWidth(board, element) {
217
+ const nodeAndText = getHorizontalSpaceBetweenNodeAndText(board, element);
218
+ if (MindElement.hasEmojis(element)) {
219
+ return (NodeSpace.getEmojiLeftSpace(board, element) +
220
+ getEmojisWidthHeight(board, element).width +
221
+ getSpaceEmojiAndText(element) +
222
+ element.width +
223
+ nodeAndText);
224
+ }
225
+ return nodeAndText + element.width + nodeAndText;
226
+ },
227
+ getNodeHeight(board, element) {
228
+ const nodeAndText = getVerticalSpaceBetweenNodeAndText(element);
229
+ return nodeAndText + element.height + nodeAndText;
230
+ },
231
+ getTextLeftSpace(board, element) {
232
+ const nodeAndText = getHorizontalSpaceBetweenNodeAndText(board, element);
233
+ if (MindElement.hasEmojis(element)) {
234
+ return NodeSpace.getEmojiLeftSpace(board, element) + getEmojisWidthHeight(board, element).width + getSpaceEmojiAndText(element);
235
+ }
236
+ else {
237
+ return nodeAndText;
238
+ }
239
+ },
240
+ getTextTopSpace(element) {
241
+ const nodeAndText = getVerticalSpaceBetweenNodeAndText(element);
242
+ return nodeAndText;
243
+ },
244
+ getEmojiLeftSpace(board, element) {
245
+ const options = board.getMindOptions();
246
+ const nodeAndText = getHorizontalSpaceBetweenNodeAndText(board, element);
247
+ return nodeAndText - options.emojiPadding;
248
+ },
249
+ getEmojiTopSpace(element) {
250
+ const nodeAndText = getVerticalSpaceBetweenNodeAndText(element);
251
+ return nodeAndText;
252
+ }
253
+ };
254
+
237
255
  function getEmojiRectangle(board, element) {
238
256
  let { x, y } = getRectangleByNode(MindElement.getNode(element));
239
257
  x = x + NodeSpace.getEmojiLeftSpace(board, element);
@@ -260,18 +278,38 @@ const isHitEmojis = (board, element, point) => {
260
278
  return RectangleClient.isHit(RectangleClient.toRectangleClient([point, point]), getEmojiRectangle(board, element));
261
279
  };
262
280
 
263
- function enterNodeEditing(element) {
281
+ function getTopicRectangleByNode(board, node) {
282
+ let nodeRectangle = getRectangleByNode(node);
283
+ return getTopicRectangleByElement(board, nodeRectangle, node.origin);
284
+ }
285
+ function getTopicRectangleByElement(board, nodeRectangle, element) {
286
+ const x = nodeRectangle.x + NodeSpace.getTextLeftSpace(board, element);
287
+ const y = nodeRectangle.y + NodeSpace.getTextTopSpace(element);
288
+ const width = Math.ceil(element.width);
289
+ const height = Math.ceil(element.height);
290
+ return { height, width, x, y };
291
+ }
292
+
293
+ const NODE_MIN_WIDTH = 18;
294
+
295
+ function editTopic(element) {
264
296
  const component = PlaitElement.getComponent(element);
265
- component.startEditText(false, false);
297
+ component.editTopic();
266
298
  }
267
299
 
300
+ const TOPIC_COLOR = '#333';
301
+ const TOPIC_FONT_SIZE = 14;
302
+ const ROOT_TOPIC_FONT_SIZE = 18;
303
+ const ROOT_TOPIC_HEIGHT = 25;
304
+ const TOPIC_DEFAULT_MAX_WORD_COUNT = 34;
305
+
268
306
  const adjustRootToNode = (board, node) => {
269
307
  const newNode = Object.assign({}, node);
270
308
  delete newNode.isRoot;
271
309
  delete newNode.rightNodeCount;
272
310
  delete newNode.type;
273
311
  const text = Node.string(node.data.topic.children[0]) || ' ';
274
- const { width, height } = getSizeByText(text, PlaitBoard.getViewportContainer(board), TOPIC_DEFAULT_MAX_WORD_COUNT);
312
+ const { width, height } = getTextSize(board, text, TOPIC_DEFAULT_MAX_WORD_COUNT);
275
313
  newNode.width = Math.max(width, NODE_MIN_WIDTH);
276
314
  newNode.height = height;
277
315
  if (newNode.layout === MindLayoutType.standard) {
@@ -297,7 +335,7 @@ const adjustNodeToRoot = (board, node) => {
297
335
  newElement === null || newElement === void 0 ? true : delete newElement.fill;
298
336
  newElement === null || newElement === void 0 ? true : delete newElement.shape;
299
337
  newElement === null || newElement === void 0 ? true : delete newElement.strokeWidth;
300
- const { width, height } = getSizeByText(text, PlaitBoard.getViewportContainer(board), TOPIC_DEFAULT_MAX_WORD_COUNT, ROOT_TOPIC_FONT_SIZE);
338
+ const { width, height } = getTextSize(board, text, TOPIC_DEFAULT_MAX_WORD_COUNT, ROOT_TOPIC_FONT_SIZE);
301
339
  newElement.width = Math.max(width, NODE_MIN_WIDTH);
302
340
  newElement.height = height;
303
341
  return Object.assign(Object.assign({}, newElement), { layout: (_a = newElement.layout) !== null && _a !== void 0 ? _a : MindLayoutType.right, isCollapsed: false, isRoot: true, type: 'mindmap' });
@@ -310,7 +348,7 @@ const createEmptyMind = (board, point) => {
310
348
  return rootElement;
311
349
  };
312
350
  const createDefaultMind = (point, rightNodeCount, layout) => {
313
- const root = createMindElement('思维导图', 72, ROOT_DEFAULT_HEIGHT, { layout });
351
+ const root = createMindElement('思维导图', 72, ROOT_TOPIC_HEIGHT, { layout });
314
352
  root.rightNodeCount = rightNodeCount;
315
353
  root.isRoot = true;
316
354
  root.type = 'mindmap';
@@ -417,7 +455,7 @@ const insertMindElement = (board, inheritNode, path) => {
417
455
  clearSelectedElement(board);
418
456
  addSelectedElement(board, newElement);
419
457
  setTimeout(() => {
420
- enterNodeEditing(newElement);
458
+ editTopic(newElement);
421
459
  });
422
460
  };
423
461
  const findLastChild = (child) => {
@@ -547,6 +585,18 @@ const getRootLayout = (root) => {
547
585
  return root.layout || getDefaultLayout();
548
586
  };
549
587
 
588
+ const DefaultAbstractNodeStyle = {
589
+ strokeColor: GRAY_COLOR,
590
+ strokeWidth: 2,
591
+ branchColor: GRAY_COLOR,
592
+ branchWidth: 2
593
+ };
594
+ const DefaultNodeStyle = {
595
+ strokeWidth: 3,
596
+ branchWidth: 3,
597
+ fill: 'none'
598
+ };
599
+
550
600
  const getAvailableProperty = (board, element, propertyKey) => {
551
601
  return element[propertyKey];
552
602
  };
@@ -649,6 +699,12 @@ const isDragging = (board) => {
649
699
  };
650
700
  const setIsDragging = (board, state) => {
651
701
  IS_DRAGGING.set(board, state);
702
+ if (state) {
703
+ PlaitBoard.getBoardNativeElement(board).classList.add('mind-node-dragging');
704
+ }
705
+ else {
706
+ PlaitBoard.getBoardNativeElement(board).classList.remove('mind-node-dragging');
707
+ }
652
708
  };
653
709
  const hasPreviousOrNextOfDropPath = (parent, dropTarget, dropPath) => {
654
710
  let children = getNonAbstractChildren(parent);
@@ -862,23 +918,10 @@ const getPathByDropTarget = (board, dropTarget) => {
862
918
  return targetPath;
863
919
  };
864
920
 
865
- function drawRoundRectangleByNode(board, node) {
866
- const rectangle = getRectangleByNode(node);
867
- return drawRoundRectangleByElement(board, rectangle, node.origin);
868
- }
869
- function drawRoundRectangleByElement(board, nodeRectangle, element) {
870
- const defaultRootFill = getMindThemeColor(board).rootFill;
871
- const fill = element.fill ? element.fill : element.isRoot ? defaultRootFill : DefaultNodeStyle.fill;
872
- const stroke = getStrokeByMindElement(board, element);
873
- const strokeWidth = element.strokeWidth ? element.strokeWidth : DefaultNodeStyle.strokeWidth;
874
- const nodeG = drawRoundRectangle(PlaitBoard.getRoughSVG(board), nodeRectangle.x, nodeRectangle.y, nodeRectangle.x + nodeRectangle.width, nodeRectangle.y + nodeRectangle.height, {
875
- stroke,
876
- strokeWidth,
877
- fill,
878
- fillStyle: 'solid'
879
- });
880
- return nodeG;
881
- }
921
+ const ABSTRACT_HANDLE_COLOR = '#6698FF80'; //primary color 50% opacity
922
+ const ABSTRACT_INCLUDED_OUTLINE_OFFSET = 3.5;
923
+ const ABSTRACT_HANDLE_LENGTH = 10;
924
+ const ABSTRACT_HANDLE_MASK_WIDTH = 8;
882
925
 
883
926
  var HorizontalPlacement;
884
927
  (function (HorizontalPlacement) {
@@ -1127,20 +1170,19 @@ function drawLink(board, parentNode, node, isHorizontal, needDrawUnderline, defa
1127
1170
  }
1128
1171
 
1129
1172
  const drawFakeDragNode = (board, element, offsetX, offsetY) => {
1130
- var _a;
1131
1173
  const activeComponent = PlaitElement.getComponent(element);
1132
1174
  const dragFakeNodeG = createG();
1133
1175
  dragFakeNodeG.classList.add('dragging', 'fake-node', 'plait-board-attached');
1134
1176
  const fakeDraggingNode = Object.assign(Object.assign({}, activeComponent.node), { children: [], x: activeComponent.node.x + offsetX, y: activeComponent.node.y + offsetY });
1135
1177
  const textRectangle = getTopicRectangleByNode(board, activeComponent.node);
1136
1178
  const fakeNodeG = drawRoundRectangleByNode(board, fakeDraggingNode);
1137
- const richtextG = (_a = activeComponent.richtextG) === null || _a === void 0 ? void 0 : _a.cloneNode(true);
1179
+ const richtextG = activeComponent.textManage.g.cloneNode(true);
1138
1180
  updateForeignObject(richtextG, textRectangle.width, textRectangle.height, textRectangle.x + offsetX, textRectangle.y + offsetY);
1139
1181
  dragFakeNodeG === null || dragFakeNodeG === void 0 ? void 0 : dragFakeNodeG.append(fakeNodeG);
1140
1182
  dragFakeNodeG === null || dragFakeNodeG === void 0 ? void 0 : dragFakeNodeG.append(richtextG);
1141
1183
  // draw emojis
1142
1184
  if (MindElement.hasEmojis(element)) {
1143
- const fakeEmojisG = activeComponent.emojisDrawer.g.cloneNode(true);
1185
+ const fakeEmojisG = activeComponent.nodeEmojisDrawer.g.cloneNode(true);
1144
1186
  const foreignRectangle = getEmojiForeignRectangle(board, element);
1145
1187
  updateForeignObject(fakeEmojisG, foreignRectangle.width, foreignRectangle.height, foreignRectangle.x + offsetX, foreignRectangle.y + offsetY);
1146
1188
  dragFakeNodeG === null || dragFakeNodeG === void 0 ? void 0 : dragFakeNodeG.append(fakeEmojisG);
@@ -1581,9 +1623,7 @@ function findLocationLeftIndex(board, parentChildren, location, isHorizontal) {
1581
1623
  }
1582
1624
  function handleTouchedAbstract(board, touchedAbstract, endPoint) {
1583
1625
  let touchedHandle;
1584
- const abstract = getSelectedElements(board)
1585
- .filter(element => AbstractNode.isAbstract(element))
1586
- .find(element => {
1626
+ const abstract = getSelectedElements(board).filter(element => AbstractNode.isAbstract(element)).find(element => {
1587
1627
  touchedHandle = getHitAbstractHandle(board, element, endPoint);
1588
1628
  return touchedHandle;
1589
1629
  });
@@ -1592,13 +1632,13 @@ function handleTouchedAbstract(board, touchedAbstract, endPoint) {
1592
1632
  }
1593
1633
  if (touchedAbstract) {
1594
1634
  const component = PlaitElement.getComponent(touchedAbstract);
1595
- component.updateAbstractIncludedOutline();
1635
+ component.activeDrawer.updateAbstractOutline(touchedAbstract);
1596
1636
  touchedAbstract = undefined;
1597
1637
  }
1598
1638
  if (abstract) {
1599
1639
  touchedAbstract = abstract;
1600
1640
  const component = PlaitElement.getComponent(touchedAbstract);
1601
- component.updateAbstractIncludedOutline(touchedHandle);
1641
+ component.activeDrawer.updateAbstractOutline(touchedAbstract, touchedHandle);
1602
1642
  }
1603
1643
  return touchedAbstract;
1604
1644
  }
@@ -1823,6 +1863,9 @@ const MindElement = {
1823
1863
  },
1824
1864
  getEmojis(element) {
1825
1865
  return element.data.emojis;
1866
+ },
1867
+ getEditor(element) {
1868
+ return PlaitElement.getComponent(element).textManage.componentRef.instance.editor;
1826
1869
  }
1827
1870
  };
1828
1871
  var MindElementShape;
@@ -1836,118 +1879,53 @@ var BranchShape;
1836
1879
  BranchShape["polyline"] = "polyline";
1837
1880
  })(BranchShape || (BranchShape = {}));
1838
1881
 
1839
- const NodeDefaultSpace = {
1840
- horizontal: {
1841
- nodeAndText: BASE * 3,
1842
- emojiAndText: BASE * 1.5
1843
- },
1844
- vertical: {
1845
- nodeAndText: BASE * 1.5
1882
+ function getRectangleByNode(node) {
1883
+ const x = node.x + node.hGap;
1884
+ let y = node.y + node.vGap;
1885
+ const width = node.width - node.hGap * 2;
1886
+ const height = node.height - node.vGap * 2;
1887
+ return {
1888
+ x,
1889
+ y,
1890
+ width,
1891
+ height
1892
+ };
1893
+ }
1894
+ function getRectangleByElement(board, originPoint, element) {
1895
+ const nodeRectangle = {
1896
+ x: originPoint[0],
1897
+ y: originPoint[1],
1898
+ width: NodeSpace.getNodeWidth(board, element),
1899
+ height: NodeSpace.getNodeHeight(board, element)
1900
+ };
1901
+ return nodeRectangle;
1902
+ }
1903
+ function isHitMindElement(board, point, element) {
1904
+ const node = MindElement.getNode(element);
1905
+ if (node && distanceBetweenPointAndRectangle(point[0], point[1], getRectangleByNode(node)) === 0) {
1906
+ return true;
1846
1907
  }
1847
- };
1848
- const RootDefaultSpace = {
1849
- horizontal: {
1850
- nodeAndText: BASE * 4,
1851
- emojiAndText: BASE * 2
1852
- },
1853
- vertical: {
1854
- nodeAndText: BASE * 2
1908
+ else {
1909
+ return false;
1855
1910
  }
1856
- };
1857
- const getHorizontalSpaceBetweenNodeAndText = (board, element) => {
1858
- const isMind = PlaitMind.isMind(element);
1859
- const nodeAndText = isMind ? RootDefaultSpace.horizontal.nodeAndText : NodeDefaultSpace.horizontal.nodeAndText;
1860
- return nodeAndText;
1861
- };
1862
- const getVerticalSpaceBetweenNodeAndText = (element) => {
1863
- const isMind = PlaitMind.isMind(element);
1864
- const nodeAndText = isMind ? RootDefaultSpace.vertical.nodeAndText : NodeDefaultSpace.vertical.nodeAndText;
1865
- return nodeAndText;
1866
- };
1867
- const getSpaceEmojiAndText = (element) => {
1868
- const isMind = PlaitMind.isMind(element);
1869
- const emojiAndText = isMind ? RootDefaultSpace.horizontal.emojiAndText : NodeDefaultSpace.horizontal.emojiAndText;
1870
- return emojiAndText;
1871
- };
1872
- const NodeSpace = {
1873
- getNodeWidth(board, element) {
1874
- const nodeAndText = getHorizontalSpaceBetweenNodeAndText(board, element);
1875
- if (MindElement.hasEmojis(element)) {
1876
- return (NodeSpace.getEmojiLeftSpace(board, element) +
1877
- getEmojisWidthHeight(board, element).width +
1878
- getSpaceEmojiAndText(element) +
1879
- element.width +
1880
- nodeAndText);
1881
- }
1882
- return nodeAndText + element.width + nodeAndText;
1883
- },
1884
- getNodeHeight(board, element) {
1885
- const nodeAndText = getVerticalSpaceBetweenNodeAndText(element);
1886
- return nodeAndText + element.height + nodeAndText;
1887
- },
1888
- getTextLeftSpace(board, element) {
1889
- const nodeAndText = getHorizontalSpaceBetweenNodeAndText(board, element);
1890
- if (MindElement.hasEmojis(element)) {
1891
- return NodeSpace.getEmojiLeftSpace(board, element) + getEmojisWidthHeight(board, element).width + getSpaceEmojiAndText(element);
1892
- }
1893
- else {
1894
- return nodeAndText;
1895
- }
1896
- },
1897
- getTextTopSpace(element) {
1898
- const nodeAndText = getVerticalSpaceBetweenNodeAndText(element);
1899
- return nodeAndText;
1900
- },
1901
- getEmojiLeftSpace(board, element) {
1902
- const options = board.getMindOptions();
1903
- const nodeAndText = getHorizontalSpaceBetweenNodeAndText(board, element);
1904
- return nodeAndText - options.emojiPadding;
1905
- },
1906
- getEmojiTopSpace(element) {
1907
- const nodeAndText = getVerticalSpaceBetweenNodeAndText(element);
1908
- return nodeAndText;
1909
- }
1910
- };
1911
-
1912
- function getTopicRectangleByNode(board, node) {
1913
- let nodeRectangle = getRectangleByNode(node);
1914
- return getTopicRectangleByElement(board, nodeRectangle, node.origin);
1915
- }
1916
- function getTopicRectangleByElement(board, nodeRectangle, element) {
1917
- const x = nodeRectangle.x + NodeSpace.getTextLeftSpace(board, element);
1918
- const y = nodeRectangle.y + NodeSpace.getTextTopSpace(element);
1919
- const width = Math.ceil(element.width);
1920
- const height = Math.ceil(element.height);
1921
- return { height, width, x, y };
1922
1911
  }
1923
1912
 
1924
- function drawTopicByNode(board, node, viewContainerRef) {
1925
- const rectangle = getTopicRectangleByNode(board, node);
1926
- return drawTopicByElement(board, rectangle, node.origin, viewContainerRef);
1927
- }
1928
- function drawTopicByElement(board, rectangle, element, viewContainerRef) {
1929
- const containerRef = viewContainerRef || PlaitBoard.getComponent(board).viewContainerRef;
1930
- const classList = [];
1931
- if (element.isRoot) {
1932
- classList.push('root-node');
1933
- classList.push('font-size-18');
1934
- }
1935
- else {
1936
- classList.push('child-node');
1937
- }
1938
- // COMPAT: last character can not show in safari browser
1939
- return drawRichtext(rectangle.x, rectangle.y, rectangle.width, rectangle.height, element.data.topic, containerRef, classList);
1913
+ function drawRoundRectangleByNode(board, node) {
1914
+ const rectangle = getRectangleByNode(node);
1915
+ return drawRoundRectangleByElement(board, rectangle, node.origin);
1940
1916
  }
1941
- function updateMindNodeTopicSize(board, node, g, isEditable) {
1942
- const { x, y, width, height } = getTopicRectangleByNode(board, node);
1943
- if (isEditable) {
1944
- // add 999, avoid changing lines when paste more text
1945
- updateForeignObject(g, width + 999, height + 999, x, y);
1946
- }
1947
- else {
1948
- // COMPAT: last character can not show in safari browser
1949
- updateForeignObject(g, width, height, x, y);
1950
- }
1917
+ function drawRoundRectangleByElement(board, nodeRectangle, element) {
1918
+ const defaultRootFill = getMindThemeColor(board).rootFill;
1919
+ const fill = element.fill ? element.fill : element.isRoot ? defaultRootFill : DefaultNodeStyle.fill;
1920
+ const stroke = getStrokeByMindElement(board, element);
1921
+ const strokeWidth = element.strokeWidth ? element.strokeWidth : DefaultNodeStyle.strokeWidth;
1922
+ const nodeG = drawRoundRectangle(PlaitBoard.getRoughSVG(board), nodeRectangle.x, nodeRectangle.y, nodeRectangle.x + nodeRectangle.width, nodeRectangle.y + nodeRectangle.height, {
1923
+ stroke,
1924
+ strokeWidth,
1925
+ fill,
1926
+ fillStyle: 'solid'
1927
+ });
1928
+ return nodeG;
1951
1929
  }
1952
1930
 
1953
1931
  function drawAbstractLink(board, node, isHorizontal) {
@@ -2028,7 +2006,7 @@ class EmojiDrawer {
2028
2006
  }
2029
2007
  }
2030
2008
  }
2031
- class EmojisDrawer {
2009
+ class NodeEmojisDrawer {
2032
2010
  constructor(board, viewContainerRef) {
2033
2011
  this.board = board;
2034
2012
  this.viewContainerRef = viewContainerRef;
@@ -2156,12 +2134,13 @@ const correctLogicLayoutNode = (board, layout, path) => {
2156
2134
  }
2157
2135
  };
2158
2136
 
2137
+ const normalizeWidthAndHeight = (board, width, height) => {
2138
+ const newWidth = width < NODE_MIN_WIDTH * board.viewport.zoom ? NODE_MIN_WIDTH : width / board.viewport.zoom;
2139
+ const newHeight = height / board.viewport.zoom;
2140
+ return { width: newWidth, height: newHeight };
2141
+ };
2159
2142
  const setTopic = (board, element, topic, width, height) => {
2160
- const newElement = {
2161
- data: { topic },
2162
- width: width < NODE_MIN_WIDTH * board.viewport.zoom ? NODE_MIN_WIDTH : width / board.viewport.zoom,
2163
- height: height / board.viewport.zoom
2164
- };
2143
+ const newElement = Object.assign({ data: { topic } }, normalizeWidthAndHeight(board, width, height));
2165
2144
  if (MindElement.hasEmojis(element)) {
2166
2145
  newElement.data.emojis = element.data.emojis;
2167
2146
  }
@@ -2169,12 +2148,9 @@ const setTopic = (board, element, topic, width, height) => {
2169
2148
  Transforms.setNode(board, newElement, path);
2170
2149
  };
2171
2150
  const setTopicSize = (board, element, width, height) => {
2172
- const newElement = {
2173
- width: width < NODE_MIN_WIDTH * board.viewport.zoom ? NODE_MIN_WIDTH : width / board.viewport.zoom,
2174
- height: height / board.viewport.zoom
2175
- };
2176
- const path = PlaitBoard.findPath(board, element);
2177
- if (newElement.width !== element.width || newElement.height !== element.height) {
2151
+ const newElement = Object.assign({}, normalizeWidthAndHeight(board, width, height));
2152
+ if (element.width !== newElement.width || element.height !== newElement.height) {
2153
+ const path = PlaitBoard.findPath(board, element);
2178
2154
  Transforms.setNode(board, newElement, path);
2179
2155
  }
2180
2156
  };
@@ -2270,6 +2246,127 @@ const MindTransforms = {
2270
2246
  setRightNodeCountByRefs
2271
2247
  };
2272
2248
 
2249
+ class BaseDrawer {
2250
+ constructor(board) {
2251
+ this.board = board;
2252
+ }
2253
+ draw(element, parentG, data) {
2254
+ this.destroy();
2255
+ if (this.canDraw && this.canDraw(element, data)) {
2256
+ const g = this.baseDraw(element, data);
2257
+ if (g) {
2258
+ parentG.append(g);
2259
+ }
2260
+ if (hasAfterDraw(this)) {
2261
+ this.afterDraw(element);
2262
+ }
2263
+ }
2264
+ }
2265
+ destroy() {
2266
+ if (this.g) {
2267
+ this.g.remove();
2268
+ }
2269
+ }
2270
+ }
2271
+ function hasAfterDraw(value) {
2272
+ if (value.afterDraw) {
2273
+ return true;
2274
+ }
2275
+ return false;
2276
+ }
2277
+
2278
+ function findNewChildNodePath(board, element) {
2279
+ const children = getNonAbstractChildren(element);
2280
+ return PlaitBoard.findPath(board, element).concat(children.length);
2281
+ }
2282
+ function findNewSiblingNodePath(board, element) {
2283
+ const path = PlaitBoard.findPath(board, element);
2284
+ return Path$1.next(path);
2285
+ }
2286
+
2287
+ class NodeInsertDrawer extends BaseDrawer {
2288
+ canDraw(element) {
2289
+ if (PlaitBoard.isReadonly(this.board) || (element === null || element === void 0 ? void 0 : element.isCollapsed)) {
2290
+ return false;
2291
+ }
2292
+ return true;
2293
+ }
2294
+ baseDraw(element) {
2295
+ const quickInsertG = createG();
2296
+ this.g = quickInsertG;
2297
+ quickInsertG.classList.add('quick-insert');
2298
+ const node = MindElement.getNode(element);
2299
+ const layout = MindQueries.getLayoutByElement(element);
2300
+ const isHorizontal = isHorizontalLayout(layout);
2301
+ let linkDirection = getLayoutDirection(node, isHorizontal);
2302
+ if (isIndentedLayout(layout)) {
2303
+ linkDirection = isTopLayout(layout) ? LayoutDirection.top : LayoutDirection.bottom;
2304
+ }
2305
+ const isUnderlineShape = getShapeByElement(this.board, element) === MindElementShape.underline;
2306
+ const nodeClient = getRectangleByNode(node);
2307
+ const branchWidth = getBranchWidthByMindElement(this.board, element);
2308
+ const branchColor = PlaitMind.isMind(element)
2309
+ ? getNextBranchColor(this.board, element)
2310
+ : getBranchColorByMindElement(this.board, element);
2311
+ let distance = 8;
2312
+ let placement = [HorizontalPlacement.right, VerticalPlacement.middle];
2313
+ transformPlacement(placement, linkDirection);
2314
+ // underline shape and horizontal
2315
+ if (isHorizontal && isUnderlineShape && !element.isRoot) {
2316
+ placement[1] = VerticalPlacement.bottom;
2317
+ }
2318
+ let beginPoint = getPointByPlacement(nodeClient, placement);
2319
+ if (element.children.length > 0 && !element.isRoot) {
2320
+ beginPoint = moveXOfPoint(beginPoint, EXTEND_DIAMETER + 8, linkDirection);
2321
+ distance = 5;
2322
+ }
2323
+ const endPoint = moveXOfPoint(beginPoint, distance, linkDirection);
2324
+ const circleCenter = moveXOfPoint(endPoint, 8, linkDirection);
2325
+ const line = PlaitBoard.getRoughSVG(this.board).line(beginPoint[0], beginPoint[1], endPoint[0], endPoint[1], {
2326
+ stroke: branchColor,
2327
+ strokeWidth: branchWidth
2328
+ });
2329
+ const circle = PlaitBoard.getRoughSVG(this.board).circle(circleCenter[0], circleCenter[1], EXTEND_DIAMETER, {
2330
+ fill: QUICK_INSERT_CIRCLE_COLOR,
2331
+ stroke: QUICK_INSERT_CIRCLE_COLOR,
2332
+ fillStyle: 'solid'
2333
+ });
2334
+ const HLineBeginPoint = [circleCenter[0] - 5, circleCenter[1]];
2335
+ const HLineEndPoint = [circleCenter[0] + 5, circleCenter[1]];
2336
+ const VLineBeginPoint = [circleCenter[0], circleCenter[1] - 5];
2337
+ const VLineEndPoint = [circleCenter[0], circleCenter[1] + 5];
2338
+ const innerCrossHLine = PlaitBoard.getRoughSVG(this.board).line(HLineBeginPoint[0], HLineBeginPoint[1], HLineEndPoint[0], HLineEndPoint[1], {
2339
+ stroke: QUICK_INSERT_INNER_CROSS_COLOR,
2340
+ strokeWidth: 2
2341
+ });
2342
+ const innerCrossVLine = PlaitBoard.getRoughSVG(this.board).line(VLineBeginPoint[0], VLineBeginPoint[1], VLineEndPoint[0], VLineEndPoint[1], {
2343
+ stroke: QUICK_INSERT_INNER_CROSS_COLOR,
2344
+ strokeWidth: 2
2345
+ });
2346
+ quickInsertG.appendChild(line);
2347
+ quickInsertG.appendChild(circle);
2348
+ quickInsertG.appendChild(innerCrossHLine);
2349
+ quickInsertG.appendChild(innerCrossVLine);
2350
+ return quickInsertG;
2351
+ }
2352
+ afterDraw(element) {
2353
+ if (!this.g) {
2354
+ throw new Error(`can not find quick insert g`);
2355
+ }
2356
+ fromEvent(this.g, 'mousedown')
2357
+ .pipe(take(1))
2358
+ .subscribe(e => {
2359
+ e.stopPropagation();
2360
+ });
2361
+ fromEvent(this.g, 'mouseup')
2362
+ .pipe(take(1))
2363
+ .subscribe(() => {
2364
+ const path = findNewChildNodePath(this.board, element);
2365
+ insertMindElement(this.board, element, path);
2366
+ });
2367
+ }
2368
+ }
2369
+
2273
2370
  function drawAbstractIncludedOutline(board, roughSVG, element, activeHandlePosition, resizingLocation) {
2274
2371
  const abstractIncludedG = createG();
2275
2372
  const parentElement = MindElement.getParent(element);
@@ -2335,295 +2432,206 @@ function changeBoardClass(board, activeHandlePosition, isHorizontal) {
2335
2432
  }
2336
2433
  }
2337
2434
 
2338
- class BaseDrawer {
2339
- constructor(board) {
2340
- this.board = board;
2435
+ class NodeActiveDrawer extends BaseDrawer {
2436
+ canDraw(element, data) {
2437
+ if (data.selected) {
2438
+ return true;
2439
+ }
2440
+ else {
2441
+ return false;
2442
+ }
2341
2443
  }
2342
- destroy() {
2343
- if (this.g) {
2344
- this.g.remove();
2444
+ baseDraw(element, data) {
2445
+ const activeG = createG();
2446
+ this.g = activeG;
2447
+ if (AbstractNode.isAbstract(element)) {
2448
+ this.abstractOutlineG = drawAbstractIncludedOutline(this.board, PlaitBoard.getRoughSVG(this.board), element);
2449
+ activeG.append(this.abstractOutlineG);
2450
+ }
2451
+ const node = MindElement.getNode(element);
2452
+ let { x, y, width, height } = getRectangleByNode(node);
2453
+ const strokeG = drawRoundRectangle(PlaitBoard.getRoughSVG(this.board), x - 2, y - 2, x + width + 2, y + height + 2, { stroke: PRIMARY_COLOR, strokeWidth: 2, fill: '' }, true);
2454
+ this.g.appendChild(strokeG);
2455
+ if (!data.isEditing) {
2456
+ const fillG = drawRoundRectangle(PlaitBoard.getRoughSVG(this.board), x - 2, y - 2, x + width + 2, y + height + 2, { stroke: PRIMARY_COLOR, fill: PRIMARY_COLOR, fillStyle: 'solid' }, true);
2457
+ fillG.style.opacity = '0.15';
2458
+ this.g.appendChild(fillG);
2345
2459
  }
2460
+ return activeG;
2346
2461
  }
2347
- }
2348
- function hasAfterDraw(value) {
2349
- if (value.afterDraw) {
2350
- return true;
2462
+ updateAbstractOutline(element, activeHandlePosition, resizingLocation) {
2463
+ if (this.abstractOutlineG) {
2464
+ this.abstractOutlineG.remove();
2465
+ }
2466
+ this.abstractOutlineG = drawAbstractIncludedOutline(this.board, PlaitBoard.getRoughSVG(this.board), element, activeHandlePosition, resizingLocation);
2467
+ this.g.append(this.abstractOutlineG);
2351
2468
  }
2352
- return false;
2353
2469
  }
2354
2470
 
2355
- function findNewChildNodePath(board, element) {
2356
- const children = getNonAbstractChildren(element);
2357
- return PlaitBoard.findPath(board, element).concat(children.length);
2358
- }
2359
- function findNewSiblingNodePath(board, element) {
2360
- const path = PlaitBoard.findPath(board, element);
2361
- return Path$1.next(path);
2362
- }
2363
-
2364
- class QuickInsertDrawer extends BaseDrawer {
2471
+ class CollapseDrawer extends BaseDrawer {
2365
2472
  canDraw(element) {
2366
- if (PlaitBoard.isReadonly(this.board) || (element === null || element === void 0 ? void 0 : element.isCollapsed)) {
2367
- return false;
2473
+ if (element.children.length && !PlaitMind.isMind(element)) {
2474
+ return true;
2368
2475
  }
2369
- return true;
2476
+ return false;
2370
2477
  }
2371
- draw(element) {
2372
- let offset = element.children.length > 0 && !element.isRoot ? EXTEND_RADIUS : 0;
2373
- const quickInsertG = createG();
2374
- this.g = quickInsertG;
2375
- quickInsertG.classList.add('quick-insert');
2478
+ baseDraw(element) {
2479
+ const collapseG = createG();
2480
+ this.g = collapseG;
2481
+ collapseG.classList.add('collapse-container');
2376
2482
  const node = MindElement.getNode(element);
2377
- const { x, y, width, height } = getRectangleByNode(node);
2378
- /**
2379
- * 方位:
2380
- * 1. 左、左上、左下
2381
- * 2. 右、右上、右下
2382
- * 3. 上、上左、上右
2383
- * 4. 下、下左、下右
2384
- */
2385
- const shape = getShapeByElement(this.board, element);
2386
- // 形状是矩形要偏移边框的线宽
2483
+ const stroke = getBranchColorByMindElement(this.board, element);
2387
2484
  const branchWidth = getBranchWidthByMindElement(this.board, element);
2388
- let offsetBorderLineWidth = 0;
2389
- if (shape === MindElementShape.roundRectangle && offset === 0) {
2390
- offsetBorderLineWidth = branchWidth;
2485
+ const layout = MindQueries.getLayoutByElement(element);
2486
+ const isUnderlineShape = getShapeByElement(this.board, element) === MindElementShape.underline;
2487
+ const isHorizontal = isHorizontalLayout(layout);
2488
+ const nodeClient = getRectangleByNode(node);
2489
+ let linkDirection = getLayoutDirection(node, isHorizontal);
2490
+ if (isIndentedLayout(layout)) {
2491
+ linkDirection = isTopLayout(layout) ? LayoutDirection.top : LayoutDirection.bottom;
2391
2492
  }
2392
- let offsetRootBorderLineWidth = 0;
2393
- if (element.isRoot) {
2394
- offsetRootBorderLineWidth = branchWidth;
2395
- }
2396
- // 当没有子节点时,需要缩小的偏移量
2397
- const extraOffset = 3;
2398
- const underlineCoordinates = {
2399
- // 画线方向:右向左 <--
2400
- [MindLayoutType.left]: {
2401
- // EXTEND_RADIUS * 0.5 是 左方向,折叠/收起的偏移量
2402
- startX: x - (offset > 0 ? offset + EXTEND_RADIUS * 0.5 : 0) - offsetRootBorderLineWidth,
2403
- startY: y + height,
2404
- endX: x -
2405
- offsetBorderLineWidth -
2406
- offsetRootBorderLineWidth -
2407
- (offset > 0 ? offset + QUICK_INSERT_CIRCLE_OFFSET - extraOffset : 0) -
2408
- EXTEND_RADIUS,
2409
- endY: y + height
2410
- },
2411
- // 画线方向:左向右 -->
2412
- [MindLayoutType.right]: {
2413
- startX: x + width + (offset > 0 ? offset + QUICK_INSERT_CIRCLE_OFFSET : 0) + offsetRootBorderLineWidth,
2414
- startY: y + height,
2415
- endX: x +
2416
- width +
2417
- offsetBorderLineWidth +
2418
- (offset > 0 ? offset + QUICK_INSERT_CIRCLE_OFFSET - extraOffset : 0) +
2419
- EXTEND_RADIUS +
2420
- offsetRootBorderLineWidth,
2421
- endY: y + height
2422
- },
2423
- // 画线方向:下向上 -->
2424
- [MindLayoutType.upward]: {
2425
- startX: x + width * 0.5,
2426
- startY: y - offsetBorderLineWidth - (offset > 0 ? offset + QUICK_INSERT_CIRCLE_OFFSET : 0) - offsetRootBorderLineWidth,
2427
- endX: x + width * 0.5,
2428
- endY: y -
2429
- offsetBorderLineWidth -
2430
- (offset > 0 ? offset + QUICK_INSERT_CIRCLE_OFFSET - extraOffset : 0) -
2431
- EXTEND_RADIUS -
2432
- offsetRootBorderLineWidth
2433
- },
2434
- // 画线方向:上向下 -->
2435
- [MindLayoutType.downward]: {
2436
- startX: x + width * 0.5,
2437
- startY: y + height + offsetBorderLineWidth + (offset > 0 ? offset + QUICK_INSERT_CIRCLE_OFFSET : 0) + offsetRootBorderLineWidth,
2438
- endX: x + width * 0.5,
2439
- endY: y +
2440
- height +
2441
- offsetBorderLineWidth +
2442
- (offset > 0 ? offset + QUICK_INSERT_CIRCLE_OFFSET - extraOffset : 0) +
2443
- EXTEND_RADIUS +
2444
- offsetRootBorderLineWidth
2445
- },
2446
- [MindLayoutType.leftBottomIndented]: {
2447
- startX: x + width * 0.5,
2448
- startY: y + height + offsetBorderLineWidth + (offset > 0 ? offset + QUICK_INSERT_CIRCLE_OFFSET : 0) + offsetRootBorderLineWidth,
2449
- endX: x + width * 0.5,
2450
- endY: y +
2451
- height +
2452
- offsetBorderLineWidth +
2453
- (offset > 0 ? offset + QUICK_INSERT_CIRCLE_OFFSET - extraOffset : 0) +
2454
- EXTEND_RADIUS +
2455
- offsetRootBorderLineWidth
2456
- },
2457
- [MindLayoutType.leftTopIndented]: {
2458
- startX: x + width * 0.5,
2459
- startY: y - offsetBorderLineWidth - (offset > 0 ? offset + QUICK_INSERT_CIRCLE_OFFSET : 0) - offsetRootBorderLineWidth,
2460
- endX: x + width * 0.5,
2461
- endY: y -
2462
- offsetBorderLineWidth -
2463
- (offset > 0 ? offset + QUICK_INSERT_CIRCLE_OFFSET : 0) -
2464
- EXTEND_RADIUS -
2465
- offsetRootBorderLineWidth
2466
- },
2467
- [MindLayoutType.rightBottomIndented]: {
2468
- startX: x + width * 0.5,
2469
- startY: y + height + offsetBorderLineWidth + (offset > 0 ? offset + QUICK_INSERT_CIRCLE_OFFSET : 0) + offsetRootBorderLineWidth,
2470
- endX: x + width * 0.5,
2471
- endY: y +
2472
- height +
2473
- offsetBorderLineWidth +
2474
- (offset > 0 ? offset + QUICK_INSERT_CIRCLE_OFFSET - extraOffset : 0) +
2475
- EXTEND_RADIUS +
2476
- offsetRootBorderLineWidth
2477
- },
2478
- [MindLayoutType.rightTopIndented]: {
2479
- startX: x + width * 0.5,
2480
- startY: y - offsetBorderLineWidth - (offset > 0 ? offset + QUICK_INSERT_CIRCLE_OFFSET : 0) - offsetRootBorderLineWidth,
2481
- endX: x + width * 0.5,
2482
- endY: y -
2483
- offsetBorderLineWidth -
2484
- (offset > 0 ? offset + QUICK_INSERT_CIRCLE_OFFSET : 0) -
2485
- EXTEND_RADIUS -
2486
- offsetRootBorderLineWidth
2487
- }
2488
- };
2489
- if (shape === MindElementShape.roundRectangle || element.isRoot) {
2490
- underlineCoordinates[MindLayoutType.left].startY -= height * 0.5;
2491
- underlineCoordinates[MindLayoutType.left].endY -= height * 0.5;
2492
- underlineCoordinates[MindLayoutType.right].startY -= height * 0.5;
2493
- underlineCoordinates[MindLayoutType.right].endY -= height * 0.5;
2493
+ let placement = [HorizontalPlacement.right, VerticalPlacement.middle];
2494
+ transformPlacement(placement, linkDirection);
2495
+ // underline shape and horizontal
2496
+ if (isHorizontal && isUnderlineShape && !element.isRoot) {
2497
+ placement[1] = VerticalPlacement.bottom;
2494
2498
  }
2495
- const branchColor = PlaitMind.isMind(element)
2496
- ? getNextBranchColor(this.board, element)
2497
- : getBranchColorByMindElement(this.board, element);
2498
- let nodeLayout = MindQueries.getCorrectLayoutByElement(this.board, element);
2499
- if (element.isRoot && isStandardLayout(nodeLayout)) {
2500
- const root = element;
2501
- nodeLayout = root.children.length >= root.rightNodeCount ? MindLayoutType.left : MindLayoutType.right;
2502
- }
2503
- const underlineCoordinate = underlineCoordinates[nodeLayout];
2504
- if (underlineCoordinate) {
2505
- const underline = PlaitBoard.getRoughSVG(this.board).line(underlineCoordinate.startX, underlineCoordinate.startY, underlineCoordinate.endX, underlineCoordinate.endY, { stroke: branchColor, strokeWidth: branchWidth });
2506
- const circleCoordinates = {
2507
- startX: underlineCoordinate.endX,
2508
- startY: underlineCoordinate.endY
2509
- };
2510
- const circle = PlaitBoard.getRoughSVG(this.board).circle(circleCoordinates.startX, circleCoordinates.startY, EXTEND_RADIUS, {
2511
- fill: QUICK_INSERT_CIRCLE_COLOR,
2512
- stroke: QUICK_INSERT_CIRCLE_COLOR,
2513
- fillStyle: 'solid'
2514
- });
2515
- const innerCrossCoordinates = {
2516
- horizontal: {
2517
- startX: circleCoordinates.startX - EXTEND_RADIUS * 0.5 + 3,
2518
- startY: circleCoordinates.startY,
2519
- endX: circleCoordinates.startX + EXTEND_RADIUS * 0.5 - 3,
2520
- endY: circleCoordinates.startY
2521
- },
2522
- vertical: {
2523
- startX: circleCoordinates.startX,
2524
- startY: circleCoordinates.startY - EXTEND_RADIUS * 0.5 + 3,
2525
- endX: circleCoordinates.startX,
2526
- endY: circleCoordinates.startY + EXTEND_RADIUS * 0.5 - 3
2527
- }
2528
- };
2529
- const innerCrossHLine = PlaitBoard.getRoughSVG(this.board).line(innerCrossCoordinates.horizontal.startX, innerCrossCoordinates.horizontal.startY, innerCrossCoordinates.horizontal.endX, innerCrossCoordinates.horizontal.endY, {
2530
- stroke: QUICK_INSERT_INNER_CROSS_COLOR,
2531
- strokeWidth: 2
2532
- });
2533
- const innerRingVLine = PlaitBoard.getRoughSVG(this.board).line(innerCrossCoordinates.vertical.startX, innerCrossCoordinates.vertical.startY, innerCrossCoordinates.vertical.endX, innerCrossCoordinates.vertical.endY, {
2534
- stroke: QUICK_INSERT_INNER_CROSS_COLOR,
2535
- strokeWidth: 2
2536
- });
2537
- quickInsertG.appendChild(underline);
2538
- quickInsertG.appendChild(circle);
2539
- quickInsertG.appendChild(innerCrossHLine);
2540
- quickInsertG.appendChild(innerRingVLine);
2499
+ let startPoint = getPointByPlacement(nodeClient, placement);
2500
+ const endPoint = moveXOfPoint(startPoint, EXTEND_OFFSET, linkDirection);
2501
+ const circleCenter = moveXOfPoint(endPoint, EXTEND_DIAMETER / 2, linkDirection);
2502
+ const arrowPoints = this.getArrowPoints(circleCenter, linkDirection);
2503
+ const arrowLine = drawLinearPath(arrowPoints, {
2504
+ stroke,
2505
+ strokeWidth: 2
2506
+ });
2507
+ const extendLine = PlaitBoard.getRoughSVG(this.board).line(startPoint[0], startPoint[1], endPoint[0], endPoint[1], {
2508
+ strokeWidth: branchWidth,
2509
+ stroke
2510
+ });
2511
+ const badge = PlaitBoard.getRoughSVG(this.board).circle(circleCenter[0], circleCenter[1], EXTEND_DIAMETER, {
2512
+ fill: stroke,
2513
+ stroke,
2514
+ fillStyle: 'solid'
2515
+ });
2516
+ const hideCircleG = PlaitBoard.getRoughSVG(this.board).circle(circleCenter[0], circleCenter[1], EXTEND_DIAMETER, {
2517
+ fill: '#fff',
2518
+ stroke,
2519
+ strokeWidth: branchWidth > 3 ? 3 : branchWidth,
2520
+ fillStyle: 'solid'
2521
+ });
2522
+ if (element.isCollapsed) {
2523
+ let numberOffset = 0;
2524
+ if (getChildrenCount(element) >= 10)
2525
+ numberOffset = -2;
2526
+ if (getChildrenCount(element) === 1)
2527
+ numberOffset = 1;
2528
+ const badgeText = createText(circleCenter[0] - 4 + numberOffset, circleCenter[1] + 4, stroke, `${getChildrenCount(element)}`);
2529
+ badge.setAttribute('style', 'opacity: 0.15');
2530
+ badgeText.setAttribute('style', 'font-size: 12px');
2531
+ collapseG.appendChild(badge);
2532
+ collapseG.appendChild(badgeText);
2533
+ collapseG.appendChild(extendLine);
2541
2534
  }
2542
- return quickInsertG;
2535
+ else {
2536
+ collapseG.appendChild(hideCircleG);
2537
+ collapseG.appendChild(arrowLine);
2538
+ }
2539
+ collapseG.appendChild(extendLine);
2540
+ return collapseG;
2543
2541
  }
2544
2542
  afterDraw(element) {
2545
2543
  if (!this.g) {
2546
2544
  throw new Error(`can not find quick insert g`);
2547
2545
  }
2548
- fromEvent(this.g, 'mousedown')
2549
- .pipe(take(1))
2550
- .subscribe(e => {
2551
- e.stopPropagation();
2552
- });
2553
2546
  fromEvent(this.g, 'mouseup')
2554
- .pipe(take(1))
2547
+ .pipe(filter(() => !PlaitBoard.isPointer(this.board, PlaitPointerType.hand) || !!PlaitBoard.isReadonly(this.board)), take(1))
2555
2548
  .subscribe(() => {
2556
- const path = findNewChildNodePath(this.board, element);
2557
- insertMindElement(this.board, element, path);
2549
+ const isCollapsed = !element.isCollapsed;
2550
+ const newElement = { isCollapsed };
2551
+ const path = PlaitBoard.findPath(this.board, element);
2552
+ Transforms.setNode(this.board, newElement, path);
2558
2553
  });
2559
2554
  }
2555
+ getArrowPoints(circleCenter, linkDirection) {
2556
+ let arrowTopPoint = moveXOfPoint(circleCenter, 2, linkDirection);
2557
+ arrowTopPoint = moveYOfPoint(arrowTopPoint, 4, linkDirection);
2558
+ const arrowMiddlePoint = moveXOfPoint(circleCenter, -2, linkDirection);
2559
+ let arrowBottomPoint = moveXOfPoint(circleCenter, 2, linkDirection);
2560
+ arrowBottomPoint = moveYOfPoint(arrowBottomPoint, -4, linkDirection);
2561
+ return [arrowTopPoint, arrowMiddlePoint, arrowBottomPoint];
2562
+ }
2560
2563
  }
2561
2564
 
2562
2565
  class MindNodeComponent extends PlaitPluginElementComponent {
2563
- get handActive() {
2564
- return this.board.pointer === PlaitPointerType.hand;
2565
- }
2566
- constructor(viewContainerRef, cdr, render2, ngZone) {
2566
+ constructor(viewContainerRef, cdr) {
2567
2567
  super(cdr);
2568
2568
  this.viewContainerRef = viewContainerRef;
2569
2569
  this.cdr = cdr;
2570
- this.render2 = render2;
2571
- this.ngZone = ngZone;
2572
- this.isEditable = false;
2573
- this.activeG = [];
2574
2570
  this.shapeG = null;
2575
2571
  this.destroy$ = new Subject();
2576
2572
  this.trackBy = (index, node) => {
2577
2573
  return node.origin.id;
2578
2574
  };
2579
2575
  }
2576
+ initializeDrawer() {
2577
+ this.nodeEmojisDrawer = new NodeEmojisDrawer(this.board, this.viewContainerRef);
2578
+ this.nodeInsertDrawer = new NodeInsertDrawer(this.board);
2579
+ this.activeDrawer = new NodeActiveDrawer(this.board);
2580
+ this.collapseDrawer = new CollapseDrawer(this.board);
2581
+ this.textManage = new TextManage(this.board, this.viewContainerRef, () => {
2582
+ return getTopicRectangleByNode(this.board, this.node);
2583
+ }, (point) => {
2584
+ return isHitMindElement(this.board, point, this.element);
2585
+ }, (textManageRef) => {
2586
+ const width = textManageRef.width;
2587
+ const height = textManageRef.height;
2588
+ if (textManageRef.newValue) {
2589
+ MindTransforms.setTopic(this.board, this.element, textManageRef.newValue, width, height);
2590
+ }
2591
+ else {
2592
+ MindTransforms.setTopicSize(this.board, this.element, width, height);
2593
+ }
2594
+ });
2595
+ }
2580
2596
  ngOnInit() {
2581
- this.emojisDrawer = new EmojisDrawer(this.board, this.viewContainerRef);
2582
- this.quickInsertDrawer = new QuickInsertDrawer(this.board);
2583
2597
  super.ngOnInit();
2598
+ this.initializeDrawer();
2584
2599
  this.node = MindElement.getNode(this.element);
2585
2600
  this.index = NODE_TO_INDEX.get(this.element) || 0;
2586
2601
  this.roughSVG = PlaitBoard.getRoughSVG(this.board);
2587
2602
  this.parentG = PlaitElement.getComponent(MindElement.getRoot(this.board, this.element)).rootG;
2588
2603
  this.drawShape();
2589
2604
  this.drawLink();
2590
- this.drawRichtext();
2591
- this.drawActiveG();
2592
- this.updateActiveClass();
2593
- this.drawMaskG();
2605
+ this.drawText();
2606
+ this.activeDrawer.draw(this.element, this.g, { selected: this.selected, isEditing: this.textManage.isEditing });
2594
2607
  this.drawEmojis();
2595
2608
  this.drawExtend();
2596
- this.drawQuickInsert();
2609
+ }
2610
+ editTopic() {
2611
+ this.activeDrawer.draw(this.element, this.g, { selected: this.selected, isEditing: true });
2612
+ this.textManage.edit(() => {
2613
+ this.activeDrawer.draw(this.element, this.g, { selected: this.selected, isEditing: false });
2614
+ });
2597
2615
  }
2598
2616
  onContextChanged(value, previous) {
2599
- var _a, _b;
2600
2617
  const newNode = MindElement.getNode(value.element);
2601
- // resolve move node richtext lose issue
2602
- if (this.node !== newNode) {
2603
- if (this.foreignObject && this.foreignObject.children.length <= 0) {
2604
- (_a = this.foreignObject) === null || _a === void 0 ? void 0 : _a.appendChild((_b = this.richtextComponentRef) === null || _b === void 0 ? void 0 : _b.instance.editable);
2605
- }
2606
- }
2607
2618
  const isEqualNode = RectangleClient.isEqual(this.node, newNode);
2608
2619
  this.node = newNode;
2609
2620
  const isChangeTheme = this.board.operations.find(op => op.type === 'set_theme');
2610
2621
  if (!isEqualNode || value.element !== previous.element || isChangeTheme) {
2611
- this.drawActiveG();
2612
- this.updateActiveClass();
2622
+ this.activeDrawer.draw(this.element, this.g, { selected: this.selected, isEditing: this.textManage.isEditing });
2613
2623
  this.drawShape();
2614
2624
  this.drawLink();
2615
- this.updateRichtext();
2616
- this.drawMaskG();
2617
- this.drawExtend();
2618
- this.drawQuickInsert();
2619
2625
  this.drawEmojis();
2626
+ this.drawExtend();
2627
+ this.textManage.updateText(this.element.data.topic);
2628
+ this.textManage.updateRectangle();
2620
2629
  }
2621
2630
  else {
2622
2631
  const hasSameSelected = value.selected === previous.selected;
2623
2632
  const hasSameParent = value.parent === previous.parent;
2624
2633
  if (!hasSameSelected) {
2625
- this.drawActiveG();
2626
- this.updateActiveClass();
2634
+ this.activeDrawer.draw(this.element, this.g, { selected: this.selected, isEditing: this.textManage.isEditing });
2627
2635
  }
2628
2636
  if (!hasSameParent) {
2629
2637
  this.drawLink();
@@ -2631,22 +2639,11 @@ class MindNodeComponent extends PlaitPluginElementComponent {
2631
2639
  }
2632
2640
  }
2633
2641
  drawEmojis() {
2634
- const g = this.emojisDrawer.drawEmojis(this.element);
2642
+ const g = this.nodeEmojisDrawer.drawEmojis(this.element);
2635
2643
  if (g) {
2636
2644
  this.g.append(g);
2637
2645
  }
2638
2646
  }
2639
- drawQuickInsert() {
2640
- var _a;
2641
- this.quickInsertDrawer.destroy();
2642
- if (this.quickInsertDrawer.canDraw(this.element)) {
2643
- const g = this.quickInsertDrawer.draw(this.element);
2644
- if (hasAfterDraw(this.quickInsertDrawer)) {
2645
- this.quickInsertDrawer.afterDraw(this.element);
2646
- }
2647
- (_a = this.extendG) === null || _a === void 0 ? void 0 : _a.appendChild(g);
2648
- }
2649
- }
2650
2647
  drawShape() {
2651
2648
  this.destroyShape();
2652
2649
  const shape = getShapeByElement(this.board, this.node.origin);
@@ -2688,393 +2685,33 @@ class MindNodeComponent extends PlaitPluginElementComponent {
2688
2685
  this.linkG.remove();
2689
2686
  }
2690
2687
  }
2691
- drawMaskG() {
2692
- this.destroyMaskG();
2693
- const lineWidthOffset = 2;
2694
- const extendOffset = 15;
2695
- const nodeLayout = MindQueries.getLayoutByElement(this.node.origin);
2696
- const isTop = isTopLayout(nodeLayout);
2697
- const isRight = isRightLayout(nodeLayout);
2698
- const isBottom = isBottomLayout(nodeLayout);
2699
- const isLeft = isLeftLayout(nodeLayout);
2700
- const { x, y, width, height } = getRectangleByNode(this.node);
2701
- let drawX = x;
2702
- let drawY = y;
2703
- let drawWidth = x + width;
2704
- let drawHeight = y + height;
2705
- switch (true) {
2706
- case isTop:
2707
- drawX = x - lineWidthOffset;
2708
- drawY = y - extendOffset;
2709
- drawWidth = x + width + lineWidthOffset;
2710
- drawHeight = y + height + lineWidthOffset;
2711
- break;
2712
- case isBottom:
2713
- drawX = x - lineWidthOffset;
2714
- drawY = y - lineWidthOffset;
2715
- drawWidth = x + width + lineWidthOffset;
2716
- drawHeight = y + height + extendOffset;
2717
- break;
2718
- case isLeft:
2719
- drawX = x - extendOffset;
2720
- drawY = y - lineWidthOffset;
2721
- drawWidth = x + width + lineWidthOffset;
2722
- drawHeight = y + height + lineWidthOffset;
2723
- break;
2724
- case isRight:
2725
- drawX = x - lineWidthOffset;
2726
- drawY = y - lineWidthOffset;
2727
- drawWidth = x + width + extendOffset;
2728
- drawHeight = y + height + lineWidthOffset;
2729
- break;
2730
- }
2731
- this.maskG = drawRoundRectangle(this.roughSVG, drawX, drawY, drawWidth, drawHeight, { stroke: 'none', fill: 'rgba(255,255,255,0)', fillStyle: 'solid' }, true);
2732
- this.maskG.classList.add('mask');
2733
- this.maskG.setAttribute('visibility', 'visible');
2734
- this.g.append(this.maskG);
2735
- if (this.isEditable) {
2736
- this.disabledMaskG();
2737
- }
2738
- fromEvent(this.maskG, 'mouseenter')
2739
- .pipe(takeUntil(this.destroy$), filter(() => {
2740
- return PlaitBoard.isFocus(this.board) && !this.element.isCollapsed && !this.handActive;
2741
- }))
2742
- .subscribe(() => {
2743
- this.g.classList.add('hovered');
2744
- });
2745
- fromEvent(this.maskG, 'mouseleave')
2746
- .pipe(takeUntil(this.destroy$), filter(() => {
2747
- return PlaitBoard.isFocus(this.board) && !this.element.isCollapsed;
2748
- }))
2749
- .subscribe(() => {
2750
- this.g.classList.remove('hovered');
2751
- });
2752
- }
2753
- destroyMaskG() {
2754
- if (this.maskG) {
2755
- this.maskG.remove();
2756
- this.g.classList.remove('hovered');
2757
- }
2758
- }
2759
- enableMaskG() {
2760
- if (this.maskG) {
2761
- this.maskG.setAttribute('visibility', 'visible');
2762
- }
2763
- }
2764
- disabledMaskG() {
2765
- if (this.maskG) {
2766
- this.maskG.setAttribute('visibility', 'hidden');
2767
- }
2768
- }
2769
- drawActiveG() {
2770
- var _a, _b;
2771
- this.destroyActiveG();
2772
- (_a = this.abstractIncludedOutlineG) === null || _a === void 0 ? void 0 : _a.remove();
2773
- if (this.selected) {
2774
- if (AbstractNode.isAbstract(this.element)) {
2775
- this.updateAbstractIncludedOutline();
2776
- }
2777
- let { x, y, width, height } = getRectangleByNode(this.node);
2778
- const selectedStrokeG = drawRoundRectangle(this.roughSVG, x - 2, y - 2, x + width + 2, y + height + 2, { stroke: PRIMARY_COLOR, strokeWidth: 2, fill: '' }, true);
2779
- // 影响 mask 移入移出事件
2780
- selectedStrokeG.style.pointerEvents = 'none';
2781
- this.g.appendChild(selectedStrokeG);
2782
- this.activeG.push(selectedStrokeG);
2783
- if (((_b = this.richtextComponentRef) === null || _b === void 0 ? void 0 : _b.instance.plaitReadonly) === true) {
2784
- const selectedBackgroundG = drawRoundRectangle(this.roughSVG, x - 2, y - 2, x + width + 2, y + height + 2, { stroke: PRIMARY_COLOR, fill: PRIMARY_COLOR, fillStyle: 'solid' }, true);
2785
- selectedBackgroundG.style.opacity = '0.15';
2786
- // 影响双击事件
2787
- selectedBackgroundG.style.pointerEvents = 'none';
2788
- this.g.appendChild(selectedBackgroundG);
2789
- this.activeG.push(selectedBackgroundG, selectedStrokeG);
2790
- }
2791
- }
2792
- }
2793
- destroyActiveG() {
2794
- this.activeG.forEach(g => g.remove());
2795
- this.activeG = [];
2796
- }
2797
- updateActiveClass() {
2798
- if (!this.g) {
2799
- return;
2800
- }
2801
- if (this.selected) {
2802
- this.render2.addClass(this.g, 'active');
2803
- }
2804
- else {
2805
- this.render2.removeClass(this.g, 'active');
2806
- }
2807
- }
2808
- drawRichtext() {
2809
- const { richtextG, richtextComponentRef, foreignObject } = drawTopicByNode(this.board, this.node, this.viewContainerRef);
2810
- this.richtextComponentRef = richtextComponentRef;
2811
- this.richtextG = richtextG;
2812
- this.foreignObject = foreignObject;
2813
- this.render2.addClass(richtextG, 'richtext');
2814
- this.g.append(richtextG);
2815
- }
2816
2688
  drawExtend() {
2817
2689
  this.destroyExtend();
2818
- // create extend
2819
2690
  this.extendG = createG();
2820
- const collapseG = createG();
2821
2691
  this.extendG.classList.add('extend');
2822
- collapseG.classList.add('collapse-container');
2823
2692
  this.g.append(this.extendG);
2824
- this.extendG.append(collapseG);
2825
- if (this.node.origin.isRoot) {
2826
- return;
2827
- }
2828
- // interactive
2829
- fromEvent(collapseG, 'mouseup')
2830
- .pipe(filter(() => !this.handActive || !!PlaitBoard.isReadonly(this.board)), take(1))
2831
- .subscribe(() => {
2832
- const isCollapsed = !this.node.origin.isCollapsed;
2833
- const newElement = { isCollapsed };
2834
- const path = PlaitBoard.findPath(this.board, this.element);
2835
- Transforms.setNode(this.board, newElement, path);
2836
- });
2837
- const { x, y, width, height } = getRectangleByNode(this.node);
2838
- const stroke = getBranchColorByMindElement(this.board, this.element);
2839
- const branchWidth = getBranchWidthByMindElement(this.board, this.element);
2840
- const extendY = y + height / 2;
2841
- const nodeLayout = MindQueries.getCorrectLayoutByElement(this.board, this.element);
2842
- let extendLineXY = [
2843
- [x + width, extendY],
2844
- [x + width + EXTEND_OFFSET, extendY]
2845
- ];
2846
- let arrowYOffset = [-4, 1, -0.6, 4];
2847
- let arrowXOffset = [10, 5.5, 5.5, 10];
2848
- let extendLineXOffset = [0, 0];
2849
- let extendLineYOffset = [0, 0];
2850
- let circleOffset = [EXTEND_RADIUS / 2, 0];
2851
- if (isHorizontalLayout(nodeLayout) && !isIndentedLayout(nodeLayout)) {
2852
- extendLineYOffset =
2853
- getShapeByElement(this.board, this.node.origin) === MindElementShape.roundRectangle
2854
- ? [0, 0]
2855
- : [height / 2, height / 2];
2856
- if (isLeftLayout(nodeLayout)) {
2857
- //左
2858
- extendLineXOffset = [-width, -width - EXTEND_OFFSET * 2];
2859
- circleOffset = [-EXTEND_RADIUS / 2, 0];
2860
- arrowXOffset = [-10, -5.5, -5.5, -10];
2861
- }
2862
- }
2863
- else {
2864
- arrowXOffset = [-4, 0.6, -1, 4];
2865
- if (isTopLayout(nodeLayout)) {
2866
- //上
2867
- extendLineXOffset = [-width / 2, -width / 2 - EXTEND_OFFSET];
2868
- extendLineYOffset = [-height / 2, -height / 2 - EXTEND_OFFSET];
2869
- arrowYOffset = [-10, -5.5, -5.5, -10];
2870
- circleOffset = [0, -EXTEND_RADIUS / 2];
2871
- }
2872
- else {
2873
- //下
2874
- extendLineXOffset = [-width / 2, -width / 2 - EXTEND_OFFSET];
2875
- extendLineYOffset = [height / 2, height / 2 + EXTEND_OFFSET];
2876
- arrowYOffset = [10, 5.5, 5.5, 10];
2877
- circleOffset = [0, EXTEND_RADIUS / 2];
2878
- }
2879
- }
2880
- extendLineXY = [
2881
- [extendLineXY[0][0] + extendLineXOffset[0], extendLineXY[0][1] + extendLineYOffset[0]],
2882
- [extendLineXY[1][0] + extendLineXOffset[1], extendLineXY[1][1] + extendLineYOffset[1]]
2883
- ];
2884
- const extendLine = this.roughSVG.line(extendLineXY[0][0], extendLineXY[0][1], extendLineXY[1][0], extendLineXY[1][1], {
2885
- strokeWidth: branchWidth,
2886
- stroke
2887
- });
2888
- //绘制箭头
2889
- const hideArrowTopLine = this.roughSVG.line(extendLineXY[1][0] + arrowXOffset[0], extendLineXY[1][1] + arrowYOffset[0], extendLineXY[1][0] + arrowXOffset[1], extendLineXY[1][1] + arrowYOffset[1], {
2890
- stroke,
2891
- strokeWidth: 2
2892
- });
2893
- const hideArrowBottomLine = this.roughSVG.line(extendLineXY[1][0] + arrowXOffset[2], extendLineXY[1][1] + arrowYOffset[2], extendLineXY[1][0] + arrowXOffset[3], extendLineXY[1][1] + arrowYOffset[3], {
2894
- stroke,
2895
- strokeWidth: 2
2896
- });
2897
- if (this.node.origin.isCollapsed) {
2898
- const badge = this.roughSVG.circle(extendLineXY[1][0] + circleOffset[0], extendLineXY[1][1] + circleOffset[1], EXTEND_RADIUS, {
2899
- fill: stroke,
2900
- stroke,
2901
- fillStyle: 'solid'
2902
- });
2903
- let numberOffset = 0;
2904
- if (getChildrenCount(this.node.origin) >= 10)
2905
- numberOffset = -2;
2906
- if (getChildrenCount(this.node.origin) === 1)
2907
- numberOffset = 1;
2908
- const badgeText = createText(extendLineXY[1][0] + circleOffset[0] - 4 + numberOffset, extendLineXY[1][1] + circleOffset[1] + 4, stroke, `${getChildrenCount(this.node.origin)}`);
2693
+ if (this.element.isCollapsed) {
2909
2694
  this.g.classList.add('collapsed');
2910
- badge.setAttribute('style', 'opacity: 0.15');
2911
- badgeText.setAttribute('style', 'font-size: 12px');
2912
- collapseG.appendChild(badge);
2913
- collapseG.appendChild(badgeText);
2914
- collapseG.appendChild(extendLine);
2915
2695
  }
2916
2696
  else {
2917
2697
  this.g.classList.remove('collapsed');
2918
- if (this.node.origin.children.length > 0) {
2919
- const hideCircleG = this.roughSVG.circle(extendLineXY[1][0] + circleOffset[0], extendLineXY[1][1] + circleOffset[1], EXTEND_RADIUS - 1, {
2920
- fill: '#fff',
2921
- stroke,
2922
- strokeWidth: branchWidth > 3 ? 3 : branchWidth,
2923
- fillStyle: 'solid'
2924
- });
2925
- collapseG.appendChild(hideCircleG);
2926
- collapseG.appendChild(hideArrowTopLine);
2927
- collapseG.appendChild(hideArrowBottomLine);
2928
- }
2929
2698
  }
2699
+ this.nodeInsertDrawer.draw(this.element, this.extendG);
2700
+ this.collapseDrawer.draw(this.element, this.extendG);
2930
2701
  }
2931
2702
  destroyExtend() {
2932
2703
  if (this.extendG) {
2933
2704
  this.extendG.remove();
2934
2705
  }
2935
2706
  }
2936
- destroyRichtext() {
2937
- if (this.richtextG) {
2938
- this.richtextG.remove();
2939
- }
2940
- if (this.richtextComponentRef) {
2941
- this.richtextComponentRef.destroy();
2942
- }
2943
- }
2944
- updateAbstractIncludedOutline(activeHandlePosition, resizingLocation) {
2945
- var _a;
2946
- (_a = this.abstractIncludedOutlineG) === null || _a === void 0 ? void 0 : _a.remove();
2947
- this.abstractIncludedOutlineG = drawAbstractIncludedOutline(this.board, this.roughSVG, this.element, activeHandlePosition, resizingLocation);
2948
- PlaitBoard.getHost(this.board).append(this.abstractIncludedOutlineG);
2949
- }
2950
- updateRichtext() {
2951
- updateRichText(this.node.origin.data.topic, this.richtextComponentRef);
2952
- updateMindNodeTopicSize(this.board, this.node, this.richtextG, this.isEditable);
2953
- }
2954
- startEditText(isEnd, isClear) {
2955
- if (!this.richtextComponentRef) {
2956
- throw new Error('undefined richtextComponentRef');
2957
- }
2958
- const richtextInstance = this.richtextComponentRef.instance;
2959
- this.isEditable = true;
2960
- IS_TEXT_EDITABLE.set(this.board, true);
2961
- this.disabledMaskG();
2962
- updateMindNodeTopicSize(this.board, this.node, this.richtextG, this.isEditable);
2963
- if (richtextInstance.plaitReadonly) {
2964
- richtextInstance.plaitReadonly = false;
2965
- this.richtextComponentRef.changeDetectorRef.detectChanges();
2966
- this.drawActiveG();
2967
- const location = isEnd ? Editor.end(richtextInstance.editor, [0]) : [0];
2968
- setFullSelectionAndFocus(richtextInstance.editor, location);
2969
- if (isClear) {
2970
- Editor.deleteBackward(richtextInstance.editor);
2971
- }
2972
- // handle invalid width and height (old data)
2973
- let { width, height } = getRichtextContentSize(richtextInstance.editable);
2974
- if (width !== this.element.width || height !== this.element.height) {
2975
- MindTransforms.setTopicSize(this.board, this.element, width, height);
2976
- }
2977
- }
2978
- let richtext = richtextInstance.plaitValue;
2979
- // use debounceTime to wait DOM render complete
2980
- const valueChange$ = richtextInstance.plaitChange
2981
- .pipe(debounceTime(0), filter(event => {
2982
- // 过滤掉 operations 中全是 set_selection 的操作
2983
- return !event.operations.every(op => Operation.isSelectionOperation(op));
2984
- }))
2985
- .subscribe(event => {
2986
- if (richtext === event.value) {
2987
- return;
2988
- }
2989
- this.updateRichtext();
2990
- // 更新富文本、更新宽高
2991
- let { width, height } = getRichtextContentSize(richtextInstance.editable);
2992
- MindTransforms.setTopic(this.board, this.element, event.value, width, height);
2993
- MERGING.set(this.board, true);
2994
- });
2995
- const composition$ = richtextInstance.plaitComposition.pipe(debounceTime(0)).subscribe(event => {
2996
- let { width, height } = getRichtextContentSize(richtextInstance.editable);
2997
- if (width < NODE_MIN_WIDTH) {
2998
- width = NODE_MIN_WIDTH;
2999
- }
3000
- if (event.isComposing && (width !== this.node.origin.width || height !== this.node.origin.height)) {
3001
- const newElement = {
3002
- width: width / this.board.viewport.zoom,
3003
- height: height / this.board.viewport.zoom
3004
- };
3005
- const path = PlaitBoard.findPath(this.board, this.element);
3006
- Transforms.setNode(this.board, newElement, path);
3007
- MERGING.set(this.board, true);
3008
- }
3009
- });
3010
- const mousedown$ = fromEvent(document, 'mousedown').subscribe((event) => {
3011
- const point = transformPoint(this.board, toPoint(event.x, event.y, PlaitBoard.getHost(this.board)));
3012
- const clickInNode = isHitMindElement(this.board, point, this.element);
3013
- if (clickInNode && !hasEditableTarget(richtextInstance.editor, event.target)) {
3014
- event.preventDefault();
3015
- }
3016
- else if (!clickInNode) {
3017
- // handle composition input state, like: Chinese IME Composition Input
3018
- timer(0).subscribe(() => {
3019
- exitHandle();
3020
- this.enableMaskG();
3021
- });
3022
- }
3023
- });
3024
- const editor = richtextInstance.editor;
3025
- const { keydown } = editor;
3026
- editor.keydown = (event) => {
3027
- if (event.isComposing) {
3028
- return;
3029
- }
3030
- if (event.key === 'Escape') {
3031
- event.preventDefault();
3032
- event.stopPropagation();
3033
- exitHandle();
3034
- this.drawActiveG();
3035
- this.enableMaskG();
3036
- return;
3037
- }
3038
- if (event.key === 'Enter' && !event.shiftKey) {
3039
- event.preventDefault();
3040
- event.stopPropagation();
3041
- exitHandle();
3042
- this.drawActiveG();
3043
- this.enableMaskG();
3044
- return;
3045
- }
3046
- if (event.key === 'Tab') {
3047
- event.preventDefault();
3048
- event.stopPropagation();
3049
- exitHandle();
3050
- this.drawActiveG();
3051
- this.drawMaskG();
3052
- }
3053
- };
3054
- const exitHandle = () => {
3055
- this.ngZone.run(() => {
3056
- var _a;
3057
- // unsubscribe
3058
- valueChange$.unsubscribe();
3059
- composition$.unsubscribe();
3060
- mousedown$.unsubscribe();
3061
- editor.keydown = keydown; // reset keydown
3062
- // editable status
3063
- MERGING.set(this.board, false);
3064
- richtextInstance.plaitReadonly = true;
3065
- (_a = this.richtextComponentRef) === null || _a === void 0 ? void 0 : _a.changeDetectorRef.markForCheck();
3066
- this.isEditable = false;
3067
- updateMindNodeTopicSize(this.board, this.node, this.richtextG, this.isEditable);
3068
- IS_TEXT_EDITABLE.set(this.board, false);
3069
- });
3070
- };
2707
+ drawText() {
2708
+ this.textManage.draw(this.element.data.topic);
2709
+ this.g.append(this.textManage.g);
3071
2710
  }
3072
2711
  ngOnDestroy() {
3073
- var _a;
3074
2712
  super.ngOnDestroy();
3075
- (_a = this.abstractIncludedOutlineG) === null || _a === void 0 ? void 0 : _a.remove();
3076
- this.destroyRichtext();
3077
- this.emojisDrawer.destroy();
2713
+ this.textManage.destroy();
2714
+ this.nodeEmojisDrawer.destroy();
3078
2715
  this.destroy$.next();
3079
2716
  this.destroy$.complete();
3080
2717
  if (ELEMENT_TO_NODE.get(this.element) === this.node) {
@@ -3082,7 +2719,7 @@ class MindNodeComponent extends PlaitPluginElementComponent {
3082
2719
  }
3083
2720
  }
3084
2721
  }
3085
- MindNodeComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.5", ngImport: i0, type: MindNodeComponent, deps: [{ token: i0.ViewContainerRef }, { token: i0.ChangeDetectorRef }, { token: i0.Renderer2 }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component });
2722
+ MindNodeComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.5", ngImport: i0, type: MindNodeComponent, deps: [{ token: i0.ViewContainerRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
3086
2723
  MindNodeComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.5", type: MindNodeComponent, selector: "plait-mind-node", usesInheritance: true, ngImport: i0, template: `
3087
2724
  <plait-children
3088
2725
  *ngIf="!element.isCollapsed"
@@ -3107,7 +2744,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImpor
3107
2744
  `,
3108
2745
  changeDetection: ChangeDetectionStrategy.OnPush
3109
2746
  }]
3110
- }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }, { type: i0.ChangeDetectorRef }, { type: i0.Renderer2 }, { type: i0.NgZone }]; } });
2747
+ }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }, { type: i0.ChangeDetectorRef }]; } });
3111
2748
 
3112
2749
  const getLayoutOptions = (board) => {
3113
2750
  function getMainAxle(element, parent) {
@@ -3180,6 +2817,7 @@ class PlaitMindComponent extends MindNodeComponent {
3180
2817
  ngOnInit() {
3181
2818
  this.updateMindLayout();
3182
2819
  super.ngOnInit();
2820
+ this.g.classList.add('root');
3183
2821
  }
3184
2822
  beforeContextChange(value) {
3185
2823
  if (value.element !== this.element && this.initialized) {
@@ -3220,19 +2858,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImpor
3220
2858
  class MindModule {
3221
2859
  }
3222
2860
  MindModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.5", ngImport: i0, type: MindModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
3223
- MindModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.5", ngImport: i0, type: MindModule, declarations: [PlaitMindComponent, MindNodeComponent], imports: [CommonModule, RichtextModule, PlaitModule], exports: [PlaitMindComponent, MindNodeComponent] });
3224
- MindModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.5", ngImport: i0, type: MindModule, imports: [CommonModule, RichtextModule, PlaitModule] });
2861
+ MindModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "15.2.5", ngImport: i0, type: MindModule, declarations: [PlaitMindComponent, MindNodeComponent], imports: [CommonModule, TextModule, PlaitModule], exports: [PlaitMindComponent, MindNodeComponent] });
2862
+ MindModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "15.2.5", ngImport: i0, type: MindModule, imports: [CommonModule, TextModule, PlaitModule] });
3225
2863
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImport: i0, type: MindModule, decorators: [{
3226
2864
  type: NgModule,
3227
2865
  args: [{
3228
2866
  declarations: [PlaitMindComponent, MindNodeComponent],
3229
- imports: [CommonModule, RichtextModule, PlaitModule],
2867
+ imports: [CommonModule, TextModule, PlaitModule],
3230
2868
  exports: [PlaitMindComponent, MindNodeComponent]
3231
2869
  }]
3232
2870
  }] });
3233
2871
 
3234
2872
  const DRAG_MOVE_BUFFER = 5;
3235
- const withDnd = (board) => {
2873
+ const withNodeDnd = (board) => {
3236
2874
  const { mousedown, mousemove, globalMouseup } = board;
3237
2875
  let activeElements = [];
3238
2876
  let correspondingElements = [];
@@ -3242,7 +2880,10 @@ const withDnd = (board) => {
3242
2880
  let dropTarget = null;
3243
2881
  let targetPath;
3244
2882
  board.mousedown = (event) => {
3245
- if (board.options.readonly || IS_TEXT_EDITABLE.get(board) || event.button === 2) {
2883
+ if (PlaitBoard.isReadonly(board) ||
2884
+ PlaitBoard.hasBeenTextEditing(board) ||
2885
+ !PlaitBoard.isPointer(board, PlaitPointerType.selection) ||
2886
+ event.button === 2) {
3246
2887
  mousedown(event);
3247
2888
  return;
3248
2889
  }
@@ -3577,7 +3218,7 @@ const withAbstract = (board) => {
3577
3218
  newProperty =
3578
3219
  abstractHandlePosition === AbstractHandlePosition.start ? { start: locationIndex + 1 } : { end: locationIndex };
3579
3220
  }
3580
- abstractComponent.updateAbstractIncludedOutline(abstractHandlePosition, location);
3221
+ abstractComponent.activeDrawer.updateAbstractOutline(activeAbstractElement, abstractHandlePosition, location);
3581
3222
  }
3582
3223
  mousemove(event);
3583
3224
  };
@@ -3594,7 +3235,7 @@ const withAbstract = (board) => {
3594
3235
  }
3595
3236
  else {
3596
3237
  const abstractComponent = PlaitElement.getComponent(activeAbstractElement);
3597
- abstractComponent.updateAbstractIncludedOutline();
3238
+ abstractComponent.activeDrawer.updateAbstractOutline(activeAbstractElement);
3598
3239
  }
3599
3240
  activeAbstractElement = undefined;
3600
3241
  }
@@ -3646,22 +3287,29 @@ const withCreateMind = (board) => {
3646
3287
  const nodeG = drawRoundRectangleByElement(board, nodeRectangle, emptyMind);
3647
3288
  const topicRectangle = getTopicRectangleByElement(newBoard, nodeRectangle, emptyMind);
3648
3289
  if (!fakeCreateNodeRef) {
3649
- const { richtextComponentRef, richtextG, foreignObject } = drawTopicByElement(newBoard, topicRectangle, emptyMind);
3290
+ const textManage = new TextManage(board, PlaitBoard.getComponent(board).viewContainerRef, () => {
3291
+ return topicRectangle;
3292
+ });
3293
+ PlaitBoard.getComponent(board)
3294
+ .viewContainerRef.injector.get(NgZone)
3295
+ .run(() => {
3296
+ textManage.draw(emptyMind.data.topic);
3297
+ });
3650
3298
  fakeCreateNodeRef = {
3651
- instanceRef: richtextComponentRef,
3299
+ g: createG(),
3652
3300
  nodeG,
3653
- foreignObject,
3654
- topicG: richtextG
3301
+ textManage
3655
3302
  };
3656
- richtextComponentRef.changeDetectorRef.detectChanges();
3657
- PlaitBoard.getHost(board).append(...[fakeCreateNodeRef.nodeG, fakeCreateNodeRef.topicG]);
3303
+ fakeCreateNodeRef.g.classList.add('root');
3304
+ PlaitBoard.getHost(board).append(fakeCreateNodeRef.g);
3305
+ fakeCreateNodeRef.g.append(...[fakeCreateNodeRef.nodeG, textManage.g]);
3658
3306
  }
3659
3307
  else {
3308
+ fakeCreateNodeRef.textManage.updateRectangle(topicRectangle);
3660
3309
  fakeCreateNodeRef.nodeG.remove();
3661
3310
  fakeCreateNodeRef.nodeG = nodeG;
3662
- PlaitBoard.getHost(board).append(nodeG);
3663
- PlaitBoard.getHost(board).append(fakeCreateNodeRef.topicG);
3664
- updateForeignObject(fakeCreateNodeRef.topicG, topicRectangle.width, topicRectangle.height, topicRectangle.x, topicRectangle.y);
3311
+ fakeCreateNodeRef.g.append(nodeG);
3312
+ fakeCreateNodeRef.g.append(fakeCreateNodeRef.textManage.g);
3665
3313
  }
3666
3314
  }
3667
3315
  });
@@ -3677,6 +3325,7 @@ const withCreateMind = (board) => {
3677
3325
  const targetPoint = transformPoint(board, toPoint(movingPoint[0], movingPoint[1], PlaitBoard.getHost(board)));
3678
3326
  const emptyMind = createEmptyMind(board, targetPoint);
3679
3327
  Transforms.insertNode(board, emptyMind, [board.children.length]);
3328
+ clearSelectedElement(board);
3680
3329
  addSelectedElement(board, emptyMind);
3681
3330
  BoardTransforms.updatePointerType(board, PlaitPointerType.selection);
3682
3331
  }
@@ -3697,9 +3346,8 @@ const withCreateMind = (board) => {
3697
3346
  };
3698
3347
  function destroy() {
3699
3348
  if (fakeCreateNodeRef) {
3700
- fakeCreateNodeRef.instanceRef.destroy();
3701
- fakeCreateNodeRef.nodeG.remove();
3702
- fakeCreateNodeRef.topicG.remove();
3349
+ fakeCreateNodeRef.textManage.destroy();
3350
+ fakeCreateNodeRef.g.remove();
3703
3351
  fakeCreateNodeRef = null;
3704
3352
  }
3705
3353
  }
@@ -3731,6 +3379,68 @@ const isExpandHotkey = (keyboardEvent) => {
3731
3379
  return isKeyHotkey('mod+/', keyboardEvent);
3732
3380
  };
3733
3381
 
3382
+ const withNodeHover = (board) => {
3383
+ const { mousemove, mouseleave } = board;
3384
+ let hoveredMindElement = null;
3385
+ board.mousemove = (event) => {
3386
+ throttleRAF(() => {
3387
+ let target = null;
3388
+ const point = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
3389
+ depthFirstRecursion(board, element => {
3390
+ if (target) {
3391
+ return;
3392
+ }
3393
+ if (!MindElement.isMindElement(board, element)) {
3394
+ return;
3395
+ }
3396
+ const isHitElement = isHitMindElement(board, point, element);
3397
+ if (isHitElement) {
3398
+ target = element;
3399
+ }
3400
+ }, node => {
3401
+ if (PlaitBoard.isBoard(node) || board.isRecursion(node)) {
3402
+ return true;
3403
+ }
3404
+ else {
3405
+ return false;
3406
+ }
3407
+ });
3408
+ if (hoveredMindElement && target && hoveredMindElement === target) {
3409
+ return;
3410
+ }
3411
+ if (hoveredMindElement) {
3412
+ removeHovered(hoveredMindElement);
3413
+ }
3414
+ if (target) {
3415
+ addHovered(target);
3416
+ hoveredMindElement = target;
3417
+ }
3418
+ else {
3419
+ hoveredMindElement = null;
3420
+ }
3421
+ });
3422
+ mousemove(event);
3423
+ };
3424
+ board.mouseleave = (event) => {
3425
+ if (hoveredMindElement) {
3426
+ removeHovered(hoveredMindElement);
3427
+ hoveredMindElement = null;
3428
+ }
3429
+ mouseleave(event);
3430
+ };
3431
+ return board;
3432
+ };
3433
+ const addHovered = (element) => {
3434
+ const component = PlaitElement.getComponent(element);
3435
+ component.g.classList.add('hovered');
3436
+ };
3437
+ const removeHovered = (element) => {
3438
+ const component = PlaitElement.getComponent(element);
3439
+ if (component && component.g) {
3440
+ component.g.classList.remove('hovered');
3441
+ }
3442
+ };
3443
+
3734
3444
  const withMind = (board) => {
3735
3445
  const { drawElement, dblclick, keydown, insertFragment, setFragment, deleteFragment, isHitSelection, getRectangle, isMovable, isRecursion } = board;
3736
3446
  board.drawElement = (context) => {
@@ -3857,7 +3567,7 @@ const withMind = (board) => {
3857
3567
  if (!isVirtualKey(event)) {
3858
3568
  event.preventDefault();
3859
3569
  const selectedElement = selectedElements[0];
3860
- enterNodeEditing(selectedElement);
3570
+ editTopic(selectedElement);
3861
3571
  return;
3862
3572
  }
3863
3573
  }
@@ -3879,7 +3589,7 @@ const withMind = (board) => {
3879
3589
  .forEach(mindMap => {
3880
3590
  depthFirstRecursion(mindMap, node => {
3881
3591
  if (!PlaitBoard.hasBeenTextEditing(board) && isHitMindElement(board, point, node)) {
3882
- enterNodeEditing(node);
3592
+ editTopic(node);
3883
3593
  }
3884
3594
  }, node => {
3885
3595
  if (PlaitBoard.isBoard(node) || board.isRecursion(node)) {
@@ -3915,7 +3625,7 @@ const withMind = (board) => {
3915
3625
  }
3916
3626
  else {
3917
3627
  const text = data === null || data === void 0 ? void 0 : data.getData(`text/plain`);
3918
- const { width, height } = getSizeByText(text, PlaitBoard.getHost(board).parentElement, TOPIC_DEFAULT_MAX_WORD_COUNT);
3628
+ const { width, height } = getTextSize(board, text, TOPIC_DEFAULT_MAX_WORD_COUNT);
3919
3629
  const selectedElements = getSelectedElements(board);
3920
3630
  if (text && selectedElements.length === 1) {
3921
3631
  insertClipboardText(board, selectedElements[0], text, width, height);
@@ -3933,7 +3643,7 @@ const withMind = (board) => {
3933
3643
  MindTransforms.removeElements(board, selectedElements);
3934
3644
  deleteFragment(data);
3935
3645
  };
3936
- return withMindHotkey(withMindExtend(withCreateMind(withAbstract(withDnd(board)))));
3646
+ return withNodeHover(withMindHotkey(withMindExtend(withCreateMind(withAbstract(withNodeDnd(board))))));
3937
3647
  };
3938
3648
 
3939
3649
  class MindEmojiBaseComponent {
@@ -3987,5 +3697,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImpor
3987
3697
  * Generated bundle index. Do not edit.
3988
3698
  */
3989
3699
 
3990
- export { ABSTRACT_HANDLE_COLOR, ABSTRACT_HANDLE_LENGTH, ABSTRACT_HANDLE_MASK_WIDTH, ABSTRACT_INCLUDED_OUTLINE_OFFSET, AbstractHandlePosition, AbstractResizeState, BASE, BRANCH_WIDTH, BaseDrawer, BranchShape, DefaultAbstractNodeStyle, DefaultNodeStyle, ELEMENT_TO_NODE, EXTEND_OFFSET, EXTEND_RADIUS, GRAY_COLOR, INHERIT_ATTRIBUTE_KEYS, IS_DRAGGING, LayoutDirection, LayoutDirectionsMap, MindColorfulThemeColor, MindDarkThemeColor, MindDefaultThemeColor, MindElement, MindElementShape, MindEmojiBaseComponent, MindModule, MindNode, MindNodeComponent, MindPointerType, MindQueries, MindRetroThemeColor, MindSoftThemeColor, MindStarryThemeColor, MindThemeColor, MindThemeColors, 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, addActiveOnDragOrigin, adjustAbstractToNode, adjustNodeToRoot, adjustRootToNode, canSetAbstract, copyNewNode, correctLayoutByDirection, createDefaultMind, createEmptyMind, createMindElement, deleteElementHandleAbstract, deleteElementsHandleRightNodeCount, detectDropTarget, directionCorrector, directionDetector, divideElementByParent, drawFakeDragNode, drawFakeDropNode, enterNodeEditing, extractNodesText, findLastChild, findLocationLeftIndex, getAbstractBranchColor, getAbstractBranchWidth, getAbstractHandleRectangle, getAllowedDirection, getAvailableSubLayoutsByLayoutDirections, getBehindAbstracts, getBranchColorByMindElement, getBranchDirectionsByLayouts, getBranchShapeByMindElement, getBranchWidthByMindElement, getChildrenCount, getCorrespondingAbstract, getDefaultBranchColor, getDefaultBranchColorByIndex, getDefaultLayout, getEmojiForeignRectangle, getEmojiRectangle, getFirstLevelElement, getHitAbstractHandle, getInCorrectLayoutDirection, getLayoutDirection$1 as getLayoutDirection, getLayoutReverseDirection, getLocationScope, getMindThemeColor, getNextBranchColor, getOverallAbstracts, getPathByDropTarget, getRectangleByElement, getRectangleByNode, getRectangleByResizingLocation, getRelativeStartEndByAbstractRef, getRootLayout, getShapeByElement, getStrokeByMindElement, getTopicRectangleByElement, getTopicRectangleByNode, getValidAbstractRefs, handleTouchedAbstract, hasAfterDraw, hasPreviousOrNextOfDropPath, insertElementHandleAbstract, insertElementHandleRightNodeCount, insertMindElement, isChildElement, isChildRight, isChildUp, isCorrectLayout, isDragging, isDropStandardRight, isHitEmojis, isHitMindElement, isInRightBranchOfStandardLayout, isMixedLayout, isSetAbstract, isValidTarget, isVirtualKey, removeActiveOnDragOrigin, separateChildren, setIsDragging, withMind, withMindExtend };
3700
+ export { ABSTRACT_HANDLE_COLOR, ABSTRACT_HANDLE_LENGTH, ABSTRACT_HANDLE_MASK_WIDTH, ABSTRACT_INCLUDED_OUTLINE_OFFSET, AbstractHandlePosition, AbstractResizeState, BASE, BRANCH_WIDTH, BaseDrawer, BranchShape, DefaultAbstractNodeStyle, DefaultNodeStyle, ELEMENT_TO_NODE, EXTEND_DIAMETER, EXTEND_OFFSET, GRAY_COLOR, INHERIT_ATTRIBUTE_KEYS, IS_DRAGGING, LayoutDirection, LayoutDirectionsMap, MindColorfulThemeColor, MindDarkThemeColor, MindDefaultThemeColor, MindElement, MindElementShape, MindEmojiBaseComponent, MindModule, MindNode, MindNodeComponent, MindPointerType, MindQueries, MindRetroThemeColor, MindSoftThemeColor, MindStarryThemeColor, MindThemeColor, MindThemeColors, 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, ROOT_TOPIC_HEIGHT, STROKE_WIDTH, TOPIC_COLOR, TOPIC_DEFAULT_MAX_WORD_COUNT, TOPIC_FONT_SIZE, TRANSPARENT, addActiveOnDragOrigin, adjustAbstractToNode, adjustNodeToRoot, adjustRootToNode, canSetAbstract, copyNewNode, correctLayoutByDirection, createDefaultMind, createEmptyMind, createMindElement, deleteElementHandleAbstract, deleteElementsHandleRightNodeCount, detectDropTarget, directionCorrector, directionDetector, divideElementByParent, drawFakeDragNode, drawFakeDropNode, editTopic, extractNodesText, findLastChild, findLocationLeftIndex, getAbstractBranchColor, getAbstractBranchWidth, getAbstractHandleRectangle, getAllowedDirection, getAvailableSubLayoutsByLayoutDirections, getBehindAbstracts, getBranchColorByMindElement, getBranchDirectionsByLayouts, getBranchShapeByMindElement, getBranchWidthByMindElement, getChildrenCount, getCorrespondingAbstract, getDefaultBranchColor, getDefaultBranchColorByIndex, getDefaultLayout, getEmojiForeignRectangle, getEmojiRectangle, getFirstLevelElement, getHitAbstractHandle, getInCorrectLayoutDirection, getLayoutDirection$1 as getLayoutDirection, getLayoutReverseDirection, getLocationScope, getMindThemeColor, getNextBranchColor, getOverallAbstracts, getPathByDropTarget, getRectangleByElement, getRectangleByNode, getRectangleByResizingLocation, getRelativeStartEndByAbstractRef, getRootLayout, getShapeByElement, getStrokeByMindElement, getTopicRectangleByElement, getTopicRectangleByNode, getValidAbstractRefs, handleTouchedAbstract, hasAfterDraw, hasPreviousOrNextOfDropPath, insertElementHandleAbstract, insertElementHandleRightNodeCount, insertMindElement, isChildElement, isChildRight, isChildUp, isCorrectLayout, isDragging, isDropStandardRight, isHitEmojis, isHitMindElement, isInRightBranchOfStandardLayout, isMixedLayout, isSetAbstract, isValidTarget, isVirtualKey, removeActiveOnDragOrigin, separateChildren, setIsDragging, withMind, withMindExtend };
3991
3701
  //# sourceMappingURL=plait-mind.mjs.map