@plait/mind 0.23.0 → 0.24.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 (36) hide show
  1. package/base/image-base.component.d.ts +6 -4
  2. package/constants/image.d.ts +3 -0
  3. package/drawer/node-image.drawer.d.ts +1 -0
  4. package/esm2020/base/image-base.component.mjs +8 -2
  5. package/esm2020/constants/image.mjs +4 -0
  6. package/esm2020/drawer/node-image.drawer.mjs +9 -6
  7. package/esm2020/interfaces/element-data.mjs +1 -1
  8. package/esm2020/node.component.mjs +24 -17
  9. package/esm2020/plugins/with-node-image.mjs +20 -6
  10. package/esm2020/plugins/with-node-resize.mjs +3 -3
  11. package/esm2020/transforms/emoji.mjs +6 -2
  12. package/esm2020/transforms/image.mjs +22 -1
  13. package/esm2020/transforms/index.mjs +4 -3
  14. package/esm2020/utils/clipboard.mjs +5 -2
  15. package/esm2020/utils/index.mjs +3 -1
  16. package/esm2020/utils/node/adjust-node.mjs +3 -2
  17. package/esm2020/utils/node/dynamic-width.mjs +19 -0
  18. package/esm2020/utils/node/image.mjs +42 -2
  19. package/esm2020/utils/node/index.mjs +2 -1
  20. package/esm2020/utils/position/topic.mjs +2 -2
  21. package/esm2020/utils/space/index.mjs +4 -0
  22. package/esm2020/utils/space/node-space.mjs +15 -4
  23. package/fesm2015/plait-mind.mjs +522 -397
  24. package/fesm2015/plait-mind.mjs.map +1 -1
  25. package/fesm2020/plait-mind.mjs +526 -399
  26. package/fesm2020/plait-mind.mjs.map +1 -1
  27. package/node.component.d.ts +3 -2
  28. package/package.json +1 -1
  29. package/transforms/image.d.ts +2 -1
  30. package/transforms/index.d.ts +1 -0
  31. package/utils/index.d.ts +2 -0
  32. package/utils/node/dynamic-width.d.ts +7 -0
  33. package/utils/node/image.d.ts +2 -0
  34. package/utils/node/index.d.ts +1 -0
  35. package/utils/space/index.d.ts +3 -0
  36. package/utils/space/node-space.d.ts +9 -1
@@ -1,8 +1,8 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Directive, Input, Component, ChangeDetectionStrategy, NgModule, NgZone, 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, RectangleClient, PlaitElement, PlaitPluginKey, idCreator, isNullOrUndefined, Transforms, clearSelectedElement, addSelectedElement, PlaitNode, Path, PlaitBoard, depthFirstRecursion, getIsRecursionFunc, drawLinearPath, drawBezierPath, createG, updateForeignObject, drawRoundRectangle, getRectangleByElements, getSelectedElements, NODE_TO_PARENT, distanceBetweenPointAndRectangle, createForeignObject, createText, PlaitPointerType, PlaitPluginElementComponent, NODE_TO_INDEX, PlaitModule, isMainPointer, transformPoint, toPoint, getHitElements, distanceBetweenPointAndPoint, CLIP_BOARD_FORMAT_KEY, BOARD_TO_HOST, throttleRAF, BoardTransforms, removeSelectedElement, PlaitHistoryBoard, hotkeys, PRESS_AND_MOVE_BUFFER, MERGING, ResizeCursorClass } from '@plait/core';
5
- import { MindLayoutType, isIndentedLayout, AbstractNode, getNonAbstractChildren, isStandardLayout, isLeftLayout, isRightLayout, isVerticalLogicLayout, isHorizontalLogicLayout, isTopLayout, isBottomLayout, isHorizontalLayout, getCorrectStartEnd, getAbstractLayout, ConnectingPosition, GlobalLayout } from '@plait/layouts';
4
+ import { DefaultThemeColor, ColorfulThemeColor, SoftThemeColor, RetroThemeColor, DarkThemeColor, StarryThemeColor, RectangleClient, PlaitElement, PlaitPluginKey, idCreator, isNullOrUndefined, Transforms, clearSelectedElement, addSelectedElement, PlaitBoard, Path, PlaitNode, PlaitContextService, depthFirstRecursion, getIsRecursionFunc, drawLinearPath, drawBezierPath, createG, updateForeignObject, drawRoundRectangle, getRectangleByElements, getSelectedElements, NODE_TO_PARENT, distanceBetweenPointAndRectangle, createForeignObject, createText, PlaitPointerType, PlaitPluginElementComponent, NODE_TO_INDEX, PlaitModule, isMainPointer, transformPoint, toPoint, getHitElements, distanceBetweenPointAndPoint, CLIP_BOARD_FORMAT_KEY, BOARD_TO_HOST, throttleRAF, BoardTransforms, removeSelectedElement, PlaitHistoryBoard, hotkeys, PRESS_AND_MOVE_BUFFER, MERGING, ResizeCursorClass } from '@plait/core';
5
+ import { MindLayoutType, isIndentedLayout, AbstractNode, isStandardLayout, isHorizontalLogicLayout, isVerticalLogicLayout, getNonAbstractChildren, isLeftLayout, isRightLayout, isTopLayout, isBottomLayout, isHorizontalLayout, getCorrectStartEnd, ConnectingPosition, getAbstractLayout, GlobalLayout } from '@plait/layouts';
6
6
  import { PlaitMarkEditor, MarkTypes, DEFAULT_FONT_SIZE, TEXT_DEFAULT_HEIGHT, buildText, getTextSize, TextManage, ExitOrigin, TextModule, getTextFromClipboard } from '@plait/text';
7
7
  import { fromEvent, Subject } from 'rxjs';
8
8
  import { Node as Node$1, Path as Path$1 } from 'slate';
@@ -262,10 +262,10 @@ const NodeSpace = {
262
262
  return (NodeSpace.getEmojiLeftSpace(board, element) +
263
263
  getEmojisWidthHeight(board, element).width +
264
264
  getSpaceEmojiAndText(element) +
265
- NodeSpace.getNodeResizableWidth(board, element) +
265
+ NodeSpace.getNodeDynamicWidth(board, element) +
266
266
  nodeAndText);
267
267
  }
268
- return nodeAndText + NodeSpace.getNodeResizableWidth(board, element) + nodeAndText;
268
+ return nodeAndText + NodeSpace.getNodeDynamicWidth(board, element) + nodeAndText;
269
269
  },
270
270
  getNodeHeight(board, element) {
271
271
  const nodeAndText = getVerticalSpaceBetweenNodeAndText(board, element);
@@ -274,11 +274,22 @@ const NodeSpace = {
274
274
  }
275
275
  return nodeAndText + element.height + nodeAndText;
276
276
  },
