@plait/mind 0.15.0 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/base/image-base.component.d.ts +16 -0
  2. package/base/index.d.ts +1 -0
  3. package/constants/default.d.ts +1 -0
  4. package/drawer/node-image.drawer.d.ts +16 -0
  5. package/esm2020/base/image-base.component.mjs +28 -0
  6. package/esm2020/base/index.mjs +2 -1
  7. package/esm2020/constants/default.mjs +2 -1
  8. package/esm2020/drawer/node-image.drawer.mjs +61 -0
  9. package/esm2020/interfaces/element-data.mjs +1 -1
  10. package/esm2020/interfaces/element.mjs +9 -1
  11. package/esm2020/interfaces/options.mjs +1 -1
  12. package/esm2020/node.component.mjs +19 -5
  13. package/esm2020/plugins/with-abstract-resize.board.mjs +1 -1
  14. package/esm2020/plugins/with-mind-extend.mjs +3 -4
  15. package/esm2020/plugins/with-mind-hotkey.mjs +42 -32
  16. package/esm2020/plugins/with-mind-image.mjs +49 -0
  17. package/esm2020/plugins/with-mind.board.mjs +1 -1
  18. package/esm2020/plugins/with-mind.mjs +3 -2
  19. package/esm2020/plugins/with-node-dnd.mjs +13 -6
  20. package/esm2020/transforms/abstract-node.mjs +1 -3
  21. package/esm2020/transforms/emoji.mjs +2 -2
  22. package/esm2020/transforms/image.mjs +10 -0
  23. package/esm2020/transforms/index.mjs +4 -2
  24. package/esm2020/transforms/node.mjs +2 -6
  25. package/esm2020/utils/abstract/common.mjs +5 -1
  26. package/esm2020/utils/draw/node-dnd.mjs +8 -1
  27. package/esm2020/utils/mind.mjs +2 -2
  28. package/esm2020/utils/node-style/branch.mjs +6 -1
  29. package/esm2020/utils/node-style/shape.mjs +8 -1
  30. package/esm2020/utils/position/emoji.mjs +8 -8
  31. package/esm2020/utils/position/image.mjs +21 -0
  32. package/esm2020/utils/position/index.mjs +2 -1
  33. package/esm2020/utils/space/emoji.mjs +3 -2
  34. package/esm2020/utils/space/node-space.mjs +25 -6
  35. package/fesm2015/plait-mind.mjs +451 -227
  36. package/fesm2015/plait-mind.mjs.map +1 -1
  37. package/fesm2020/plait-mind.mjs +448 -227
  38. package/fesm2020/plait-mind.mjs.map +1 -1
  39. package/interfaces/element-data.d.ts +9 -0
  40. package/interfaces/element.d.ts +2 -1
  41. package/interfaces/options.d.ts +4 -1
  42. package/node.component.d.ts +3 -0
  43. package/package.json +1 -1
  44. package/plugins/with-abstract-resize.board.d.ts +2 -2
  45. package/plugins/with-mind-hotkey.d.ts +2 -0
  46. package/plugins/with-mind-image.d.ts +2 -0
  47. package/plugins/with-mind.board.d.ts +0 -2
  48. package/transforms/image.d.ts +3 -0
  49. package/transforms/index.d.ts +1 -0
  50. package/utils/abstract/common.d.ts +1 -0
  51. package/utils/position/emoji.d.ts +4 -4
  52. package/utils/position/image.d.ts +6 -0
  53. package/utils/position/index.d.ts +1 -0
  54. package/utils/space/node-space.d.ts +1 -0
@@ -1,9 +1,9 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Component, ChangeDetectionStrategy, NgModule, NgZone, Directive, Input, HostListener } from '@angular/core';
2
+ import { Directive, Input, Component, ChangeDetectionStrategy, NgModule, NgZone, HostListener } from '@angular/core';
3
3
  import * as i2 from '@plait/core';
4
- import { DefaultThemeColor, ColorfulThemeColor, SoftThemeColor, RetroThemeColor, DarkThemeColor, StarryThemeColor, RectangleClient, PlaitElement, idCreator, isNullOrUndefined, Transforms, clearSelectedElement, addSelectedElement, PlaitBoard, depthFirstRecursion, Path, drawLinearPath, drawBezierPath, createG, updateForeignObject, PlaitNode, drawRoundRectangle, getRectangleByElements, getSelectedElements, NODE_TO_PARENT, distanceBetweenPointAndRectangle, createForeignObject, drawAbstractRoundRectangle, createText, PlaitPointerType, PlaitPluginElementComponent, NODE_TO_INDEX, PlaitModule, transformPoint, toPoint, getHitElements, distanceBetweenPointAndPoint, CLIP_BOARD_FORMAT_KEY, isMainPointer, BOARD_TO_HOST, PlaitPluginKey, throttleRAF, BoardTransforms, removeSelectedElement, PlaitHistoryBoard, hotkeys } from '@plait/core';
5
- import { MindLayoutType, isIndentedLayout, getNonAbstractChildren, isStandardLayout, AbstractNode, isLeftLayout, isRightLayout, isVerticalLogicLayout, isHorizontalLogicLayout, isTopLayout, isBottomLayout, isHorizontalLayout, getCorrectStartEnd, getAbstractLayout, ConnectingPosition, GlobalLayout } from '@plait/layouts';
6
- import { TEXT_DEFAULT_HEIGHT, buildText, getTextSize, TextManage, TextModule, getTextFromClipboard } from '@plait/text';
4
+ import { DefaultThemeColor, ColorfulThemeColor, SoftThemeColor, RetroThemeColor, DarkThemeColor, StarryThemeColor, RectangleClient, PlaitElement, idCreator, isNullOrUndefined, Transforms, clearSelectedElement, addSelectedElement, PlaitNode, Path, PlaitBoard, depthFirstRecursion, drawLinearPath, drawBezierPath, createG, updateForeignObject, drawRoundRectangle, getRectangleByElements, getSelectedElements, NODE_TO_PARENT, distanceBetweenPointAndRectangle, createForeignObject, drawAbstractRoundRectangle, createText, PlaitPointerType, PlaitPluginElementComponent, NODE_TO_INDEX, PlaitModule, transformPoint, toPoint, getHitElements, distanceBetweenPointAndPoint, CLIP_BOARD_FORMAT_KEY, isMainPointer, BOARD_TO_HOST, PlaitPluginKey, throttleRAF, BoardTransforms, removeSelectedElement, PlaitHistoryBoard, hotkeys } from '@plait/core';
5
+ import { MindLayoutType, isIndentedLayout, AbstractNode, getNonAbstractChildren, isStandardLayout, isLeftLayout, isRightLayout, isVerticalLogicLayout, isHorizontalLogicLayout, isTopLayout, isBottomLayout, isHorizontalLayout, getCorrectStartEnd, getAbstractLayout, ConnectingPosition, GlobalLayout } from '@plait/layouts';
6
+ import { TEXT_DEFAULT_HEIGHT, buildText, getTextSize, TextManage, ExitOrigin, TextModule, getTextFromClipboard } from '@plait/text';
7
7
  import { fromEvent, Subject } from 'rxjs';