277
- getNodeResizableWidth(board, element) {
277
+ getNodeDynamicWidth(board, element) {
278
278
  const width = element.manualWidth || element.width;
279
279
  const imageWidth = MindElement.hasImage(element) ? element.data.image?.width : 0;
280
280
  return Math.max(width, imageWidth);
281
281
  },
282
+ /**
283
+ * use this when upload image first or resize image
284
+ * @param board
285
+ * @param element
286
+ * @param imageWidth
287
+ * @returns
288
+ */
289
+ getNodeNewDynamicWidth(board, element, imageWidth) {
290
+ const width = element.manualWidth || element.width;
291
+ return Math.max(width, imageWidth);
292
+ },
282
293
  getNodeResizableMinWidth(board, element) {
283
294
  const minTopicWidth = NodeSpace.getNodeTopicMinWidth(board, element);
284
295
  if (MindElement.hasImage(element) && element.data.image.width > minTopicWidth) {
@@ -378,7 +389,7 @@ function getTopicRectangleByNode(board, node) {
378
389
  function getTopicRectangleByElement(board, nodeRectangle, element) {
379
390
  const x = nodeRectangle.x + NodeSpace.getTextLeftSpace(board, element);
380
391
  const y = nodeRectangle.y + NodeSpace.getTextTopSpace(board, element);
381
- const width = NodeSpace.getNodeResizableWidth(board, element);
392
+ const width = NodeSpace.getNodeDynamicWidth(board, element);
382
393
  const height = Math.ceil(element.height);
383
394
  return { height, width, x, y };
384
395
  }
@@ -691,7 +702,8 @@ const adjustNodeToRoot = (board, node) => {
691
702
  delete newElement?.isCollapsed;
692
703
  const { width, height } = getTextSize(board, newElement.data.topic, TOPIC_DEFAULT_MAX_WORD_COUNT, {
693
704
  fontSize: ROOT_TOPIC_FONT_SIZE,
694
- fontFamily: BRANCH_FONT_FAMILY
705
+ fontFamily: BRANCH_FONT_FAMILY,
706
+ width: node.manualWidth ? node.manualWidth : undefined
695
707
  });
696
708
  newElement.width = Math.max(width, getNodeDefaultFontSize(true));
697
709
  newElement.height = height;
@@ -703,28 +715,6 @@ const adjustNodeToRoot = (board, node) => {
703
715
  };
704
716
  };
705
717
 
706
- const BOARD_TO_SELECTED_IMAGE_ELEMENT = new WeakMap();
707
- const getSelectedImageElement = (board) => {
708
- return BOARD_TO_SELECTED_IMAGE_ELEMENT.get(board);
709
- };
710
- const addSelectedImageElement = (board, element) => {
711
- BOARD_TO_SELECTED_IMAGE_ELEMENT.set(board, element);
712
- };
713
- const removeSelectedImageElement = (board) => {
714
- BOARD_TO_SELECTED_IMAGE_ELEMENT.delete(board);
715
- };
716
- const setImageFocus = (board, element, isFocus) => {
717
- if (isFocus) {
718
- addSelectedImageElement(board, element);
719
- }
720
- else {
721
- removeSelectedImageElement(board);
722
- }
723
- const elementComponent = PlaitElement.getComponent(element);
724
- elementComponent.imageDrawer.componentRef.instance.isFocus = isFocus;
725
- elementComponent.imageDrawer.componentRef.instance.cdr.markForCheck();
726
- };
727
-
728
718
  const DefaultAbstractNodeStyle = {
729
719
  branch: { color: GRAY_COLOR, width: 2 },
730
720
  shape: {
@@ -743,8 +733,92 @@ const DefaultNodeStyle = {
743
733
  }
744
734
  };
745
735
 
746
- const getAvailableProperty = (board, element, propertyKey) => {
747
- return element[propertyKey];
736
+ const setAbstractsByRefs = (board, abstractRefs) => {
737
+ abstractRefs.forEach((newProperty, element) => {
738
+ const start = element.start + newProperty.start;
739
+ const end = element.end + newProperty.end;
740
+ const path = PlaitBoard.findPath(board, element);
741
+ if (start > end) {
742
+ Transforms.removeNode(board, path);
743
+ }
744
+ else {
745
+ Transforms.setNode(board, { start, end }, path);
746
+ }
747
+ });
748
+ };
749
+ const setAbstractByStandardLayout = (board, element) => {
750
+ const rightNodeCount = element.rightNodeCount;
751
+ const abstract = element.children.find(child => {
752
+ return AbstractNode.isAbstract(child) && child.end >= rightNodeCount && child.start < rightNodeCount;
753
+ });
754
+ if (abstract) {
755
+ const path = PlaitBoard.findPath(board, abstract);
756
+ Transforms.setNode(board, { end: rightNodeCount - 1 }, path);
757
+ }
758
+ };
759
+ const insertAbstract = (board, elements) => {
760
+ let elementGroup = getFirstLevelElement(elements);
761
+ const { parentElements, abstractIncludedGroups } = divideElementByParent(elementGroup);
762
+ abstractIncludedGroups.forEach((group, index) => {
763
+ const groupParent = parentElements[index];
764
+ setAbstractByElements(board, groupParent, group);
765
+ });
766
+ };
767
+ const setAbstractByElements = (board, groupParent, group) => {
768
+ const indexArray = group.map(child => groupParent.children.indexOf(child)).sort((a, b) => a - b);
769
+ const rightNodeCount = groupParent?.rightNodeCount;
770
+ const start = indexArray[0], end = indexArray[indexArray.length - 1];
771
+ if (isStandardLayout(MindQueries.getLayoutByElement(groupParent)) &&
772
+ rightNodeCount &&
773
+ start < rightNodeCount &&
774
+ end >= rightNodeCount) {
775
+ const childrenLength = groupParent.children.length;
776
+ const path = [...PlaitBoard.findPath(board, groupParent), childrenLength];
777
+ const leftChildren = indexArray.filter(index => index >= rightNodeCount);
778
+ const rightChildren = indexArray.filter(index => index < rightNodeCount);
779
+ insertAbstractNode(board, path, rightChildren[0], rightChildren[rightChildren.length - 1]);
780
+ insertAbstractNode(board, Path.next(path), leftChildren[0], leftChildren[leftChildren.length - 1]);
781
+ }
782
+ else {
783
+ const path = [...PlaitBoard.findPath(board, groupParent), groupParent.children.length];
784
+ insertAbstractNode(board, path, start, end);
785
+ }
786
+ };
787
+ const insertAbstractNode = (board, path, start, end) => {
788
+ const mindElement = createMindElement('概要', 28, 20, {
789
+ strokeWidth: DefaultAbstractNodeStyle.branch.width,
790
+ branchWidth: DefaultAbstractNodeStyle.branch.width
791
+ });
792
+ mindElement.start = start;
793
+ mindElement.end = end;
794
+ Transforms.insertNode(board, mindElement, path);
795
+ clearSelectedElement(board);
796
+ addSelectedElement(board, mindElement);
797
+ };
798
+
799
+ const setLayout = (board, layout, path) => {
800
+ correctLogicLayoutNode(board, layout, path);
801
+ const element = PlaitNode.get(board, path);
802
+ if (PlaitMind.isMind(element) && isStandardLayout(layout)) {
803
+ MindTransforms.setAbstractByStandardLayout(board, element);
804
+ }
805
+ Transforms.setNode(board, { layout }, path);
806
+ };
807
+ const correctLogicLayoutNode = (board, layout, path) => {
808
+ const node = PlaitNode.get(board, path);
809
+ if (node && layout) {
810
+ node.children?.forEach((value, index) => {
811
+ if (value.layout) {
812
+ if ((isHorizontalLogicLayout(layout) && isVerticalLogicLayout(value.layout)) ||
813
+ (isVerticalLogicLayout(layout) && isHorizontalLogicLayout(value.layout))) {
814
+ Transforms.setNode(board, { layout: null }, [...path, index]);
815
+ }
816
+ if (value.children?.length) {
817
+ correctLogicLayoutNode(board, layout, [...path, index]);
818
+ }
819
+ }
820
+ });
821
+ }
748
822
  };
749
823
 
750
824
  const separateChildren = (parentElement) => {
@@ -909,9 +983,257 @@ const deleteElementHandleAbstract = (board, deletableElements, effectedAbstracts
909
983
  });
910
984
  return effectedAbstracts;
911
985
  };
912
- const isChildOfAbstract = (board, element) => {
913
- const ancestors = MindElement.getAncestors(board, element);
914
- return !!ancestors.find((value) => AbstractNode.isAbstract(value));
986
+ const isChildOfAbstract = (board, element) => {
987
+ const ancestors = MindElement.getAncestors(board, element);
988
+ return !!ancestors.find((value) => AbstractNode.isAbstract(value));
989
+ };
990
+
991
+ const normalizeWidthAndHeight = (board, element, width, height) => {
992
+ const minWidth = NodeSpace.getNodeTopicMinWidth(board, element, element.isRoot);
993
+ const newWidth = width < minWidth * board.viewport.zoom ? minWidth : width / board.viewport.zoom;
994
+ const newHeight = height / board.viewport.zoom;
995
+ return { width: newWidth, height: newHeight };
996
+ };
997
+ const setTopic = (board, element, topic, width, height) => {
998
+ const newElement = {
999
+ data: { ...element.data, topic },
1000
+ ...normalizeWidthAndHeight(board, element, width, height)
1001
+ };
1002
+ const path = PlaitBoard.findPath(board, element);
1003
+ Transforms.setNode(board, newElement, path);
1004
+ };
1005
+ const setNodeManualWidth = (board, element, width, height) => {
1006
+ const path = PlaitBoard.findPath(board, element);
1007
+ const { width: normalizedWidth, height: normalizedHeight } = normalizeWidthAndHeight(board, element, width, height);
1008
+ const newElement = { manualWidth: normalizedWidth, height: normalizedHeight };
1009
+ Transforms.setNode(board, newElement, path);
1010
+ };
1011
+ const setTopicSize = (board, element, width, height) => {
1012
+ const newElement = {
1013
+ ...normalizeWidthAndHeight(board, element, width, height)
1014
+ };
1015
+ let isEqualWidth = Math.ceil(element.width) === Math.ceil(newElement.width);
1016
+ let isEqualHeight = Math.ceil(element.height) === Math.ceil(newElement.height);
1017
+ if (element.manualWidth) {
1018
+ isEqualWidth = true;
1019
+ }
1020
+ if (!isEqualWidth || !isEqualHeight) {
1021
+ const path = PlaitBoard.findPath(board, element);
1022
+ Transforms.setNode(board, newElement, path);
1023
+ }
1024
+ };
1025
+ const removeElements = (board, elements) => {
1026
+ const deletableElements = getFirstLevelElement(elements);
1027
+ deletableElements
1028
+ .map(element => {
1029
+ const path = PlaitBoard.findPath(board, element);
1030
+ const ref = board.pathRef(path);
1031
+ return () => {
1032
+ Transforms.removeNode(board, ref.current);
1033
+ ref.unref();
1034
+ };
1035
+ })
1036
+ .forEach(action => {
1037
+ action();
1038
+ });
1039
+ };
1040
+ const insertNodes = (board, elements, path) => {
1041
+ const pathRef = board.pathRef(path);
1042
+ elements.forEach(element => {
1043
+ if (pathRef.current) {
1044
+ Transforms.insertNode(board, element, pathRef.current);
1045
+ }
1046
+ });
1047
+ pathRef.unref();
1048
+ };
1049
+ const insertAbstractNodes = (board, validAbstractRefs, elements, path) => {
1050
+ const parent = PlaitNode.get(board, Path$1.parent(path));
1051
+ const abstractPath = [...Path$1.parent(path), parent.children?.length];
1052
+ const abstracts = validAbstractRefs.map(refs => {
1053
+ const { start, end } = getRelativeStartEndByAbstractRef(refs, elements);
1054
+ return {
1055
+ ...refs.abstract,
1056
+ start: start + path[path.length - 1],
1057
+ end: end + path[path.length - 1]
1058
+ };
1059
+ });
1060
+ insertNodes(board, abstracts, abstractPath);
1061
+ };
1062
+ const setRightNodeCountByRefs = (board, refs) => {
1063
+ refs.forEach(ref => {
1064
+ Transforms.setNode(board, { rightNodeCount: ref.rightNodeCount }, ref.path);
1065
+ });
1066
+ };
1067
+
1068
+ const addEmoji = (board, element, emojiItem) => {
1069
+ const emojis = element.data.emojis || [];
1070
+ const newEmojis = [...emojis];
1071
+ newEmojis.push(emojiItem);
1072
+ const newElement = {
1073
+ data: { ...element.data, emojis: newEmojis }
1074
+ };
1075
+ const path = PlaitBoard.findPath(board, element);
1076
+ Transforms.setNode(board, newElement, path);
1077
+ };
1078
+ const removeEmoji = (board, element, emojiItem) => {
1079
+ const emojis = element.data.emojis.filter(value => value !== emojiItem);
1080
+ const newElement = {
1081
+ data: { topic: element.data.topic }
1082
+ };
1083
+ if (MindElement.hasImage(element)) {
1084
+ newElement.data.image = element.data.image;
1085
+ }
1086
+ if (emojis.length > 0) {
1087
+ newElement.data.emojis = emojis;
1088
+ }
1089
+ const path = PlaitBoard.findPath(board, element);
1090
+ Transforms.setNode(board, newElement, path);
1091
+ };
1092
+ const replaceEmoji = (board, element, oldEmoji, newEmoji) => {
1093
+ const newElement = {
1094
+ data: { ...element.data }
1095
+ };
1096
+ const newEmojis = element.data.emojis.map(value => {
1097
+ if (value === oldEmoji) {
1098
+ return newEmoji;
1099
+ }
1100
+ return value;
1101
+ });
1102
+ newElement.data.emojis = newEmojis;
1103
+ const path = PlaitBoard.findPath(board, element);
1104
+ Transforms.setNode(board, newElement, path);
1105
+ };
1106
+
1107
+ /**
1108
+ * 1. return new node height if height changed
1109
+ * 2. new height is effected by zoom
1110
+ */
1111
+ const getNewNodeHeight = (board, element, newNodeDynamicWidth) => {
1112
+ const textManage = PlaitElement.getComponent(element).textManage;
1113
+ const { height } = textManage.getSize();
1114
+ textManage.updateWidth(newNodeDynamicWidth);
1115
+ const { height: newHeight } = textManage.getSize();
1116
+ if (!element.manualWidth) {
1117
+ textManage.updateWidth(0);
1118
+ }
1119
+ if (height !== newHeight) {
1120
+ return newHeight;
1121
+ }
1122
+ return undefined;
1123
+ };
1124
+
1125
+ const removeImage = (board, element) => {
1126
+ setImageFocus(board, element, false);
1127
+ const newElement = {
1128
+ data: { ...element.data }
1129
+ };
1130
+ delete newElement.data.image;
1131
+ const path = PlaitBoard.findPath(board, element);
1132
+ const newDynamicWidth = NodeSpace.getNodeNewDynamicWidth(board, element, 0);
1133
+ const newHeight = getNewNodeHeight(board, element, newDynamicWidth);
1134
+ if (newHeight) {
1135
+ newElement.height = newHeight / board.viewport.zoom;
1136
+ }
1137
+ Transforms.setNode(board, newElement, path);
1138
+ };
1139
+ const setImage = (board, element, imageItem) => {
1140
+ const newElement = {
1141
+ data: { ...element.data, image: imageItem }
1142
+ };
1143
+ const newDynamicWidth = NodeSpace.getNodeNewDynamicWidth(board, element, imageItem.width);
1144
+ const newHeight = getNewNodeHeight(board, element, newDynamicWidth);
1145
+ if (newHeight) {
1146
+ newElement.height = newHeight / board.viewport.zoom;
1147
+ }
1148
+ const path = PlaitBoard.findPath(board, element);
1149
+ Transforms.setNode(board, newElement, path);
1150
+ };
1151
+
1152
+ const MindTransforms = {
1153
+ setLayout,
1154
+ setTopic,
1155
+ setTopicSize,
1156
+ setNodeManualWidth,
1157
+ addEmoji,
1158
+ removeEmoji,
1159
+ replaceEmoji,
1160
+ insertAbstract,
1161
+ setAbstractsByRefs,
1162
+ setAbstractByStandardLayout,
1163
+ removeElements,
1164
+ insertNodes,
1165
+ insertAbstractNodes,
1166
+ setRightNodeCountByRefs,
1167
+ removeImage,
1168
+ setImage
1169
+ };
1170
+
1171
+ const PICTURE_ACCEPTED_UPLOAD_SIZE = 20;
1172
+ const acceptImageTypes = ['png', 'jpeg', 'gif', 'bmp'];
1173
+ const DEFAULT_IMAGE_WIDTH = 240;
1174
+
1175
+ const BOARD_TO_SELECTED_IMAGE_ELEMENT = new WeakMap();
1176
+ const getSelectedImageElement = (board) => {
1177
+ return BOARD_TO_SELECTED_IMAGE_ELEMENT.get(board);
1178
+ };
1179
+ const addSelectedImageElement = (board, element) => {
1180
+ BOARD_TO_SELECTED_IMAGE_ELEMENT.set(board, element);
1181
+ };
1182
+ const removeSelectedImageElement = (board) => {
1183
+ BOARD_TO_SELECTED_IMAGE_ELEMENT.delete(board);
1184
+ };
1185
+ const setImageFocus = (board, element, isFocus) => {
1186
+ if (isFocus) {
1187
+ addSelectedImageElement(board, element);
1188
+ }
1189
+ else {
1190
+ removeSelectedImageElement(board);
1191
+ }
1192
+ const elementComponent = PlaitElement.getComponent(element);
1193
+ elementComponent.imageDrawer.componentRef.instance.isFocus = isFocus;
1194
+ elementComponent.imageDrawer.componentRef.instance.cdr.markForCheck();
1195
+ };
1196
+ const selectImage = (board, element, acceptImageTypes = ['png', 'jpeg', 'gif', 'bmp']) => {
1197
+ const inputFile = document.createElement('input');
1198
+ inputFile.setAttribute('type', 'file');
1199
+ const acceptImageTypesString = '.' + acceptImageTypes.join(',.');
1200
+ inputFile.setAttribute('accept', acceptImageTypesString);
1201
+ inputFile.onchange = (event) => {
1202
+ buildImage(board, element, event.target.files[0]);
1203
+ };
1204
+ inputFile.click();
1205
+ };
1206
+ const buildImage = async (board, element, imageFile) => {
1207
+ let width = 0, height = 0;
1208
+ await getImageSize(imageFile).then((value) => {
1209
+ width = value.width;
1210
+ height = value.height;
1211
+ });
1212
+ let imageItem = null;
1213
+ const url = URL.createObjectURL(imageFile);
1214
+ const context = PlaitBoard.getComponent(board).viewContainerRef.injector.get(PlaitContextService);
1215
+ context.setUploadingFile({ url, file: imageFile });
1216
+ imageItem = {
1217
+ url,
1218
+ width,
1219
+ height
1220
+ };
1221
+ MindTransforms.setImage(board, element, imageItem);
1222
+ };
1223
+ function getImageSize(file, defaultImageWidth = DEFAULT_IMAGE_WIDTH) {
1224
+ return new Promise((resolve, reject) => {
1225
+ const image = new Image();
1226
+ image.src = URL.createObjectURL(file);
1227
+ image.onload = function () {
1228
+ const width = defaultImageWidth;
1229
+ const height = (defaultImageWidth * image.naturalHeight) / image.naturalWidth;
1230
+ resolve(image.naturalWidth > defaultImageWidth ? { width, height } : { width: image.naturalWidth, height: image.naturalHeight });
1231
+ };
1232
+ });
1233
+ }
1234
+
1235
+ const getAvailableProperty = (board, element, propertyKey) => {
1236
+ return element[propertyKey];
915
1237
  };
916
1238
 
917
1239
  /**
@@ -1864,6 +2186,73 @@ const deleteElementsHandleRightNodeCount = (board, deletableElements, effectedRi
1864
2186
  return effectedRightNodeCount;
1865
2187
  };
1866
2188
 
2189
+ const getLayoutOptions = (board) => {
2190
+ function getMainAxle(element, parent) {
2191
+ const strokeWidth = element.strokeWidth || STROKE_WIDTH;
2192
+ if (element.isRoot) {
2193
+ return BASE * 12;
2194
+ }
2195
+ if (parent && parent.isRoot()) {
2196
+ return BASE * 3 + strokeWidth / 2;
2197
+ }
2198
+ return BASE * 3 + strokeWidth / 2;
2199
+ }
2200
+ function getSecondAxle(element, parent) {
2201
+ const strokeWidth = element.strokeWidth || STROKE_WIDTH;
2202
+ if (element.isRoot) {
2203
+ return BASE * 10 + strokeWidth / 2;
2204
+ }
2205
+ return BASE * 6 + strokeWidth / 2;
2206
+ }
2207
+ return {
2208
+ getHeight(element) {
2209
+ return NodeSpace.getNodeHeight(board, element);
2210
+ },
2211
+ getWidth(element) {
2212
+ return NodeSpace.getNodeWidth(board, element);
2213
+ },
2214
+ getHorizontalGap(element, parent) {
2215
+ const _layout = (parent && parent.layout) || getRootLayout(element);
2216
+ const isHorizontal = isHorizontalLayout(_layout);
2217
+ const strokeWidth = element.strokeWidth || STROKE_WIDTH;
2218
+ if (isIndentedLayout(_layout)) {
2219
+ return BASE * 4 + strokeWidth;
2220
+ }
2221
+ if (!isHorizontal) {
2222
+ return getMainAxle(element, parent);
2223
+ }
2224
+ else {
2225
+ return getSecondAxle(element, parent);
2226
+ }
2227
+ },
2228
+ getVerticalGap(element, parent) {
2229
+ const _layout = (parent && parent.layout) || getRootLayout(element);
2230
+ if (isIndentedLayout(_layout)) {
2231
+ return BASE;
2232
+ }
2233
+ const isHorizontal = isHorizontalLayout(_layout);
2234
+ if (isHorizontal) {
2235
+ return getMainAxle(element, parent);
2236
+ }
2237
+ else {
2238
+ return getSecondAxle(element, parent);
2239
+ }
2240
+ },
2241
+ getVerticalConnectingPosition(element, parent) {
2242
+ if (element.shape === MindElementShape.underline && parent && isHorizontalLogicLayout(parent.layout)) {
2243
+ return ConnectingPosition.bottom;
2244
+ }
2245
+ return undefined;
2246
+ },
2247
+ getExtendHeight(node) {
2248
+ return BASE * 6;
2249
+ },
2250
+ getIndentedCrossLevelGap() {
2251
+ return BASE * 2;
2252
+ }
2253
+ };
2254
+ };
2255
+
1867
2256
  /**
1868
2257
  * get correctly layout:
1869
2258
  * 1. root is standard -> left or right
@@ -2223,249 +2612,21 @@ class NodeEmojisDrawer {
2223
2612
  drawer.draw(emojiItem, element);
2224
2613
  return drawer;
2225
2614
  });
2226
- this.emojiDrawers.forEach(drawer => {
2227
- container.append(drawer.nativeElement);
2228
- });
2229
- return this.g;
2230
- }
2231
- return undefined;
2232
- }
2233
- destroy() {
2234
- if (this.g) {
2235
- this.g.remove();
2236
- }
2237
- this.emojiDrawers.forEach(drawer => drawer.destroy());
2238
- this.emojiDrawers = [];
2239
- }
2240
- }
2241
-
2242
- const setAbstractsByRefs = (board, abstractRefs) => {
2243
- abstractRefs.forEach((newProperty, element) => {
2244
- const start = element.start + newProperty.start;
2245
- const end = element.end + newProperty.end;
2246
- const path = PlaitBoard.findPath(board, element);
2247
- if (start > end) {
2248
- Transforms.removeNode(board, path);
2249
- }
2250
- else {
2251
- Transforms.setNode(board, { start, end }, path);
2252
- }
2253
- });
2254
- };
2255
- const setAbstractByStandardLayout = (board, element) => {
2256
- const rightNodeCount = element.rightNodeCount;
2257
- const abstract = element.children.find(child => {
2258
- return AbstractNode.isAbstract(child) && child.end >= rightNodeCount && child.start < rightNodeCount;
2259
- });
2260
- if (abstract) {
2261
- const path = PlaitBoard.findPath(board, abstract);
2262
- Transforms.setNode(board, { end: rightNodeCount - 1 }, path);
2263
- }
2264
- };
2265
- const insertAbstract = (board, elements) => {
2266
- let elementGroup = getFirstLevelElement(elements);
2267
- const { parentElements, abstractIncludedGroups } = divideElementByParent(elementGroup);
2268
- abstractIncludedGroups.forEach((group, index) => {
2269
- const groupParent = parentElements[index];
2270
- setAbstractByElements(board, groupParent, group);
2271
- });
2272
- };
2273
- const setAbstractByElements = (board, groupParent, group) => {
2274
- const indexArray = group.map(child => groupParent.children.indexOf(child)).sort((a, b) => a - b);
2275
- const rightNodeCount = groupParent?.rightNodeCount;
2276
- const start = indexArray[0], end = indexArray[indexArray.length - 1];
2277
- if (isStandardLayout(MindQueries.getLayoutByElement(groupParent)) &&
2278
- rightNodeCount &&
2279
- start < rightNodeCount &&
2280
- end >= rightNodeCount) {
2281
- const childrenLength = groupParent.children.length;
2282
- const path = [...PlaitBoard.findPath(board, groupParent), childrenLength];
2283
- const leftChildren = indexArray.filter(index => index >= rightNodeCount);
2284
- const rightChildren = indexArray.filter(index => index < rightNodeCount);
2285
- insertAbstractNode(board, path, rightChildren[0], rightChildren[rightChildren.length - 1]);
2286
- insertAbstractNode(board, Path.next(path), leftChildren[0], leftChildren[leftChildren.length - 1]);
2287
- }
2288
- else {
2289
- const path = [...PlaitBoard.findPath(board, groupParent), groupParent.children.length];
2290
- insertAbstractNode(board, path, start, end);
2291
- }
2292
- };
2293
- const insertAbstractNode = (board, path, start, end) => {
2294
- const mindElement = createMindElement('概要', 28, 20, {
2295
- strokeWidth: DefaultAbstractNodeStyle.branch.width,
2296
- branchWidth: DefaultAbstractNodeStyle.branch.width
2297
- });
2298
- mindElement.start = start;
2299
- mindElement.end = end;
2300
- Transforms.insertNode(board, mindElement, path);
2301
- clearSelectedElement(board);
2302
- addSelectedElement(board, mindElement);
2303
- };
2304
-
2305
- const setLayout = (board, layout, path) => {
2306
- correctLogicLayoutNode(board, layout, path);
2307
- const element = PlaitNode.get(board, path);
2308
- if (PlaitMind.isMind(element) && isStandardLayout(layout)) {
2309
- MindTransforms.setAbstractByStandardLayout(board, element);
2310
- }
2311
- Transforms.setNode(board, { layout }, path);
2312
- };
2313
- const correctLogicLayoutNode = (board, layout, path) => {
2314
- const node = PlaitNode.get(board, path);
2315
- if (node && layout) {
2316
- node.children?.forEach((value, index) => {
2317
- if (value.layout) {
2318
- if ((isHorizontalLogicLayout(layout) && isVerticalLogicLayout(value.layout)) ||
2319
- (isVerticalLogicLayout(layout) && isHorizontalLogicLayout(value.layout))) {
2320
- Transforms.setNode(board, { layout: null }, [...path, index]);
2321
- }
2322
- if (value.children?.length) {
2323
- correctLogicLayoutNode(board, layout, [...path, index]);
2324
- }
2325
- }
2326
- });
2327
- }
2328
- };
2329
-
2330
- const normalizeWidthAndHeight = (board, element, width, height) => {
2331
- const minWidth = NodeSpace.getNodeTopicMinWidth(board, element, element.isRoot);
2332
- const newWidth = width < minWidth * board.viewport.zoom ? minWidth : width / board.viewport.zoom;
2333
- const newHeight = height / board.viewport.zoom;
2334
- return { width: newWidth, height: newHeight };
2335
- };
2336
- const setTopic = (board, element, topic, width, height) => {
2337
- const newElement = {
2338
- data: { ...element.data, topic },
2339
- ...normalizeWidthAndHeight(board, element, width, height)
2340
- };
2341
- const path = PlaitBoard.findPath(board, element);
2342
- Transforms.setNode(board, newElement, path);
2343
- };
2344
- const setNodeManualWidth = (board, element, width, height) => {
2345
- const path = PlaitBoard.findPath(board, element);
2346
- const { width: normalizedWidth, height: normalizedHeight } = normalizeWidthAndHeight(board, element, width, height);
2347
- const newElement = { manualWidth: normalizedWidth, height: normalizedHeight };
2348
- Transforms.setNode(board, newElement, path);
2349
- };
2350
- const setTopicSize = (board, element, width, height) => {
2351
- const newElement = {
2352
- ...normalizeWidthAndHeight(board, element, width, height)
2353
- };
2354
- let isEqualWidth = Math.ceil(element.width) === Math.ceil(newElement.width);
2355
- let isEqualHeight = Math.ceil(element.height) === Math.ceil(newElement.height);
2356
- if (element.manualWidth) {
2357
- isEqualWidth = true;
2358
- }
2359
- if (!isEqualWidth || !isEqualHeight) {
2360
- const path = PlaitBoard.findPath(board, element);
2361
- Transforms.setNode(board, newElement, path);
2362
- }
2363
- };
2364
- const removeElements = (board, elements) => {
2365
- const deletableElements = getFirstLevelElement(elements);
2366
- deletableElements
2367
- .map(element => {
2368
- const path = PlaitBoard.findPath(board, element);
2369
- const ref = board.pathRef(path);
2370
- return () => {
2371
- Transforms.removeNode(board, ref.current);
2372
- ref.unref();
2373
- };
2374
- })
2375
- .forEach(action => {
2376
- action();
2377
- });
2378
- };
2379
- const insertNodes = (board, elements, path) => {
2380
- const pathRef = board.pathRef(path);
2381
- elements.forEach(element => {
2382
- if (pathRef.current) {
2383
- Transforms.insertNode(board, element, pathRef.current);
2615
+ this.emojiDrawers.forEach(drawer => {
2616
+ container.append(drawer.nativeElement);
2617
+ });
2618
+ return this.g;
2384
2619
  }
2385
- });
2386
- pathRef.unref();
2387
- };
2388
- const insertAbstractNodes = (board, validAbstractRefs, elements, path) => {
2389
- const parent = PlaitNode.get(board, Path$1.parent(path));
2390
- const abstractPath = [...Path$1.parent(path), parent.children?.length];
2391
- const abstracts = validAbstractRefs.map(refs => {
2392
- const { start, end } = getRelativeStartEndByAbstractRef(refs, elements);
2393
- return {
2394
- ...refs.abstract,
2395
- start: start + path[path.length - 1],
2396
- end: end + path[path.length - 1]
2397
- };
2398
- });
2399
- insertNodes(board, abstracts, abstractPath);
2400
- };
2401
- const setRightNodeCountByRefs = (board, refs) => {
2402
- refs.forEach(ref => {
2403
- Transforms.setNode(board, { rightNodeCount: ref.rightNodeCount }, ref.path);
2404
- });
2405
- };
2406
-
2407
- const addEmoji = (board, element, emojiItem) => {
2408
- const emojis = element.data.emojis || [];
2409
- const newEmojis = [...emojis];
2410
- newEmojis.push(emojiItem);
2411
- const newElement = {
2412
- data: { topic: element.data.topic, emojis: newEmojis }
2413
- };
2414
- const path = PlaitBoard.findPath(board, element);
2415
- Transforms.setNode(board, newElement, path);
2416
- };
2417
- const removeEmoji = (board, element, emojiItem) => {
2418
- const emojis = element.data.emojis.filter(value => value !== emojiItem);
2419
- const newElement = {
2420
- data: { topic: element.data.topic }
2421
- };
2422
- if (emojis.length > 0) {
2423
- newElement.data.emojis = emojis;
2620
+ return undefined;
2424
2621
  }
2425
- const path = PlaitBoard.findPath(board, element);
2426
- Transforms.setNode(board, newElement, path);
2427
- };
2428
- const replaceEmoji = (board, element, oldEmoji, newEmoji) => {
2429
- const newElement = {
2430
- data: { ...element.data }
2431
- };
2432
- const newEmojis = element.data.emojis.map(value => {
2433
- if (value === oldEmoji) {
2434
- return newEmoji;
2622
+ destroy() {
2623
+ if (this.g) {
2624
+ this.g.remove();
2435
2625
  }
2436
- return value;
2437
- });
2438
- newElement.data.emojis = newEmojis;
2439
- const path = PlaitBoard.findPath(board, element);
2440
- Transforms.setNode(board, newElement, path);
2441
- };
2442
-
2443
- const removeImage = (board, element) => {
2444
- const newElement = {
2445
- data: { ...element.data }
2446
- };
2447
- delete newElement.data.image;
2448
- const path = PlaitBoard.findPath(board, element);
2449
- Transforms.setNode(board, newElement, path);
2450
- };
2451
-
2452
- const MindTransforms = {
2453
- setLayout,
2454
- setTopic,
2455
- setTopicSize,
2456
- setNodeManualWidth,
2457
- addEmoji,
2458
- removeEmoji,
2459
- replaceEmoji,
2460
- insertAbstract,
2461
- setAbstractsByRefs,
2462
- setAbstractByStandardLayout,
2463
- removeElements,
2464
- insertNodes,
2465
- insertAbstractNodes,
2466
- setRightNodeCountByRefs,
2467
- removeImage
2468
- };
2626
+ this.emojiDrawers.forEach(drawer => drawer.destroy());
2627
+ this.emojiDrawers = [];
2628
+ }
2629
+ }
2469
2630
 
2470
2631
  class BaseDrawer {
2471
2632
  constructor(board) {
@@ -2824,36 +2985,6 @@ class CollapseDrawer extends BaseDrawer {
2824
2985
  }
2825
2986
  }
2826
2987
 
2827
- class MindImageBaseComponent {
2828
- get nativeElement() {
2829
- return this.elementRef.nativeElement;
2830
- }
2831
- constructor(elementRef, cdr) {
2832
- this.elementRef = elementRef;
2833
- this.cdr = cdr;
2834
- this.isFocus = false;
2835
- }
2836
- ngOnInit() { }
2837
- }
2838
- MindImageBaseComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.5", ngImport: i0, type: MindImageBaseComponent, deps: [{ token: i0.ElementRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive });
2839
- MindImageBaseComponent.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.5", type: MindImageBaseComponent, inputs: { imageItem: "imageItem", board: "board", element: "element", isFocus: "isFocus" }, host: { classAttribute: "mind-node-image" }, ngImport: i0 });
2840
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImport: i0, type: MindImageBaseComponent, decorators: [{
2841
- type: Directive,
2842
- args: [{
2843
- host: {
2844
- class: 'mind-node-image'
2845
- }
2846
- }]
2847
- }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { imageItem: [{
2848
- type: Input
2849
- }], board: [{
2850
- type: Input
2851
- }], element: [{
2852
- type: Input
2853
- }], isFocus: [{
2854
- type: Input
2855
- }] } });
2856
-
2857
2988
  class NodeImageDrawer {
2858
2989
  constructor(board, viewContainerRef) {
2859
2990
  this.board = board;
@@ -2867,9 +2998,9 @@ class NodeImageDrawer {
2867
2998
  }
2868
2999
  this.g = createG();
2869
3000
  const foreignRectangle = getImageForeignRectangle(this.board, element);
2870
- const foreignObject = createForeignObject(foreignRectangle.x, foreignRectangle.y, foreignRectangle.width, foreignRectangle.height);
2871
- this.g.append(foreignObject);
2872
- const componentType = this.board.getPluginOptions(WithMindPluginKey).imageComponentType || MindImageBaseComponent;
3001
+ this.foreignObject = createForeignObject(foreignRectangle.x, foreignRectangle.y, foreignRectangle.width, foreignRectangle.height);
3002
+ this.g.append(this.foreignObject);
3003
+ const componentType = this.board.getPluginOptions(WithMindPluginKey).imageComponentType;
2873
3004
  if (!componentType) {
2874
3005
  throw new Error('Not implement drawEmoji method error.');
2875
3006
  }
@@ -2878,7 +3009,7 @@ class NodeImageDrawer {
2878
3009
  this.componentRef.instance.element = element;
2879
3010
  this.componentRef.instance.imageItem = element.data.image;
2880
3011
  this.componentRef.instance.cdr.markForCheck();
2881
- foreignObject.append(this.componentRef.instance.nativeElement);
3012
+ this.foreignObject.append(this.componentRef.instance.nativeElement);
2882
3013
  nodeG.appendChild(this.g);
2883
3014
  }
2884
3015
  updateImage(nodeG, previous, current) {
@@ -2892,6 +3023,10 @@ class NodeImageDrawer {
2892
3023
  }
2893
3024
  const currentForeignObject = getImageForeignRectangle(this.board, current);
2894
3025
  updateForeignObject(this.g, currentForeignObject.width, currentForeignObject.height, currentForeignObject.x, currentForeignObject.y);
3026
+ // solve image lose on move node
3027
+ if (this.foreignObject.children.length === 0) {
3028
+ this.foreignObject.append(this.componentRef.instance.nativeElement);
3029
+ }
2895
3030
  this.componentRef?.instance.cdr.markForCheck();
2896
3031
  }
2897
3032
  destroy() {
@@ -2951,7 +3086,7 @@ class MindNodeComponent extends PlaitPluginElementComponent {
2951
3086
  this.parentG = PlaitElement.getComponent(MindElement.getRoot(this.board, this.element)).rootG;
2952
3087
  this.drawShape();
2953
3088
  this.drawLink();
2954
- this.drawText();
3089
+ this.drawTopic();
2955
3090
  this.activeDrawer.draw(this.element, this.g, { selected: this.selected, isEditing: this.textManage.isEditing });
2956
3091
  this.drawEmojis();
2957
3092
  this.drawExtend();
@@ -2960,18 +3095,6 @@ class MindNodeComponent extends PlaitPluginElementComponent {
2960
3095
  this.g.classList.add('branch');
2961
3096
  }
2962
3097
  }
2963
- editTopic() {
2964
- this.activeDrawer.draw(this.element, this.g, { selected: this.selected, isEditing: true });
2965
- if (this.element.manualWidth) {
2966
- const width = NodeSpace.getNodeResizableWidth(this.board, this.element);
2967
- this.textManage.updateWidth(width);
2968
- }
2969
- this.textManage.edit((origin) => {
2970
- if (origin === ExitOrigin.default) {
2971
- this.activeDrawer.draw(this.element, this.g, { selected: this.selected, isEditing: false });
2972
- }
2973
- });
2974
- }
2975
3098
  onContextChanged(value, previous) {
2976
3099
  const newNode = MindElement.getNode(value.element);
2977
3100
  const isEqualNode = RectangleClient.isEqual(this.node, newNode);
@@ -2984,8 +3107,7 @@ class MindNodeComponent extends PlaitPluginElementComponent {
2984
3107
  this.drawEmojis();
2985
3108
  this.drawExtend();
2986
3109
  this.imageDrawer.updateImage(this.g, previous.element, value.element);
2987
- this.textManage.updateText(this.element.data.topic);
2988
- this.textManage.updateRectangle();
3110
+ this.updateTopic();
2989
3111
  }
2990
3112
  else {
2991
3113
  const hasSameSelected = value.selected === previous.selected;
@@ -3064,9 +3186,29 @@ class MindNodeComponent extends PlaitPluginElementComponent {
3064
3186
  this.extendG.remove();
3065
3187
  }
3066
3188
  }
3067
- drawText() {
3189
+ drawTopic() {
3068
3190
  this.textManage.draw(this.element.data.topic);
3069
3191
  this.g.append(this.textManage.g);
3192
+ if (this.element.manualWidth) {
3193
+ const width = NodeSpace.getNodeDynamicWidth(this.board, this.element);
3194
+ this.textManage.updateWidth(width);
3195
+ }
3196
+ }
3197
+ updateTopic() {
3198
+ this.textManage.updateText(this.element.data.topic);
3199
+ this.textManage.updateRectangle();
3200
+ if (this.element.manualWidth) {
3201
+ const width = NodeSpace.getNodeDynamicWidth(this.board, this.element);
3202
+ this.textManage.updateWidth(width);
3203
+ }
3204
+ }
3205
+ editTopic() {
3206
+ this.activeDrawer.draw(this.element, this.g, { selected: this.selected, isEditing: true });
3207
+ this.textManage.edit((origin) => {
3208
+ if (origin === ExitOrigin.default) {
3209
+ this.activeDrawer.draw(this.element, this.g, { selected: this.selected, isEditing: false });
3210
+ }
3211
+ });
3070
3212
  }
3071
3213
  ngOnDestroy() {
3072
3214
  super.ngOnDestroy();
@@ -3107,73 +3249,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImpor
3107
3249
  }]
3108
3250
  }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }, { type: i0.ChangeDetectorRef }]; } });
3109
3251
 
3110
- const getLayoutOptions = (board) => {
3111
- function getMainAxle(element, parent) {
3112
- const strokeWidth = element.strokeWidth || STROKE_WIDTH;
3113
- if (element.isRoot) {
3114
- return BASE * 12;
3115
- }
3116
- if (parent && parent.isRoot()) {
3117
- return BASE * 3 + strokeWidth / 2;
3118
- }
3119
- return BASE * 3 + strokeWidth / 2;
3120
- }
3121
- function getSecondAxle(element, parent) {
3122
- const strokeWidth = element.strokeWidth || STROKE_WIDTH;
3123
- if (element.isRoot) {
3124
- return BASE * 10 + strokeWidth / 2;
3125
- }
3126
- return BASE * 6 + strokeWidth / 2;
3127
- }
3128
- return {
3129
- getHeight(element) {
3130
- return NodeSpace.getNodeHeight(board, element);
3131
- },
3132
- getWidth(element) {
3133
- return NodeSpace.getNodeWidth(board, element);
3134
- },
3135
- getHorizontalGap(element, parent) {
3136
- const _layout = (parent && parent.layout) || getRootLayout(element);
3137
- const isHorizontal = isHorizontalLayout(_layout);
3138
- const strokeWidth = element.strokeWidth || STROKE_WIDTH;
3139
- if (isIndentedLayout(_layout)) {
3140
- return BASE * 4 + strokeWidth;
3141
- }
3142
- if (!isHorizontal) {
3143
- return getMainAxle(element, parent);
3144
- }
3145
- else {
3146
- return getSecondAxle(element, parent);
3147
- }
3148
- },
3149
- getVerticalGap(element, parent) {
3150
- const _layout = (parent && parent.layout) || getRootLayout(element);
3151
- if (isIndentedLayout(_layout)) {
3152
- return BASE;
3153
- }
3154
- const isHorizontal = isHorizontalLayout(_layout);
3155
- if (isHorizontal) {
3156
- return getMainAxle(element, parent);
3157
- }
3158
- else {
3159
- return getSecondAxle(element, parent);
3160
- }
3161
- },
3162
- getVerticalConnectingPosition(element, parent) {
3163
- if (element.shape === MindElementShape.underline && parent && isHorizontalLogicLayout(parent.layout)) {
3164
- return ConnectingPosition.bottom;
3165
- }
3166
- return undefined;
3167
- },
3168
- getExtendHeight(node) {
3169
- return BASE * 6;
3170
- },
3171
- getIndentedCrossLevelGap() {
3172
- return BASE * 2;
3173
- }
3174
- };
3175
- };
3176
-
3177
3252
  class PlaitMindComponent extends MindNodeComponent {
3178
3253
  ngOnInit() {
3179
3254
  this.updateMindLayout();
@@ -3476,7 +3551,10 @@ const insertClipboardData = (board, elements, targetPoint) => {
3476
3551
  if (item.isRoot) {
3477
3552
  newElement = adjustRootToNode(board, newElement);
3478
3553
  const styles = PlaitMind.isMind(targetParent) ? { fontFamily: BRANCH_FONT_FAMILY } : { fontFamily: DEFAULT_FONT_FAMILY };
3479
- const { width, height } = getTextSize(board, newElement.data.topic, TOPIC_DEFAULT_MAX_WORD_COUNT, styles);
3554
+ const { width, height } = getTextSize(board, newElement.data.topic, TOPIC_DEFAULT_MAX_WORD_COUNT, {
3555
+ ...styles,
3556
+ width: newElement.manualWidth ? newElement.manualWidth : undefined
3557
+ });
3480
3558
  newElement.width = Math.max(width, getNodeDefaultFontSize());
3481
3559
  newElement.height = height;
3482
3560
  }
@@ -3906,7 +3984,7 @@ const withNodeHoverDetect = (board) => {
3906
3984
  };
3907
3985
 
3908
3986
  const withNodeImage = (board) => {
3909
- const { keydown, mousedown, globalMouseup } = board;
3987
+ const { keydown, mousedown, globalMouseup, insertFragment } = board;
3910
3988
  board.mousedown = (event) => {
3911
3989
  const selectedImageElement = getSelectedImageElement(board);
3912
3990
  if (PlaitBoard.isReadonly(board) || !isMainPointer(event) || !PlaitBoard.isPointer(board, PlaitPointerType.selection)) {
@@ -3932,7 +4010,6 @@ const withNodeImage = (board) => {
3932
4010
  if (hitImage) {
3933
4011
  temporaryDisableSelection(board);
3934
4012
  setImageFocus(board, hitElements[0], true);
3935
- clearSelectedElement(board);
3936
4013
  }
3937
4014
  mousedown(event);
3938
4015
  };
@@ -3940,7 +4017,6 @@ const withNodeImage = (board) => {
3940
4017
  const selectedImageElement = getSelectedImageElement(board);
3941
4018
  if (!PlaitBoard.isReadonly(board) && selectedImageElement && (hotkeys.isDeleteBackward(event) || hotkeys.isDeleteForward(event))) {
3942
4019
  addSelectedElement(board, selectedImageElement);
3943
- setImageFocus(board, selectedImageElement, false);
3944
4020
  MindTransforms.removeImage(board, selectedImageElement);
3945
4021
  return;
3946
4022
  }
@@ -3957,6 +4033,21 @@ const withNodeImage = (board) => {
3957
4033
  }
3958
4034
  globalMouseup(event);
3959
4035
  };
4036
+ board.insertFragment = (data, targetPoint) => {
4037
+ const selectedElements = getSelectedElements(board);
4038
+ const isSelectedImage = !!getSelectedImageElement(board);
4039
+ const isSingleSelection = selectedElements.length === 1 && MindElement.isMindElement(board, selectedElements[0]);
4040
+ if (data?.files.length && (isSingleSelection || isSelectedImage)) {
4041
+ const selectedElement = (selectedElements[0] || getSelectedImageElement(board));
4042
+ const acceptImageArray = acceptImageTypes.map(type => 'image/' + type);
4043
+ if (acceptImageArray.includes(data?.files[0].type)) {
4044
+ const imageFile = data.files[0];
4045
+ buildImage(board, selectedElement, imageFile);
4046
+ return;
4047
+ }
4048
+ }
4049
+ insertFragment(data, targetPoint);
4050
+ };
3960
4051
  return board;
3961
4052
  };
3962
4053
 
@@ -3986,7 +4077,7 @@ const withNodeResize = (board) => {
3986
4077
  addResizing(board, targetElement);
3987
4078
  targetElementRef = {
3988
4079
  minWidth: NodeSpace.getNodeResizableMinWidth(board, targetElement),
3989
- currentWidth: NodeSpace.getNodeResizableWidth(board, targetElement),
4080
+ currentWidth: NodeSpace.getNodeDynamicWidth(board, targetElement),
3990
4081
  path: PlaitBoard.findPath(board, targetElement),
3991
4082
  textManage: PlaitElement.getComponent(targetElement).textManage
3992
4083
  };
@@ -4002,7 +4093,7 @@ const withNodeResize = (board) => {
4002
4093
  const offsetX = endPoint[0] - startPoint[0];
4003
4094
  const zoom = board.viewport.zoom;
4004
4095
  let resizedWidth = targetElementRef.currentWidth + offsetX / zoom;
4005
- if (resizedWidth < targetElementRef.minWidth) {
4096
+ if (resizedWidth <= targetElementRef.minWidth) {
4006
4097
  resizedWidth = targetElementRef.minWidth;
4007
4098
  }
4008
4099
  const newTarget = PlaitNode.get(board, targetElementRef.path);
@@ -4229,6 +4320,42 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImpor
4229
4320
  args: ['mousedown']
4230
4321
  }] } });
4231
4322
 
4323
+ class MindImageBaseComponent {
4324
+ set imageItem(value) {
4325
+ this.afterImageItemChange(this._imageItem, value);
4326
+ this._imageItem = value;
4327
+ }
4328
+ get imageItem() {
4329
+ return this._imageItem;
4330
+ }
4331
+ get nativeElement() {
4332
+ return this.elementRef.nativeElement;
4333
+ }
4334
+ constructor(elementRef, cdr) {
4335
+ this.elementRef = elementRef;
4336
+ this.cdr = cdr;
4337
+ this.isFocus = false;
4338
+ }
4339
+ }
4340
+ MindImageBaseComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.5", ngImport: i0, type: MindImageBaseComponent, deps: [{ token: i0.ElementRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive });
4341
+ MindImageBaseComponent.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "15.2.5", type: MindImageBaseComponent, inputs: { imageItem: "imageItem", board: "board", element: "element", isFocus: "isFocus" }, host: { classAttribute: "mind-node-image" }, ngImport: i0 });
4342
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImport: i0, type: MindImageBaseComponent, decorators: [{
4343
+ type: Directive,
4344
+ args: [{
4345
+ host: {
4346
+ class: 'mind-node-image'
4347
+ }
4348
+ }]
4349
+ }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { imageItem: [{
4350
+ type: Input
4351
+ }], board: [{
4352
+ type: Input
4353
+ }], element: [{
4354
+ type: Input
4355
+ }], isFocus: [{
4356
+ type: Input
4357
+ }] } });
4358
+
4232
4359
  /*
4233
4360
  * Public API Surface of mind
4234
4361
  */
@@ -4237,5 +4364,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImpor
4237
4364
  * Generated bundle index. Do not edit.
4238
4365
  */
4239
4366
 
4240
- 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, 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, addSelectedImageElement, 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, getFillByElement, getFirstLevelElement, getHitAbstractHandle, getImageForeignRectangle, getInCorrectLayoutDirection, getLayoutDirection$1 as getLayoutDirection, getLayoutReverseDirection, getLocationScope, getMindThemeColor, getNextBranchColor, getOverallAbstracts, getPathByDropTarget, getRectangleByElement, getRectangleByNode, getRectangleByResizingLocation, getRelativeStartEndByAbstractRef, getRootLayout, getSelectedImageElement, getShapeByElement, getStrokeByMindElement, getStrokeWidthByElement, 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, removeSelectedImageElement, separateChildren, setImageFocus, setIsDragging, temporaryDisableSelection, withMind, withMindExtend };
4367
+ 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, NodeSpace, 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, addSelectedImageElement, adjustAbstractToNode, adjustNodeToRoot, adjustRootToNode, buildImage, 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, getEmojiFontSize, getEmojiForeignRectangle, getEmojiRectangle, getEmojisWidthHeight, getFillByElement, getFirstLevelElement, getFontSizeBySlateElement, getHitAbstractHandle, getImageForeignRectangle, getInCorrectLayoutDirection, getLayoutDirection$1 as getLayoutDirection, getLayoutOptions, getLayoutReverseDirection, getLocationScope, getMindThemeColor, getNewNodeHeight, getNextBranchColor, getNodeDefaultFontSize, getOverallAbstracts, getPathByDropTarget, getRectangleByElement, getRectangleByNode, getRectangleByResizingLocation, getRelativeStartEndByAbstractRef, getRootLayout, getSelectedImageElement, getShapeByElement, getStrokeByMindElement, getStrokeWidthByElement, 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, removeSelectedImageElement, selectImage, separateChildren, setImageFocus, setIsDragging, temporaryDisableSelection, withMind, withMindExtend };
4241
4368
  //# sourceMappingURL=plait-mind.mjs.map