8
8
  import { Node, Path as Path$1 } from 'slate';
9
9
  import { isKeyHotkey } from 'is-hotkey';
@@ -179,6 +179,7 @@ const MindThemeColor = {
179
179
  }
180
180
  };
181
181
 
182
+ const WithMindPluginKey = 'plait-mind-plugin-key';
182
183
  const BASE = 4;
183
184
  const PRIMARY_COLOR = '#6698FF';
184
185
  const TRANSPARENT = 'transparent';
@@ -192,7 +193,7 @@ const QUICK_INSERT_CIRCLE_COLOR = '#6698FF';
192
193
  const QUICK_INSERT_INNER_CROSS_COLOR = 'white';
193
194
 
194
195
  function getEmojisWidthHeight(board, element) {
195
- const options = board.getMindOptions();
196
+ const options = board.getPluginOptions(WithMindPluginKey);
196
197
  const count = element.data.emojis.length;
197
198
  const fontSize = getEmojiFontSize(element);
198
199
  return {
@@ -215,7 +216,9 @@ const NodeDefaultSpace = {
215
216
  emojiAndText: BASE * 1.5
216
217
  },
217
218
  vertical: {
218
- nodeAndText: BASE * 1.5
219
+ nodeAndText: BASE * 1.5,
220
+ nodeAndImage: BASE,
221
+ imageAndText: BASE * 1.5
219
222
  }
220
223
  };
221
224
  const RootDefaultSpace = {
@@ -245,17 +248,25 @@ const getSpaceEmojiAndText = (element) => {
245
248
  const NodeSpace = {
246
249
  getNodeWidth(board, element) {
247
250
  const nodeAndText = getHorizontalSpaceBetweenNodeAndText(board, element);
251
+ const imageWidth = MindElement.hasImage(element) ? element.data.image?.width : 0;
248
252
  if (MindElement.hasEmojis(element)) {
249
253
  return (NodeSpace.getEmojiLeftSpace(board, element) +
250
254
  getEmojisWidthHeight(board, element).width +
251
255
  getSpaceEmojiAndText(element) +
252
- element.width +
256
+ Math.max(element.width, imageWidth) +
253
257
  nodeAndText);
254
258
  }
255
- return nodeAndText + element.width + nodeAndText;
259
+ return nodeAndText + Math.max(element.width, imageWidth) + nodeAndText;
256
260
  },
257
261
  getNodeHeight(board, element) {
258
262
  const nodeAndText = getVerticalSpaceBetweenNodeAndText(element);
263
+ if (MindElement.hasImage(element)) {
264
+ return (NodeDefaultSpace.vertical.nodeAndImage +
265
+ element.data.image.height +
266
+ NodeDefaultSpace.vertical.imageAndText +
267
+ element.height +
268
+ nodeAndText);
269
+ }
259
270
  return nodeAndText + element.height + nodeAndText;
260
271
  },
261
272
  getTextLeftSpace(board, element) {
@@ -269,10 +280,18 @@ const NodeSpace = {
269
280
  },
270
281
  getTextTopSpace(element) {
271
282
  const nodeAndText = getVerticalSpaceBetweenNodeAndText(element);
272
- return nodeAndText;
283
+ if (MindElement.hasImage(element)) {
284
+ return element.data.image.height + NodeDefaultSpace.vertical.nodeAndImage + NodeDefaultSpace.vertical.imageAndText;
285
+ }
286
+ else {
287
+ return nodeAndText;
288
+ }
289
+ },
290
+ getImageTopSpace(element) {
291
+ return NodeDefaultSpace.vertical.nodeAndImage;
273
292
  },
274
293
  getEmojiLeftSpace(board, element) {
275
- const options = board.getMindOptions();
294
+ const options = board.getPluginOptions(WithMindPluginKey);
276
295
  const nodeAndText = getHorizontalSpaceBetweenNodeAndText(board, element);
277
296
  return nodeAndText - options.emojiPadding;
278
297
  },
@@ -296,12 +315,12 @@ function getEmojiRectangle(board, element) {
296
315
  function getEmojiForeignRectangle(board, element) {
297
316
  let { x, y } = getRectangleByNode(MindElement.getNode(element));
298
317
  x = x + NodeSpace.getEmojiLeftSpace(board, element);
299
- const { width, height } = getEmojisWidthHeight(board, element);
318
+ const { width } = getEmojisWidthHeight(board, element);
300
319
  return {
301
320
  x,
302
321
  y,
303
322
  width,
304
- height: height + NodeSpace.getEmojiTopSpace(element) * 2
323
+ height: NodeSpace.getNodeHeight(board, element)
305
324
  };
306
325
  }
307
326
  const isHitEmojis = (board, element, point) => {
@@ -323,6 +342,23 @@ function getTopicRectangleByElement(board, nodeRectangle, element) {
323
342
  return { height, width, x, y };
324
343
  }
325
344
 
345
+ function getImageForeignRectangle(board, element) {
346
+ let { x, y } = getRectangleByNode(MindElement.getNode(element));
347
+ x = x + NodeSpace.getTextLeftSpace(board, element);
348
+ y = NodeSpace.getImageTopSpace(element) + y;
349
+ const { width, height } = element.data.image;
350
+ return {
351
+ x,
352
+ y,
353
+ width,
354
+ height
355
+ };
356
+ }
357
+ const isHitImage = (board, element, range) => {
358
+ const client = getImageForeignRectangle(board, element);
359
+ return RectangleClient.isHit(RectangleClient.toRectangleClient([range.anchor, range.focus]), client);
360
+ };
361
+
326
362
  const NODE_MIN_WIDTH = 18;
327
363
 
328
364
  function editTopic(element) {
@@ -432,7 +468,7 @@ const copyNewNode = (node) => {
432
468
  const extractNodesText = (node) => {
433
469
  let str = '';
434
470
  if (node) {
435
- str += Node.string(node.data.topic.children[0]) + ' ';
471
+ str += Node.string(node.data.topic) + ' ';
436
472
  for (const childNode of node.children) {
437
473
  str += extractNodesText(childNode);
438
474
  }
@@ -638,10 +674,180 @@ const getAvailableProperty = (board, element, propertyKey) => {
638
674
  return element[propertyKey];
639
675
  };
640
676
 
677
+ const separateChildren = (parentElement) => {
678
+ const rightNodeCount = parentElement.rightNodeCount;
679
+ const children = parentElement.children;
680
+ let rightChildren = [], leftChildren = [];
681
+ for (let i = 0; i < children.length; i++) {
682
+ const child = children[i];
683
+ if (AbstractNode.isAbstract(child) && child.end < rightNodeCount) {
684
+ rightChildren.push(child);
685
+ continue;
686
+ }
687
+ if (AbstractNode.isAbstract(child) && child.start >= rightNodeCount) {
688
+ leftChildren.push(child);
689
+ continue;
690
+ }
691
+ if (i < rightNodeCount) {
692
+ rightChildren.push(child);
693
+ }
694
+ else {
695
+ leftChildren.push(child);
696
+ }
697
+ }
698
+ return { leftChildren, rightChildren };
699
+ };
700
+ const isSetAbstract = (element) => {
701
+ return !!getCorrespondingAbstract(element);
702
+ };
703
+ const canSetAbstract = (element) => {
704
+ return !PlaitElement.isRootElement(element) && !AbstractNode.isAbstract(element) && !isSetAbstract(element);
705
+ };
706
+ const getCorrespondingAbstract = (element) => {
707
+ const parent = MindElement.findParent(element);
708
+ if (!parent)
709
+ return undefined;
710
+ const elementIndex = parent.children.indexOf(element);
711
+ return parent.children.find(child => {
712
+ return AbstractNode.isAbstract(child) && elementIndex >= child.start && elementIndex <= child.end;
713
+ });
714
+ };
715
+ const getBehindAbstracts = (element) => {
716
+ const parent = MindElement.findParent(element);
717
+ if (!parent)
718
+ return [];
719
+ const index = parent.children.indexOf(element);
720
+ return parent.children.filter(child => AbstractNode.isAbstract(child) && child.start > index);
721
+ };
722
+ /**
723
+ * return corresponding abstract that is not child of elements
724
+ */
725
+ const getOverallAbstracts = (board, elements) => {
726
+ const overallAbstracts = [];
727
+ elements
728
+ .filter(value => !AbstractNode.isAbstract(value) && !PlaitMind.isMind(value))
729
+ .forEach(value => {
730
+ const abstract = getCorrespondingAbstract(value);
731
+ if (abstract && elements.indexOf(abstract) === -1 && overallAbstracts.indexOf(abstract) === -1) {
732
+ const { start, end } = abstract;
733
+ const parent = MindElement.getParent(value);
734
+ const isOverall = parent.children.slice(start, end + 1).every(includedElement => elements.indexOf(includedElement) > -1);
735
+ if (isOverall) {
736
+ overallAbstracts.push(abstract);
737
+ }
738
+ }
739
+ });
740
+ return overallAbstracts;
741
+ };
742
+ /**
743
+ * abstract node is valid when elements contains at least one element it is referenced with
744
+ */
745
+ const getValidAbstractRefs = (board, elements) => {
746
+ const validAbstractRefs = [];
747
+ elements
748
+ .filter(value => !AbstractNode.isAbstract(value) && !PlaitMind.isMind(value))
749
+ .forEach(value => {
750
+ const abstract = getCorrespondingAbstract(value);
751
+ if (abstract && elements.indexOf(abstract) > 0) {
752
+ const index = validAbstractRefs.findIndex(value => value.abstract === abstract);
753
+ if (index === -1) {
754
+ validAbstractRefs.push({
755
+ abstract: abstract,
756
+ references: [value]
757
+ });
758
+ }
759
+ else {
760
+ validAbstractRefs[index].references.push(value);
761
+ }
762
+ }
763
+ });
764
+ return validAbstractRefs;
765
+ };
766
+ function getRelativeStartEndByAbstractRef(abstractRef, elements) {
767
+ const start = elements.indexOf(abstractRef.references[0]);
768
+ const end = elements.indexOf(abstractRef.references[abstractRef.references.length - 1]);
769
+ return { start, end };
770
+ }
771
+ const insertElementHandleAbstract = (board, path, step = 1,
772
+ //由此区分拖拽和新增到概要概括最后一个节点
773
+ isExtendPreviousNode = true, effectedAbstracts = new Map()) => {
774
+ const parent = PlaitNode.parent(board, path);
775
+ const hasPreviousNode = path[path.length - 1] !== 0;
776
+ let behindAbstracts;
777
+ if (!hasPreviousNode) {
778
+ behindAbstracts = parent.children.filter(child => AbstractNode.isAbstract(child));
779
+ }
780
+ else {
781
+ const selectedElement = PlaitNode.get(board, Path.previous(path));
782
+ behindAbstracts = getBehindAbstracts(selectedElement);
783
+ }
784
+ if (behindAbstracts.length) {
785
+ behindAbstracts.forEach(abstract => {
786
+ let newProperties = effectedAbstracts.get(abstract);
787
+ if (!newProperties) {
788
+ newProperties = { start: 0, end: 0 };
789
+ effectedAbstracts.set(abstract, newProperties);
790
+ }
791
+ newProperties.start = newProperties.start + step;
792
+ newProperties.end = newProperties.end + step;
793
+ });
794
+ }
795
+ if (!hasPreviousNode) {
796
+ return effectedAbstracts;
797
+ }
798
+ const selectedElement = PlaitNode.get(board, Path.previous(path));
799
+ const correspondingAbstract = getCorrespondingAbstract(selectedElement);
800
+ const isDragToLast = !isExtendPreviousNode && correspondingAbstract && correspondingAbstract.end === path[path.length - 1] - 1;
801
+ if (correspondingAbstract && !isDragToLast) {
802
+ let newProperties = effectedAbstracts.get(correspondingAbstract);
803
+ if (!newProperties) {
804
+ newProperties = { start: 0, end: 0 };
805
+ effectedAbstracts.set(correspondingAbstract, newProperties);
806
+ }
807
+ newProperties.end = newProperties.end + step;
808
+ }
809
+ return effectedAbstracts;
810
+ };
811
+ const deleteElementHandleAbstract = (board, deletableElements, effectedAbstracts = new Map()) => {
812
+ deletableElements.forEach(node => {
813
+ if (!PlaitMind.isMind(node)) {
814
+ const behindAbstracts = getBehindAbstracts(node).filter(abstract => !deletableElements.includes(abstract));
815
+ if (behindAbstracts.length) {
816
+ behindAbstracts.forEach(abstract => {
817
+ let newProperties = effectedAbstracts.get(abstract);
818
+ if (!newProperties) {
819
+ newProperties = { start: 0, end: 0 };
820
+ effectedAbstracts.set(abstract, newProperties);
821
+ }
822
+ newProperties.start = newProperties.start - 1;
823
+ newProperties.end = newProperties.end - 1;
824
+ });
825
+ }
826
+ const correspondingAbstract = getCorrespondingAbstract(node);
827
+ if (correspondingAbstract && !deletableElements.includes(correspondingAbstract)) {
828
+ let newProperties = effectedAbstracts.get(correspondingAbstract);
829
+ if (!newProperties) {
830
+ newProperties = { start: 0, end: 0 };
831
+ effectedAbstracts.set(correspondingAbstract, newProperties);
832
+ }
833
+ newProperties.end = newProperties.end - 1;
834
+ }
835
+ }
836
+ });
837
+ return effectedAbstracts;
838
+ };
839
+ const isChildOfAbstract = (board, element) => {
840
+ const ancestors = MindElement.getAncestors(board, element);
841
+ return !!ancestors.find((value) => AbstractNode.isAbstract(value));
842
+ };
843
+
641
844
  /**
642
845
  * Processing of branch color, width, style, etc. of the mind node
643
846
  */
644
847
  const getBranchColorByMindElement = (board, element) => {
848
+ if (AbstractNode.isAbstract(element) || isChildOfAbstract(board, element)) {
849
+ return getAbstractBranchColor(board, element);
850
+ }
645
851
  const branchColor = getAvailableProperty(board, element, 'branchColor');
646
852
  return branchColor || getDefaultBranchColor(board, element);
647
853
  };
@@ -695,6 +901,10 @@ const getStrokeByMindElement = (board, element) => {
695
901
  const defaultRootStroke = getMindThemeColor(board).rootFill;
696
902
  return element.strokeColor || defaultRootStroke;
697
903
  }
904
+ if (AbstractNode.isAbstract(element) || isChildOfAbstract(board, element)) {
905
+ return element.strokeColor || DefaultAbstractNodeStyle.strokeColor;
906
+ ;
907
+ }
698
908
  return getAvailableProperty(board, element, 'strokeColor') || getDefaultBranchColor(board, element);
699
909
  };
700
910
  const getShapeByElement = (board, element) => {
@@ -1218,6 +1428,12 @@ const drawFakeDragNode = (board, element, offsetX, offsetY) => {
1218
1428
  updateForeignObject(fakeEmojisG, foreignRectangle.width, foreignRectangle.height, foreignRectangle.x + offsetX, foreignRectangle.y + offsetY);
1219
1429
  dragFakeNodeG?.append(fakeEmojisG);
1220
1430
  }
1431
+ if (MindElement.hasImage(element)) {
1432
+ const fakeImageG = activeComponent.imageDrawer.g.cloneNode(true);
1433
+ const foreignRectangle = getImageForeignRectangle(board, element);
1434
+ updateForeignObject(fakeImageG, foreignRectangle.width, foreignRectangle.height, foreignRectangle.x + offsetX, foreignRectangle.y + offsetY);
1435
+ dragFakeNodeG?.append(fakeImageG);
1436
+ }
1221
1437
  return dragFakeNodeG;
1222
1438
  };
1223
1439
  const drawFakeDropNode = (board, dropTarget, path) => {
@@ -1334,169 +1550,6 @@ const drawFakeDropNode = (board, dropTarget, path) => {
1334
1550
  return fakeDropNodeG;
1335
1551
  };
1336
1552
 
1337
- const separateChildren = (parentElement) => {
1338
- const rightNodeCount = parentElement.rightNodeCount;
1339
- const children = parentElement.children;
1340
- let rightChildren = [], leftChildren = [];
1341
- for (let i = 0; i < children.length; i++) {
1342
- const child = children[i];
1343
- if (AbstractNode.isAbstract(child) && child.end < rightNodeCount) {
1344
- rightChildren.push(child);
1345
- continue;
1346
- }
1347
- if (AbstractNode.isAbstract(child) && child.start >= rightNodeCount) {
1348
- leftChildren.push(child);
1349
- continue;
1350
- }
1351
- if (i < rightNodeCount) {
1352
- rightChildren.push(child);
1353
- }
1354
- else {
1355
- leftChildren.push(child);
1356
- }
1357
- }
1358
- return { leftChildren, rightChildren };
1359
- };
1360
- const isSetAbstract = (element) => {
1361
- return !!getCorrespondingAbstract(element);
1362
- };
1363
- const canSetAbstract = (element) => {
1364
- return !PlaitElement.isRootElement(element) && !AbstractNode.isAbstract(element) && !isSetAbstract(element);
1365
- };
1366
- const getCorrespondingAbstract = (element) => {
1367
- const parent = MindElement.findParent(element);
1368
- if (!parent)
1369
- return undefined;
1370
- const elementIndex = parent.children.indexOf(element);
1371
- return parent.children.find(child => {
1372
- return AbstractNode.isAbstract(child) && elementIndex >= child.start && elementIndex <= child.end;
1373
- });
1374
- };
1375
- const getBehindAbstracts = (element) => {
1376
- const parent = MindElement.findParent(element);
1377
- if (!parent)
1378
- return [];
1379
- const index = parent.children.indexOf(element);
1380
- return parent.children.filter(child => AbstractNode.isAbstract(child) && child.start > index);
1381
- };
1382
- /**
1383
- * return corresponding abstract that is not child of elements
1384
- */
1385
- const getOverallAbstracts = (board, elements) => {
1386
- const overallAbstracts = [];
1387
- elements
1388
- .filter(value => !AbstractNode.isAbstract(value) && !PlaitMind.isMind(value))
1389
- .forEach(value => {
1390
- const abstract = getCorrespondingAbstract(value);
1391
- if (abstract && elements.indexOf(abstract) === -1 && overallAbstracts.indexOf(abstract) === -1) {
1392
- const { start, end } = abstract;
1393
- const parent = MindElement.getParent(value);
1394
- const isOverall = parent.children.slice(start, end + 1).every(includedElement => elements.indexOf(includedElement) > -1);
1395
- if (isOverall) {
1396
- overallAbstracts.push(abstract);
1397
- }
1398
- }
1399
- });
1400
- return overallAbstracts;
1401
- };
1402
- /**
1403
- * abstract node is valid when elements contains at least one element it is referenced with
1404
- */
1405
- const getValidAbstractRefs = (board, elements) => {
1406
- const validAbstractRefs = [];
1407
- elements
1408
- .filter(value => !AbstractNode.isAbstract(value) && !PlaitMind.isMind(value))
1409
- .forEach(value => {
1410
- const abstract = getCorrespondingAbstract(value);
1411
- if (abstract && elements.indexOf(abstract) > 0) {
1412
- const index = validAbstractRefs.findIndex(value => value.abstract === abstract);
1413
- if (index === -1) {
1414
- validAbstractRefs.push({
1415
- abstract: abstract,
1416
- references: [value]
1417
- });
1418
- }
1419
- else {
1420
- validAbstractRefs[index].references.push(value);
1421
- }
1422
- }
1423
- });
1424
- return validAbstractRefs;
1425
- };
1426
- function getRelativeStartEndByAbstractRef(abstractRef, elements) {
1427
- const start = elements.indexOf(abstractRef.references[0]);
1428
- const end = elements.indexOf(abstractRef.references[abstractRef.references.length - 1]);
1429
- return { start, end };
1430
- }
1431
- const insertElementHandleAbstract = (board, path, step = 1,
1432
- //由此区分拖拽和新增到概要概括最后一个节点
1433
- isExtendPreviousNode = true, effectedAbstracts = new Map()) => {
1434
- const parent = PlaitNode.parent(board, path);
1435
- const hasPreviousNode = path[path.length - 1] !== 0;
1436
- let behindAbstracts;
1437
- if (!hasPreviousNode) {
1438
- behindAbstracts = parent.children.filter(child => AbstractNode.isAbstract(child));
1439
- }
1440
- else {
1441
- const selectedElement = PlaitNode.get(board, Path.previous(path));
1442
- behindAbstracts = getBehindAbstracts(selectedElement);
1443
- }
1444
- if (behindAbstracts.length) {
1445
- behindAbstracts.forEach(abstract => {
1446
- let newProperties = effectedAbstracts.get(abstract);
1447
- if (!newProperties) {
1448
- newProperties = { start: 0, end: 0 };
1449
- effectedAbstracts.set(abstract, newProperties);
1450
- }
1451
- newProperties.start = newProperties.start + step;
1452
- newProperties.end = newProperties.end + step;
1453
- });
1454
- }
1455
- if (!hasPreviousNode) {
1456
- return effectedAbstracts;
1457
- }
1458
- const selectedElement = PlaitNode.get(board, Path.previous(path));
1459
- const correspondingAbstract = getCorrespondingAbstract(selectedElement);
1460
- const isDragToLast = !isExtendPreviousNode && correspondingAbstract && correspondingAbstract.end === path[path.length - 1] - 1;
1461
- if (correspondingAbstract && !isDragToLast) {
1462
- let newProperties = effectedAbstracts.get(correspondingAbstract);
1463
- if (!newProperties) {
1464
- newProperties = { start: 0, end: 0 };
1465
- effectedAbstracts.set(correspondingAbstract, newProperties);
1466
- }
1467
- newProperties.end = newProperties.end + step;
1468
- }
1469
- return effectedAbstracts;
1470
- };
1471
- const deleteElementHandleAbstract = (board, deletableElements, effectedAbstracts = new Map()) => {
1472
- deletableElements.forEach(node => {
1473
- if (!PlaitMind.isMind(node)) {
1474
- const behindAbstracts = getBehindAbstracts(node).filter(abstract => !deletableElements.includes(abstract));
1475
- if (behindAbstracts.length) {
1476
- behindAbstracts.forEach(abstract => {
1477
- let newProperties = effectedAbstracts.get(abstract);
1478
- if (!newProperties) {
1479
- newProperties = { start: 0, end: 0 };
1480
- effectedAbstracts.set(abstract, newProperties);
1481
- }
1482
- newProperties.start = newProperties.start - 1;
1483
- newProperties.end = newProperties.end - 1;
1484
- });
1485
- }
1486
- const correspondingAbstract = getCorrespondingAbstract(node);
1487
- if (correspondingAbstract && !deletableElements.includes(correspondingAbstract)) {
1488
- let newProperties = effectedAbstracts.get(correspondingAbstract);
1489
- if (!newProperties) {
1490
- newProperties = { start: 0, end: 0 };
1491
- effectedAbstracts.set(correspondingAbstract, newProperties);
1492
- }
1493
- newProperties.end = newProperties.end - 1;
1494
- }
1495
- }
1496
- });
1497
- return effectedAbstracts;
1498
- };
1499
-
1500
1553
  var AbstractHandlePosition;
1501
1554
  (function (AbstractHandlePosition) {
1502
1555
  AbstractHandlePosition["start"] = "start";
@@ -1911,6 +1964,14 @@ const MindElement = {
1911
1964
  return false;
1912
1965
  }
1913
1966
  },
1967
+ hasImage(element) {
1968
+ if (element.data.image) {
1969
+ return true;
1970
+ }
1971
+ else {
1972
+ return false;
1973
+ }
1974
+ },
1914
1975
  getEmojis(element) {
1915
1976
  return element.data.emojis;
1916
1977
  },
@@ -2155,9 +2216,7 @@ const setAbstractByElements = (board, groupParent, group) => {
2155
2216
  };
2156
2217
  const insertAbstractNode = (board, path, start, end) => {
2157
2218
  const mindElement = createMindElement('概要', 28, 20, {
2158
- strokeColor: DefaultAbstractNodeStyle.strokeColor,
2159
2219
  strokeWidth: DefaultAbstractNodeStyle.branchWidth,
2160
- branchColor: DefaultAbstractNodeStyle.branchColor,
2161
2220
  branchWidth: DefaultAbstractNodeStyle.branchWidth
2162
2221
  });
2163
2222
  mindElement.start = start;
@@ -2197,12 +2256,9 @@ const normalizeWidthAndHeight = (board, width, height) => {
2197
2256
  };
2198
2257
  const setTopic = (board, element, topic, width, height) => {
2199
2258
  const newElement = {
2200
- data: { topic },
2259
+ data: { ...element.data, topic },
2201
2260
  ...normalizeWidthAndHeight(board, width, height)
2202
2261
  };
2203
- if (MindElement.hasEmojis(element)) {
2204
- newElement.data.emojis = element.data.emojis;
2205
- }
2206
2262
  const path = PlaitBoard.findPath(board, element);
2207
2263
  Transforms.setNode(board, newElement, path);
2208
2264
  };
@@ -2281,7 +2337,7 @@ const removeEmoji = (board, element, emojiItem) => {
2281
2337
  };
2282
2338
  const replaceEmoji = (board, element, oldEmoji, newEmoji) => {
2283
2339
  const newElement = {
2284
- data: { topic: element.data.topic }
2340
+ data: { ...element.data }
2285
2341
  };
2286
2342
  const newEmojis = element.data.emojis.map(value => {
2287
2343
  if (value === oldEmoji) {
@@ -2294,6 +2350,15 @@ const replaceEmoji = (board, element, oldEmoji, newEmoji) => {
2294
2350
  Transforms.setNode(board, newElement, path);
2295
2351
  };
2296
2352
 
2353
+ const removeImage = (board, element) => {
2354
+ const newElement = {
2355
+ data: { ...element.data }
2356
+ };
2357
+ delete newElement.data.image;
2358
+ const path = PlaitBoard.findPath(board, element);
2359
+ Transforms.setNode(board, newElement, path);
2360
+ };
2361
+
2297
2362
  const MindTransforms = {
2298
2363
  setLayout,
2299
2364
  setTopic,
@@ -2307,7 +2372,8 @@ const MindTransforms = {
2307
2372
  removeElements,
2308
2373
  insertNodes,
2309
2374
  insertAbstractNodes,
2310
- setRightNodeCountByRefs
2375
+ setRightNodeCountByRefs,
2376
+ removeImage
2311
2377
  };
2312
2378
 
2313
2379
  class BaseDrawer {
@@ -2626,6 +2692,88 @@ class CollapseDrawer extends BaseDrawer {
2626
2692
  }
2627
2693
  }
2628
2694
 
2695
+ class MindImageBaseComponent {
2696
+ get nativeElement() {
2697
+ return this.elementRef.nativeElement;
2698
+ }
2699
+ constructor(elementRef) {
2700
+ this.elementRef = elementRef;
2701
+ }
2702
+ ngOnInit() { }
2703
+ }
2704
+ MindImageBaseComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.5", ngImport: i0, type: MindImageBaseComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive });
2705
+ MindImageBaseComponent.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.5", type: MindImageBaseComponent, inputs: { imageItem: "imageItem", board: "board", element: "element" }, host: { classAttribute: "mind-node-image" }, ngImport: i0 });
2706
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImport: i0, type: MindImageBaseComponent, decorators: [{
2707
+ type: Directive,
2708
+ args: [{
2709
+ host: {
2710
+ class: 'mind-node-image'
2711
+ }
2712
+ }]
2713
+ }], ctorParameters: function () { return [{ type: i0.ElementRef }]; }, propDecorators: { imageItem: [{
2714
+ type: Input
2715
+ }], board: [{
2716
+ type: Input
2717
+ }], element: [{
2718
+ type: Input
2719
+ }] } });
2720
+
2721
+ class NodeImageDrawer {
2722
+ constructor(board, viewContainerRef) {
2723
+ this.board = board;
2724
+ this.viewContainerRef = viewContainerRef;
2725
+ this.componentRef = null;
2726
+ }
2727
+ drawImage(element) {
2728
+ this.destroy();
2729
+ if (MindElement.hasImage(element)) {
2730
+ this.g = createG();
2731
+ const foreignRectangle = getImageForeignRectangle(this.board, element);
2732
+ const foreignObject = createForeignObject(foreignRectangle.x, foreignRectangle.y, foreignRectangle.width, foreignRectangle.height);
2733
+ this.g.append(foreignObject);
2734
+ if (this.componentRef) {
2735
+ this.componentRef.destroy();
2736
+ this.componentRef = null;
2737
+ }
2738
+ const componentType = this.board.getPluginOptions(WithMindPluginKey).imageComponentType || MindImageBaseComponent;
2739
+ if (!componentType) {
2740
+ throw new Error('Not implement drawEmoji method error.');
2741
+ }
2742
+ this.componentRef = this.viewContainerRef.createComponent(componentType);
2743
+ this.componentRef.instance.board = this.board;
2744
+ this.componentRef.instance.element = element;
2745
+ this.componentRef.instance.imageItem = element.data.image;
2746
+ foreignObject.append(this.componentRef.instance.nativeElement);
2747
+ return this.g;
2748
+ }
2749
+ return undefined;
2750
+ }
2751
+ drawActive(element) {
2752
+ this.destroyActive();
2753
+ const imageRectangle = getImageForeignRectangle(this.board, element);
2754
+ const rectangle = RectangleClient.getOutlineRectangle(imageRectangle, -1);
2755
+ const roughSVG = PlaitBoard.getRoughSVG(this.board);
2756
+ this.activeG = roughSVG.rectangle(rectangle.x, rectangle.y, rectangle.width, rectangle.height, {
2757
+ stroke: PRIMARY_COLOR,
2758
+ fill: '',
2759
+ fillStyle: 'solid'
2760
+ });
2761
+ this.g?.append(this.activeG);
2762
+ }
2763
+ destroyActive() {
2764
+ this.activeG?.remove();
2765
+ }
2766
+ destroy() {
2767
+ if (this.g) {
2768
+ this.g.remove();
2769
+ }
2770
+ if (this.componentRef) {
2771
+ this.componentRef.destroy();
2772
+ this.componentRef = null;
2773
+ }
2774
+ }
2775
+ }
2776
+
2629
2777
  // 1. When the text at the end has an italic attribute, the text is partially covered
2630
2778
  // 2. There will be some differences in the width measured by different browsers
2631
2779
  const WIDTH_BUFFER = 4;
@@ -2645,7 +2793,8 @@ class MindNodeComponent extends PlaitPluginElementComponent {
2645
2793
  this.nodeInsertDrawer = new NodeInsertDrawer(this.board);
2646
2794
  this.activeDrawer = new NodeActiveDrawer(this.board);
2647
2795
  this.collapseDrawer = new CollapseDrawer(this.board);
2648
- const plugins = this.board.getMindOptions().textPlugins;
2796
+ this.imageDrawer = new NodeImageDrawer(this.board, this.viewContainerRef);
2797
+ const plugins = this.board.getPluginOptions(WithMindPluginKey).textPlugins;
2649
2798
  this.textManage = new TextManage(this.board, this.viewContainerRef, () => {
2650
2799
  const rect = getTopicRectangleByNode(this.board, this.node);
2651
2800
  return rect;
@@ -2675,14 +2824,17 @@ class MindNodeComponent extends PlaitPluginElementComponent {
2675
2824
  this.activeDrawer.draw(this.element, this.g, { selected: this.selected, isEditing: this.textManage.isEditing });
2676
2825
  this.drawEmojis();
2677
2826
  this.drawExtend();
2827
+ this.drawImage();
2678
2828
  if (PlaitMind.isMind(this.context.parent)) {
2679
2829
  this.g.classList.add('branch');
2680
2830
  }
2681
2831
  }
2682
2832
  editTopic() {
2683
2833
  this.activeDrawer.draw(this.element, this.g, { selected: this.selected, isEditing: true });
2684
- this.textManage.edit(() => {
2685
- this.activeDrawer.draw(this.element, this.g, { selected: this.selected, isEditing: false });
2834
+ this.textManage.edit((origin) => {
2835
+ if (origin === ExitOrigin.default) {
2836
+ this.activeDrawer.draw(this.element, this.g, { selected: this.selected, isEditing: false });
2837
+ }
2686
2838
  });
2687
2839
  }
2688
2840
  onContextChanged(value, previous) {
@@ -2695,6 +2847,7 @@ class MindNodeComponent extends PlaitPluginElementComponent {
2695
2847
  this.drawShape();
2696
2848
  this.drawLink();
2697
2849
  this.drawEmojis();
2850
+ this.drawImage();
2698
2851
  this.drawExtend();
2699
2852
  this.textManage.updateText(this.element.data.topic);
2700
2853
  this.textManage.updateRectangle();
@@ -2716,6 +2869,12 @@ class MindNodeComponent extends PlaitPluginElementComponent {
2716
2869
  this.g.append(g);
2717
2870
  }
2718
2871
  }
2872
+ drawImage() {
2873
+ const image = this.imageDrawer.drawImage(this.element);
2874
+ if (image) {
2875
+ this.g.append(image);
2876
+ }
2877
+ }
2719
2878
  drawShape() {
2720
2879
  this.destroyShape();
2721
2880
  const shape = getShapeByElement(this.board, this.node.origin);
@@ -2784,6 +2943,7 @@ class MindNodeComponent extends PlaitPluginElementComponent {
2784
2943
  super.ngOnDestroy();
2785
2944
  this.textManage.destroy();
2786
2945
  this.nodeEmojisDrawer.destroy();
2946
+ this.imageDrawer.destroy();
2787
2947
  this.destroy$.next();
2788
2948
  this.destroy$.complete();
2789
2949
  if (ELEMENT_TO_NODE.get(this.element) === this.node) {
@@ -2971,12 +3131,11 @@ const withNodeDnd = (board) => {
2971
3131
  !AbstractNode.isAbstract(targetElement)) {
2972
3132
  const targetElements = selectedElements.filter(element => MindElement.isMindElement(board, element) && !element.isRoot && !AbstractNode.isAbstract(element));
2973
3133
  const isMultiple = selectedElements.length > 0 && selectedElements.includes(targetElement);
2974
- const isSingle = !isMultiple && selectedElements.length === 0;
2975
3134
  if (isMultiple) {
2976
3135
  activeElements = targetElements;
2977
3136
  startPoint = point;
2978
3137
  }
2979
- else if (isSingle) {
3138
+ else {
2980
3139
  activeElements = [targetElement];
2981
3140
  startPoint = point;
2982
3141
  }
@@ -3030,6 +3189,7 @@ const withNodeDnd = (board) => {
3030
3189
  }
3031
3190
  if (dropTarget) {
3032
3191
  const targetPathRef = board.pathRef(targetPath);
3192
+ const targetPreviousPathRef = Path.hasPrevious(targetPath) && board.pathRef(Path.previous(targetPath));
3033
3193
  const targetElementPathRef = board.pathRef(PlaitBoard.findPath(board, dropTarget.target));
3034
3194
  let abstractRefs = getValidAbstractRefs(board, firstLevelElements);
3035
3195
  const normalElements = firstLevelElements
@@ -3067,9 +3227,16 @@ const withNodeDnd = (board) => {
3067
3227
  let insertPath = targetPathRef.current;
3068
3228
  const parentPath = Path.parent(targetPathRef.current || targetPath);
3069
3229
  if (!insertPath) {
3070
- const parent = PlaitNode.get(board, parentPath);
3071
- const children = getNonAbstractChildren(parent);
3072
- insertPath = [...parentPath, children.length || 0];
3230
+ //当插入位置和选中节点位置相同时,使用记录的 previousPath
3231
+ const previousPath = targetPreviousPathRef && targetPreviousPathRef.unref();
3232
+ if (previousPath) {
3233
+ insertPath = Path.next(previousPath);
3234
+ }
3235
+ else {
3236
+ const parent = PlaitNode.get(board, parentPath);
3237
+ const children = getNonAbstractChildren(parent);
3238
+ insertPath = [...parentPath, children.length || 0];
3239
+ }
3073
3240
  }
3074
3241
  MindTransforms.insertNodes(board, normalElements, insertPath);
3075
3242
  if (abstractRefs.length) {
@@ -3325,9 +3492,7 @@ const withMindExtend = (board) => {
3325
3492
  newBoard.drawEmoji = (emoji, element) => {
3326
3493
  throw new Error('Not implement drawEmoji method error.');
3327
3494
  };
3328
- newBoard.getMindOptions = () => {
3329
- return { spaceBetweenEmojis: 4, emojiPadding: 0 };
3330
- };
3495
+ board.setPluginOptions(WithMindPluginKey, { spaceBetweenEmojis: 4, emojiPadding: 0 });
3331
3496
  return newBoard;
3332
3497
  };
3333
3498
 
@@ -3476,38 +3641,18 @@ const withMindHotkey = (board) => {
3476
3641
  event.preventDefault();
3477
3642
  const targetMindElements = selectedElements.filter(el => MindElement.isMindElement(board, el));
3478
3643
  const firstLevelElements = getFirstLevelElement(targetMindElements);
3479
- const deletableElements = firstLevelElements.reverse();
3480
- const abstractRefs = deleteElementHandleAbstract(board, deletableElements);
3481
- MindTransforms.setAbstractsByRefs(board, abstractRefs);
3482
- const refs = deleteElementsHandleRightNodeCount(board, targetMindElements);
3483
- MindTransforms.setRightNodeCountByRefs(board, refs);
3484
- MindTransforms.removeElements(board, targetMindElements);
3485
- let activeElement;
3486
- if (AbstractNode.isAbstract(firstLevelElements[0])) {
3487
- const parent = MindElement.getParent(firstLevelElements[0]);
3488
- activeElement = parent.children[firstLevelElements[0].start];
3489
- }
3490
- const firstElement = firstLevelElements[0];
3491
- const firstElementParent = MindElement.findParent(firstElement);
3492
- const hasSameParent = firstLevelElements.every(element => {
3493
- return MindElement.findParent(element) === firstElementParent;
3494
- });
3495
- if (firstElementParent && hasSameParent && !activeElement) {
3496
- const firstElementIndex = firstElementParent.children.indexOf(firstElement);
3497
- const childrenCount = firstElementParent.children.length;
3498
- // active parent element
3499
- if (childrenCount === firstLevelElements.length) {
3500
- activeElement = firstElementParent;
3501
- }
3502
- else {
3503
- if (firstElementIndex > 0) {
3504
- activeElement = firstElementParent.children[firstElementIndex - 1];
3505
- }
3644
+ if (firstLevelElements.length > 0) {
3645
+ const deletableElements = [...firstLevelElements].reverse();
3646
+ const abstractRefs = deleteElementHandleAbstract(board, deletableElements);
3647
+ MindTransforms.setAbstractsByRefs(board, abstractRefs);
3648
+ const refs = deleteElementsHandleRightNodeCount(board, targetMindElements);
3649
+ MindTransforms.setRightNodeCountByRefs(board, refs);
3650
+ MindTransforms.removeElements(board, targetMindElements);
3651
+ const nextSelected = getNextSelectedElement(board, firstLevelElements);
3652
+ if (nextSelected) {
3653
+ addSelectedElement(board, nextSelected);
3506
3654
  }
3507
3655
  }
3508
- if (activeElement) {
3509
- addSelectedElement(board, activeElement);
3510
- }
3511
3656
  return;
3512
3657
  }
3513
3658
  if (!isVirtualKey(event) && !isSpaceHotkey(event) && isSingleSelection) {
@@ -3520,6 +3665,36 @@ const withMindHotkey = (board) => {
3520
3665
  };
3521
3666
  return board;
3522
3667
  };
3668
+ const getNextSelectedElement = (board, firstLevelElements) => {
3669
+ let activeElement;
3670
+ const firstLevelElement = firstLevelElements[0];
3671
+ const firstLevelElementPath = PlaitBoard.findPath(board, firstLevelElement);
3672
+ let nextSelectedPath = firstLevelElementPath;
3673
+ if (Path.hasPrevious(firstLevelElementPath)) {
3674
+ nextSelectedPath = Path.previous(firstLevelElementPath);
3675
+ }
3676
+ if (AbstractNode.isAbstract(firstLevelElement)) {
3677
+ const parent = MindElement.getParent(firstLevelElement);
3678
+ if (!firstLevelElements.includes(parent.children[firstLevelElement.start])) {
3679
+ activeElement = parent.children[firstLevelElement.start];
3680
+ }
3681
+ }
3682
+ try {
3683
+ if (!activeElement) {
3684
+ activeElement = PlaitNode.get(board, nextSelectedPath);
3685
+ }
3686
+ }
3687
+ catch (error) { }
3688
+ const firstElement = firstLevelElements[0];
3689
+ const firstElementParent = MindElement.findParent(firstElement);
3690
+ const hasSameParent = firstLevelElements.every(element => {
3691
+ return MindElement.findParent(element) === firstElementParent;
3692
+ });
3693
+ if (firstElementParent && hasSameParent && !activeElement) {
3694
+ activeElement = firstElementParent;
3695
+ }
3696
+ return activeElement;
3697
+ };
3523
3698
  const isExpandHotkey = (event) => {
3524
3699
  return isKeyHotkey('mod+/', event);
3525
3700
  };
@@ -3595,6 +3770,52 @@ const removeHovered = (element) => {
3595
3770
  }
3596
3771
  };
3597
3772
 
3773
+ const withMindImage = (board) => {
3774
+ let selectedImageElement = null;
3775
+ const { keydown, mousedown } = board;
3776
+ board.mousedown = (event) => {
3777
+ if (PlaitBoard.isReadonly(board) || !isMainPointer(event) || !PlaitBoard.isPointer(board, PlaitPointerType.selection)) {
3778
+ mousedown(event);
3779
+ return;
3780
+ }
3781
+ const point = transformPoint(board, toPoint(event.x, event.y, PlaitBoard.getHost(board)));
3782
+ const range = { anchor: point, focus: point };
3783
+ const hitElements = getHitElements(board, { ranges: [range] });
3784
+ const hasImage = hitElements.length && MindElement.hasImage(hitElements[0]);
3785
+ const hitImage = hasImage && isHitImage(board, hitElements[0], range);
3786
+ if (hitImage) {
3787
+ const currentOptions = board.getPluginOptions(PlaitPluginKey.withSelection);
3788
+ board.setPluginOptions(PlaitPluginKey.withSelection, {
3789
+ isDisabledSelect: true
3790
+ });
3791
+ setTimeout(() => {
3792
+ board.setPluginOptions(PlaitPluginKey.withSelection, { ...currentOptions });
3793
+ }, 0);
3794
+ selectedImageElement = hitElements[0];
3795
+ const component = PlaitElement.getComponent(selectedImageElement);
3796
+ component.imageDrawer.drawActive(selectedImageElement);
3797
+ clearSelectedElement(board);
3798
+ }
3799
+ else {
3800
+ if (selectedImageElement) {
3801
+ const component = PlaitElement.getComponent(selectedImageElement);
3802
+ component && component.imageDrawer.destroyActive();
3803
+ }
3804
+ selectedImageElement = null;
3805
+ }
3806
+ mousedown(event);
3807
+ };
3808
+ board.keydown = (event) => {
3809
+ if (!PlaitBoard.isReadonly(board) && selectedImageElement && (hotkeys.isDeleteBackward(event) || hotkeys.isDeleteForward(event))) {
3810
+ MindTransforms.removeImage(board, selectedImageElement);
3811
+ selectedImageElement = null;
3812
+ return;
3813
+ }
3814
+ keydown(event);
3815
+ };
3816
+ return board;
3817
+ };
3818
+
3598
3819
  const withMind = (board) => {
3599
3820
  const { drawElement, dblclick, keydown, insertFragment, setFragment, deleteFragment, isHitSelection, getRectangle, isMovable, isRecursion } = board;
3600
3821
  board.drawElement = (context) => {
@@ -3712,7 +3933,7 @@ const withMind = (board) => {
3712
3933
  MindTransforms.removeElements(board, selectedElements);
3713
3934
  deleteFragment(data);
3714
3935
  };
3715
- return withNodeHover(withMindHotkey(withMindExtend(withCreateMind(withAbstract(withNodeDnd(board))))));
3936
+ return withMindImage(withNodeHover(withMindHotkey(withMindExtend(withCreateMind(withAbstract(withNodeDnd(board)))))));
3716
3937
  };
3717
3938
 
3718
3939
  class MindEmojiBaseComponent {
@@ -3766,5 +3987,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImpor
3766
3987
  * Generated bundle index. Do not edit.
3767
3988
  */
3768
3989
 
3769
- export { ABSTRACT_HANDLE_COLOR, ABSTRACT_HANDLE_LENGTH, ABSTRACT_HANDLE_MASK_WIDTH, ABSTRACT_INCLUDED_OUTLINE_OFFSET, AbstractHandlePosition, AbstractResizeState, BASE, BRANCH_FONT_FAMILY, BRANCH_WIDTH, BaseDrawer, BranchShape, DEFAULT_FONT_FAMILY, 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 };
3990
+ export { ABSTRACT_HANDLE_COLOR, ABSTRACT_HANDLE_LENGTH, ABSTRACT_HANDLE_MASK_WIDTH, ABSTRACT_INCLUDED_OUTLINE_OFFSET, AbstractHandlePosition, AbstractResizeState, BASE, BRANCH_FONT_FAMILY, BRANCH_WIDTH, BaseDrawer, BranchShape, DEFAULT_FONT_FAMILY, DefaultAbstractNodeStyle, DefaultNodeStyle, ELEMENT_TO_NODE, EXTEND_DIAMETER, EXTEND_OFFSET, GRAY_COLOR, INHERIT_ATTRIBUTE_KEYS, IS_DRAGGING, LayoutDirection, LayoutDirectionsMap, MindColorfulThemeColor, MindDarkThemeColor, MindDefaultThemeColor, MindElement, MindElementShape, MindEmojiBaseComponent, MindImageBaseComponent, 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, WithMindPluginKey, 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, getImageForeignRectangle, 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, isChildOfAbstract, isChildRight, isChildUp, isCorrectLayout, isDragging, isDropStandardRight, isHitEmojis, isHitImage, isHitMindElement, isInRightBranchOfStandardLayout, isMixedLayout, isSetAbstract, isValidTarget, isVirtualKey, removeActiveOnDragOrigin, separateChildren, setIsDragging, withMind, withMindExtend };
3770
3991
  //# sourceMappingURL=plait-mind.mjs.map