@plait/mind 0.23.1 → 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.
@@ -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
  }
@@ -704,28 +715,6 @@ const adjustNodeToRoot = (board, node) => {
704
715
  };
705
716
  };
706
717
 
707
- const BOARD_TO_SELECTED_IMAGE_ELEMENT = new WeakMap();
708
- const getSelectedImageElement = (board) => {
709
- return BOARD_TO_SELECTED_IMAGE_ELEMENT.get(board);
710
- };
711
- const addSelectedImageElement = (board, element) => {
712
- BOARD_TO_SELECTED_IMAGE_ELEMENT.set(board, element);
713
- };
714
- const removeSelectedImageElement = (board) => {
715
- BOARD_TO_SELECTED_IMAGE_ELEMENT.delete(board);
716
- };
717
- const setImageFocus = (board, element, isFocus) => {
718
- if (isFocus) {
719
- addSelectedImageElement(board, element);
720
- }
721
- else {
722
- removeSelectedImageElement(board);
723
- }
724
- const elementComponent = PlaitElement.getComponent(element);
725
- elementComponent.imageDrawer.componentRef.instance.isFocus = isFocus;
726
- elementComponent.imageDrawer.componentRef.instance.cdr.markForCheck();
727
- };
728
-
729
718
  const DefaultAbstractNodeStyle = {
730
719
  branch: { color: GRAY_COLOR, width: 2 },
731
720
  shape: {
@@ -744,8 +733,92 @@ const DefaultNodeStyle = {
744
733
  }
745
734
  };
746
735
 
747
- const getAvailableProperty = (board, element, propertyKey) => {
748
- 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
+ }
749
822
  };
750
823
 
751
824
  const separateChildren = (parentElement) => {
@@ -915,78 +988,326 @@ const isChildOfAbstract = (board, element) => {
915
988
  return !!ancestors.find((value) => AbstractNode.isAbstract(value));
916
989
  };
917
990
 
918
- /**
919
- * Processing of branch color, width, style, etc. of the mind node
920
- */
921
- const getBranchColorByMindElement = (board, element) => {
922
- if (AbstractNode.isAbstract(element) || isChildOfAbstract(board, element)) {
923
- return getAbstractBranchColor(board, element);
924
- }
925
- const branchColor = getAvailableProperty(board, element, 'branchColor');
926
- return branchColor || getDefaultBranchColor(board, element);
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 };
927
996
  };
928
- const getBranchShapeByMindElement = (board, element) => {
929
- const branchShape = getAvailableProperty(board, element, 'branchShape');
930
- return branchShape || BranchShape.bight;
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);
931
1004
  };
932
- const getBranchWidthByMindElement = (board, element) => {
933
- const branchWidth = getAvailableProperty(board, element, 'branchWidth');
934
- return branchWidth || BRANCH_WIDTH;
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);
935
1010
  };
936
- const getAbstractBranchWidth = (board, element) => {
937
- if (!isNullOrUndefined(element.branchWidth)) {
938
- return element.branchWidth;
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;
939
1019
  }
940
- return DefaultAbstractNodeStyle.branch.width;
941
- };
942
- const getAbstractBranchColor = (board, element) => {
943
- if (element.branchColor) {
944
- return element.branchColor;
1020
+ if (!isEqualWidth || !isEqualHeight) {
1021
+ const path = PlaitBoard.findPath(board, element);
1022
+ Transforms.setNode(board, newElement, path);
945
1023
  }
946
- return DefaultAbstractNodeStyle.branch.color;
947
1024
  };
948
- const getNextBranchColor = (board, root) => {
949
- const index = root.children.length;
950
- return getDefaultBranchColorByIndex(board, index);
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
+ });
951
1039
  };
952
- const getDefaultBranchColor = (board, element) => {
953
- const path = PlaitBoard.findPath(board, element);
954
- return getDefaultBranchColorByIndex(board, path[1]);
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();
955
1048
  };
956
- const getDefaultBranchColorByIndex = (board, index) => {
957
- const themeColor = getMindThemeColor(board);
958
- const length = themeColor.branchColors.length;
959
- const remainder = index % length;
960
- return themeColor.branchColors[remainder];
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);
961
1061
  };
962
- const getMindThemeColor = (board) => {
963
- const themeColors = PlaitBoard.getThemeColors(board);
964
- const themeColor = themeColors.find(val => val.mode === board.theme.themeColorMode);
965
- if (themeColor && MindThemeColor.isMindThemeColor(themeColor)) {
966
- return themeColor;
967
- }
968
- else {
969
- return MindDefaultThemeColor;
970
- }
1062
+ const setRightNodeCountByRefs = (board, refs) => {
1063
+ refs.forEach(ref => {
1064
+ Transforms.setNode(board, { rightNodeCount: ref.rightNodeCount }, ref.path);
1065
+ });
971
1066
  };
972
1067
 
973
- const getStrokeByMindElement = (board, element) => {
974
- if (PlaitMind.isMind(element)) {
975
- const defaultRootStroke = getMindThemeColor(board).rootFill;
976
- return element.strokeColor || defaultRootStroke;
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;
977
1085
  }
978
- if (AbstractNode.isAbstract(element) || isChildOfAbstract(board, element)) {
979
- return element.strokeColor || DefaultAbstractNodeStyle.shape.strokeColor;
1086
+ if (emojis.length > 0) {
1087
+ newElement.data.emojis = emojis;
980
1088
  }
981
- return getAvailableProperty(board, element, 'strokeColor') || getDefaultBranchColor(board, element);
982
- };
983
- const getStrokeWidthByElement = (board, element) => {
984
- const strokeWidth = element.strokeWidth ||
985
- (AbstractNode.isAbstract(element) ? DefaultAbstractNodeStyle.shape.strokeWidth : DefaultNodeStyle.shape.strokeWidth);
986
- return strokeWidth;
1089
+ const path = PlaitBoard.findPath(board, element);
1090
+ Transforms.setNode(board, newElement, path);
987
1091
  };
988
- const getFillByElement = (board, element) => {
989
- if (element.fill) {
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];
1237
+ };
1238
+
1239
+ /**
1240
+ * Processing of branch color, width, style, etc. of the mind node
1241
+ */
1242
+ const getBranchColorByMindElement = (board, element) => {
1243
+ if (AbstractNode.isAbstract(element) || isChildOfAbstract(board, element)) {
1244
+ return getAbstractBranchColor(board, element);
1245
+ }
1246
+ const branchColor = getAvailableProperty(board, element, 'branchColor');
1247
+ return branchColor || getDefaultBranchColor(board, element);
1248
+ };
1249
+ const getBranchShapeByMindElement = (board, element) => {
1250
+ const branchShape = getAvailableProperty(board, element, 'branchShape');
1251
+ return branchShape || BranchShape.bight;
1252
+ };
1253
+ const getBranchWidthByMindElement = (board, element) => {
1254
+ const branchWidth = getAvailableProperty(board, element, 'branchWidth');
1255
+ return branchWidth || BRANCH_WIDTH;
1256
+ };
1257
+ const getAbstractBranchWidth = (board, element) => {
1258
+ if (!isNullOrUndefined(element.branchWidth)) {
1259
+ return element.branchWidth;
1260
+ }
1261
+ return DefaultAbstractNodeStyle.branch.width;
1262
+ };
1263
+ const getAbstractBranchColor = (board, element) => {
1264
+ if (element.branchColor) {
1265
+ return element.branchColor;
1266
+ }
1267
+ return DefaultAbstractNodeStyle.branch.color;
1268
+ };
1269
+ const getNextBranchColor = (board, root) => {
1270
+ const index = root.children.length;
1271
+ return getDefaultBranchColorByIndex(board, index);
1272
+ };
1273
+ const getDefaultBranchColor = (board, element) => {
1274
+ const path = PlaitBoard.findPath(board, element);
1275
+ return getDefaultBranchColorByIndex(board, path[1]);
1276
+ };
1277
+ const getDefaultBranchColorByIndex = (board, index) => {
1278
+ const themeColor = getMindThemeColor(board);
1279
+ const length = themeColor.branchColors.length;
1280
+ const remainder = index % length;
1281
+ return themeColor.branchColors[remainder];
1282
+ };
1283
+ const getMindThemeColor = (board) => {
1284
+ const themeColors = PlaitBoard.getThemeColors(board);
1285
+ const themeColor = themeColors.find(val => val.mode === board.theme.themeColorMode);
1286
+ if (themeColor && MindThemeColor.isMindThemeColor(themeColor)) {
1287
+ return themeColor;
1288
+ }
1289
+ else {
1290
+ return MindDefaultThemeColor;
1291
+ }
1292
+ };
1293
+
1294
+ const getStrokeByMindElement = (board, element) => {
1295
+ if (PlaitMind.isMind(element)) {
1296
+ const defaultRootStroke = getMindThemeColor(board).rootFill;
1297
+ return element.strokeColor || defaultRootStroke;
1298
+ }
1299
+ if (AbstractNode.isAbstract(element) || isChildOfAbstract(board, element)) {
1300
+ return element.strokeColor || DefaultAbstractNodeStyle.shape.strokeColor;
1301
+ }
1302
+ return getAvailableProperty(board, element, 'strokeColor') || getDefaultBranchColor(board, element);
1303
+ };
1304
+ const getStrokeWidthByElement = (board, element) => {
1305
+ const strokeWidth = element.strokeWidth ||
1306
+ (AbstractNode.isAbstract(element) ? DefaultAbstractNodeStyle.shape.strokeWidth : DefaultNodeStyle.shape.strokeWidth);
1307
+ return strokeWidth;
1308
+ };
1309
+ const getFillByElement = (board, element) => {
1310
+ if (element.fill) {
990
1311
  return element.fill;
991
1312
  }
992
1313
  const defaultRootFill = getMindThemeColor(board).rootFill;
@@ -1865,6 +2186,73 @@ const deleteElementsHandleRightNodeCount = (board, deletableElements, effectedRi
1865
2186
  return effectedRightNodeCount;
1866
2187
  };
1867
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
+
1868
2256
  /**
1869
2257
  * get correctly layout:
1870
2258
  * 1. root is standard -> left or right
@@ -2161,313 +2549,84 @@ function drawAbstractLink(board, node, isHorizontal) {
2161
2549
  stroke: branchColor,
2162
2550
  strokeWidth: branchWidth
2163
2551
  });
2164
- g.appendChild(polyline);
2165
- g.appendChild(straightLine);
2166
- return g;
2167
- }
2168
- const link = PlaitBoard.getRoughSVG(board).path(`M${bezierBeginPoint[0]},${bezierBeginPoint[1]} Q${c1[0]},${c1[1]} ${bezierConnectorPoint[0]},${bezierConnectorPoint[1]} Q${c2[0]},${c2[1]} ${bezierEndPoint[0]},${bezierEndPoint[1]} M${abstractConnectorPoint[0]},${abstractConnectorPoint[1]} L${bezierConnectorPoint[0]},${bezierConnectorPoint[1]}`, {
2169
- stroke: branchColor,
2170
- strokeWidth: branchWidth
2171
- });
2172
- return link;
2173
- }
2174
-
2175
- class EmojiDrawer {
2176
- constructor(board, viewContainerRef) {
2177
- this.board = board;
2178
- this.viewContainerRef = viewContainerRef;
2179
- this.componentRef = null;
2180
- }
2181
- draw(emoji, element) {
2182
- this.destroy();
2183
- const componentType = this.board.drawEmoji(emoji, element);
2184
- this.componentRef = this.viewContainerRef.createComponent(componentType);
2185
- this.componentRef.instance.emojiItem = emoji;
2186
- this.componentRef.instance.board = this.board;
2187
- this.componentRef.instance.element = element;
2188
- this.componentRef.instance.fontSize = getEmojiFontSize(element);
2189
- }
2190
- get nativeElement() {
2191
- if (this.componentRef) {
2192
- return this.componentRef.instance.nativeElement;
2193
- }
2194
- else {
2195
- return null;
2196
- }
2197
- }
2198
- destroy() {
2199
- if (this.componentRef) {
2200
- this.componentRef.destroy();
2201
- this.componentRef = null;
2202
- }
2203
- }
2204
- }
2205
- class NodeEmojisDrawer {
2206
- constructor(board, viewContainerRef) {
2207
- this.board = board;
2208
- this.viewContainerRef = viewContainerRef;
2209
- this.emojiDrawers = [];
2210
- }
2211
- drawEmojis(element) {
2212
- this.destroy();
2213
- if (MindElement.hasEmojis(element)) {
2214
- this.g = createG();
2215
- this.g.classList.add('emojis');
2216
- const foreignRectangle = getEmojiForeignRectangle(this.board, element);
2217
- const foreignObject = createForeignObject(foreignRectangle.x, foreignRectangle.y, foreignRectangle.width, foreignRectangle.height);
2218
- this.g.append(foreignObject);
2219
- const container = document.createElement('div');
2220
- container.classList.add('node-emojis-container');
2221
- foreignObject.append(container);
2222
- this.emojiDrawers = element.data.emojis.map(emojiItem => {
2223
- const drawer = new EmojiDrawer(this.board, this.viewContainerRef);
2224
- drawer.draw(emojiItem, element);
2225
- return drawer;
2226
- });
2227
- this.emojiDrawers.forEach(drawer => {
2228
- container.append(drawer.nativeElement);
2229
- });
2230
- return this.g;
2231
- }
2232
- return undefined;
2233
- }
2234
- destroy() {
2235
- if (this.g) {
2236
- this.g.remove();
2237
- }
2238
- this.emojiDrawers.forEach(drawer => drawer.destroy());
2239
- this.emojiDrawers = [];
2240
- }
2241
- }
2242
-
2243
- const setAbstractsByRefs = (board, abstractRefs) => {
2244
- abstractRefs.forEach((newProperty, element) => {
2245
- const start = element.start + newProperty.start;
2246
- const end = element.end + newProperty.end;
2247
- const path = PlaitBoard.findPath(board, element);
2248
- if (start > end) {
2249
- Transforms.removeNode(board, path);
2250
- }
2251
- else {
2252
- Transforms.setNode(board, { start, end }, path);
2253
- }
2254
- });
2255
- };
2256
- const setAbstractByStandardLayout = (board, element) => {
2257
- const rightNodeCount = element.rightNodeCount;
2258
- const abstract = element.children.find(child => {
2259
- return AbstractNode.isAbstract(child) && child.end >= rightNodeCount && child.start < rightNodeCount;
2260
- });
2261
- if (abstract) {
2262
- const path = PlaitBoard.findPath(board, abstract);
2263
- Transforms.setNode(board, { end: rightNodeCount - 1 }, path);
2264
- }
2265
- };
2266
- const insertAbstract = (board, elements) => {
2267
- let elementGroup = getFirstLevelElement(elements);
2268
- const { parentElements, abstractIncludedGroups } = divideElementByParent(elementGroup);
2269
- abstractIncludedGroups.forEach((group, index) => {
2270
- const groupParent = parentElements[index];
2271
- setAbstractByElements(board, groupParent, group);
2272
- });
2273
- };
2274
- const setAbstractByElements = (board, groupParent, group) => {
2275
- const indexArray = group.map(child => groupParent.children.indexOf(child)).sort((a, b) => a - b);
2276
- const rightNodeCount = groupParent?.rightNodeCount;
2277
- const start = indexArray[0], end = indexArray[indexArray.length - 1];
2278
- if (isStandardLayout(MindQueries.getLayoutByElement(groupParent)) &&
2279
- rightNodeCount &&
2280
- start < rightNodeCount &&
2281
- end >= rightNodeCount) {
2282
- const childrenLength = groupParent.children.length;
2283
- const path = [...PlaitBoard.findPath(board, groupParent), childrenLength];
2284
- const leftChildren = indexArray.filter(index => index >= rightNodeCount);
2285
- const rightChildren = indexArray.filter(index => index < rightNodeCount);
2286
- insertAbstractNode(board, path, rightChildren[0], rightChildren[rightChildren.length - 1]);
2287
- insertAbstractNode(board, Path.next(path), leftChildren[0], leftChildren[leftChildren.length - 1]);
2288
- }
2289
- else {
2290
- const path = [...PlaitBoard.findPath(board, groupParent), groupParent.children.length];
2291
- insertAbstractNode(board, path, start, end);
2292
- }
2293
- };
2294
- const insertAbstractNode = (board, path, start, end) => {
2295
- const mindElement = createMindElement('概要', 28, 20, {
2296
- strokeWidth: DefaultAbstractNodeStyle.branch.width,
2297
- branchWidth: DefaultAbstractNodeStyle.branch.width
2298
- });
2299
- mindElement.start = start;
2300
- mindElement.end = end;
2301
- Transforms.insertNode(board, mindElement, path);
2302
- clearSelectedElement(board);
2303
- addSelectedElement(board, mindElement);
2304
- };
2305
-
2306
- const setLayout = (board, layout, path) => {
2307
- correctLogicLayoutNode(board, layout, path);
2308
- const element = PlaitNode.get(board, path);
2309
- if (PlaitMind.isMind(element) && isStandardLayout(layout)) {
2310
- MindTransforms.setAbstractByStandardLayout(board, element);
2311
- }
2312
- Transforms.setNode(board, { layout }, path);
2313
- };
2314
- const correctLogicLayoutNode = (board, layout, path) => {
2315
- const node = PlaitNode.get(board, path);
2316
- if (node && layout) {
2317
- node.children?.forEach((value, index) => {
2318
- if (value.layout) {
2319
- if ((isHorizontalLogicLayout(layout) && isVerticalLogicLayout(value.layout)) ||
2320
- (isVerticalLogicLayout(layout) && isHorizontalLogicLayout(value.layout))) {
2321
- Transforms.setNode(board, { layout: null }, [...path, index]);
2322
- }
2323
- if (value.children?.length) {
2324
- correctLogicLayoutNode(board, layout, [...path, index]);
2325
- }
2326
- }
2327
- });
2328
- }
2329
- };
2330
-
2331
- const normalizeWidthAndHeight = (board, element, width, height) => {
2332
- const minWidth = NodeSpace.getNodeTopicMinWidth(board, element, element.isRoot);
2333
- const newWidth = width < minWidth * board.viewport.zoom ? minWidth : width / board.viewport.zoom;
2334
- const newHeight = height / board.viewport.zoom;
2335
- return { width: newWidth, height: newHeight };
2336
- };
2337
- const setTopic = (board, element, topic, width, height) => {
2338
- const newElement = {
2339
- data: { ...element.data, topic },
2340
- ...normalizeWidthAndHeight(board, element, width, height)
2341
- };
2342
- const path = PlaitBoard.findPath(board, element);
2343
- Transforms.setNode(board, newElement, path);
2344
- };
2345
- const setNodeManualWidth = (board, element, width, height) => {
2346
- const path = PlaitBoard.findPath(board, element);
2347
- const { width: normalizedWidth, height: normalizedHeight } = normalizeWidthAndHeight(board, element, width, height);
2348
- const newElement = { manualWidth: normalizedWidth, height: normalizedHeight };
2349
- Transforms.setNode(board, newElement, path);
2350
- };
2351
- const setTopicSize = (board, element, width, height) => {
2352
- const newElement = {
2353
- ...normalizeWidthAndHeight(board, element, width, height)
2354
- };
2355
- let isEqualWidth = Math.ceil(element.width) === Math.ceil(newElement.width);
2356
- let isEqualHeight = Math.ceil(element.height) === Math.ceil(newElement.height);
2357
- if (element.manualWidth) {
2358
- isEqualWidth = true;
2359
- }
2360
- if (!isEqualWidth || !isEqualHeight) {
2361
- const path = PlaitBoard.findPath(board, element);
2362
- Transforms.setNode(board, newElement, path);
2363
- }
2364
- };
2365
- const removeElements = (board, elements) => {
2366
- const deletableElements = getFirstLevelElement(elements);
2367
- deletableElements
2368
- .map(element => {
2369
- const path = PlaitBoard.findPath(board, element);
2370
- const ref = board.pathRef(path);
2371
- return () => {
2372
- Transforms.removeNode(board, ref.current);
2373
- ref.unref();
2374
- };
2375
- })
2376
- .forEach(action => {
2377
- action();
2378
- });
2379
- };
2380
- const insertNodes = (board, elements, path) => {
2381
- const pathRef = board.pathRef(path);
2382
- elements.forEach(element => {
2383
- if (pathRef.current) {
2384
- Transforms.insertNode(board, element, pathRef.current);
2385
- }
2386
- });
2387
- pathRef.unref();
2388
- };
2389
- const insertAbstractNodes = (board, validAbstractRefs, elements, path) => {
2390
- const parent = PlaitNode.get(board, Path$1.parent(path));
2391
- const abstractPath = [...Path$1.parent(path), parent.children?.length];
2392
- const abstracts = validAbstractRefs.map(refs => {
2393
- const { start, end } = getRelativeStartEndByAbstractRef(refs, elements);
2394
- return {
2395
- ...refs.abstract,
2396
- start: start + path[path.length - 1],
2397
- end: end + path[path.length - 1]
2398
- };
2399
- });
2400
- insertNodes(board, abstracts, abstractPath);
2401
- };
2402
- const setRightNodeCountByRefs = (board, refs) => {
2403
- refs.forEach(ref => {
2404
- Transforms.setNode(board, { rightNodeCount: ref.rightNodeCount }, ref.path);
2405
- });
2406
- };
2407
-
2408
- const addEmoji = (board, element, emojiItem) => {
2409
- const emojis = element.data.emojis || [];
2410
- const newEmojis = [...emojis];
2411
- newEmojis.push(emojiItem);
2412
- const newElement = {
2413
- data: { ...element.data, emojis: newEmojis }
2414
- };
2415
- const path = PlaitBoard.findPath(board, element);
2416
- Transforms.setNode(board, newElement, path);
2417
- };
2418
- const removeEmoji = (board, element, emojiItem) => {
2419
- const emojis = element.data.emojis.filter(value => value !== emojiItem);
2420
- const newElement = {
2421
- data: { ...element.data }
2422
- };
2423
- if (emojis.length > 0) {
2424
- newElement.data.emojis = emojis;
2552
+ g.appendChild(polyline);
2553
+ g.appendChild(straightLine);
2554
+ return g;
2425
2555
  }
2426
- const path = PlaitBoard.findPath(board, element);
2427
- Transforms.setNode(board, newElement, path);
2428
- };
2429
- const replaceEmoji = (board, element, oldEmoji, newEmoji) => {
2430
- const newElement = {
2431
- data: { ...element.data }
2432
- };
2433
- const newEmojis = element.data.emojis.map(value => {
2434
- if (value === oldEmoji) {
2435
- return newEmoji;
2436
- }
2437
- return value;
2556
+ const link = PlaitBoard.getRoughSVG(board).path(`M${bezierBeginPoint[0]},${bezierBeginPoint[1]} Q${c1[0]},${c1[1]} ${bezierConnectorPoint[0]},${bezierConnectorPoint[1]} Q${c2[0]},${c2[1]} ${bezierEndPoint[0]},${bezierEndPoint[1]} M${abstractConnectorPoint[0]},${abstractConnectorPoint[1]} L${bezierConnectorPoint[0]},${bezierConnectorPoint[1]}`, {
2557
+ stroke: branchColor,
2558
+ strokeWidth: branchWidth
2438
2559
  });
2439
- newElement.data.emojis = newEmojis;
2440
- const path = PlaitBoard.findPath(board, element);
2441
- Transforms.setNode(board, newElement, path);
2442
- };
2443
-
2444
- const removeImage = (board, element) => {
2445
- setImageFocus(board, element, false);
2446
- const newElement = {
2447
- data: { ...element.data }
2448
- };
2449
- delete newElement.data.image;
2450
- const path = PlaitBoard.findPath(board, element);
2451
- Transforms.setNode(board, newElement, path);
2452
- };
2560
+ return link;
2561
+ }
2453
2562
 
2454
- const MindTransforms = {
2455
- setLayout,
2456
- setTopic,
2457
- setTopicSize,
2458
- setNodeManualWidth,
2459
- addEmoji,
2460
- removeEmoji,
2461
- replaceEmoji,
2462
- insertAbstract,
2463
- setAbstractsByRefs,
2464
- setAbstractByStandardLayout,
2465
- removeElements,
2466
- insertNodes,
2467
- insertAbstractNodes,
2468
- setRightNodeCountByRefs,
2469
- removeImage
2470
- };
2563
+ class EmojiDrawer {
2564
+ constructor(board, viewContainerRef) {
2565
+ this.board = board;
2566
+ this.viewContainerRef = viewContainerRef;
2567
+ this.componentRef = null;
2568
+ }
2569
+ draw(emoji, element) {
2570
+ this.destroy();
2571
+ const componentType = this.board.drawEmoji(emoji, element);
2572
+ this.componentRef = this.viewContainerRef.createComponent(componentType);
2573
+ this.componentRef.instance.emojiItem = emoji;
2574
+ this.componentRef.instance.board = this.board;
2575
+ this.componentRef.instance.element = element;
2576
+ this.componentRef.instance.fontSize = getEmojiFontSize(element);
2577
+ }
2578
+ get nativeElement() {
2579
+ if (this.componentRef) {
2580
+ return this.componentRef.instance.nativeElement;
2581
+ }
2582
+ else {
2583
+ return null;
2584
+ }
2585
+ }
2586
+ destroy() {
2587
+ if (this.componentRef) {
2588
+ this.componentRef.destroy();
2589
+ this.componentRef = null;
2590
+ }
2591
+ }
2592
+ }
2593
+ class NodeEmojisDrawer {
2594
+ constructor(board, viewContainerRef) {
2595
+ this.board = board;
2596
+ this.viewContainerRef = viewContainerRef;
2597
+ this.emojiDrawers = [];
2598
+ }
2599
+ drawEmojis(element) {
2600
+ this.destroy();
2601
+ if (MindElement.hasEmojis(element)) {
2602
+ this.g = createG();
2603
+ this.g.classList.add('emojis');
2604
+ const foreignRectangle = getEmojiForeignRectangle(this.board, element);
2605
+ const foreignObject = createForeignObject(foreignRectangle.x, foreignRectangle.y, foreignRectangle.width, foreignRectangle.height);
2606
+ this.g.append(foreignObject);
2607
+ const container = document.createElement('div');
2608
+ container.classList.add('node-emojis-container');
2609
+ foreignObject.append(container);
2610
+ this.emojiDrawers = element.data.emojis.map(emojiItem => {
2611
+ const drawer = new EmojiDrawer(this.board, this.viewContainerRef);
2612
+ drawer.draw(emojiItem, element);
2613
+ return drawer;
2614
+ });
2615
+ this.emojiDrawers.forEach(drawer => {
2616
+ container.append(drawer.nativeElement);
2617
+ });
2618
+ return this.g;
2619
+ }
2620
+ return undefined;
2621
+ }
2622
+ destroy() {
2623
+ if (this.g) {
2624
+ this.g.remove();
2625
+ }
2626
+ this.emojiDrawers.forEach(drawer => drawer.destroy());
2627
+ this.emojiDrawers = [];
2628
+ }
2629
+ }
2471
2630
 
2472
2631
  class BaseDrawer {
2473
2632
  constructor(board) {
@@ -2826,36 +2985,6 @@ class CollapseDrawer extends BaseDrawer {
2826
2985
  }
2827
2986
  }
2828
2987
 
2829
- class MindImageBaseComponent {
2830
- get nativeElement() {
2831
- return this.elementRef.nativeElement;
2832
- }
2833
- constructor(elementRef, cdr) {
2834
- this.elementRef = elementRef;
2835
- this.cdr = cdr;
2836
- this.isFocus = false;
2837
- }
2838
- ngOnInit() { }
2839
- }
2840
- 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 });
2841
- 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 });
2842
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImport: i0, type: MindImageBaseComponent, decorators: [{
2843
- type: Directive,
2844
- args: [{
2845
- host: {
2846
- class: 'mind-node-image'
2847
- }
2848
- }]
2849
- }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { imageItem: [{
2850
- type: Input
2851
- }], board: [{
2852
- type: Input
2853
- }], element: [{
2854
- type: Input
2855
- }], isFocus: [{
2856
- type: Input
2857
- }] } });
2858
-
2859
2988
  class NodeImageDrawer {
2860
2989
  constructor(board, viewContainerRef) {
2861
2990
  this.board = board;
@@ -2869,9 +2998,9 @@ class NodeImageDrawer {
2869
2998
  }
2870
2999
  this.g = createG();
2871
3000
  const foreignRectangle = getImageForeignRectangle(this.board, element);
2872
- const foreignObject = createForeignObject(foreignRectangle.x, foreignRectangle.y, foreignRectangle.width, foreignRectangle.height);
2873
- this.g.append(foreignObject);
2874
- 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;
2875
3004
  if (!componentType) {
2876
3005
  throw new Error('Not implement drawEmoji method error.');
2877
3006
  }
@@ -2880,7 +3009,7 @@ class NodeImageDrawer {
2880
3009
  this.componentRef.instance.element = element;
2881
3010
  this.componentRef.instance.imageItem = element.data.image;
2882
3011
  this.componentRef.instance.cdr.markForCheck();
2883
- foreignObject.append(this.componentRef.instance.nativeElement);
3012
+ this.foreignObject.append(this.componentRef.instance.nativeElement);
2884
3013
  nodeG.appendChild(this.g);
2885
3014
  }
2886
3015
  updateImage(nodeG, previous, current) {
@@ -2894,6 +3023,10 @@ class NodeImageDrawer {
2894
3023
  }
2895
3024
  const currentForeignObject = getImageForeignRectangle(this.board, current);
2896
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
+ }
2897
3030
  this.componentRef?.instance.cdr.markForCheck();
2898
3031
  }
2899
3032
  destroy() {
@@ -3057,13 +3190,17 @@ class MindNodeComponent extends PlaitPluginElementComponent {
3057
3190
  this.textManage.draw(this.element.data.topic);
3058
3191
  this.g.append(this.textManage.g);
3059
3192
  if (this.element.manualWidth) {
3060
- const width = NodeSpace.getNodeResizableWidth(this.board, this.element);
3193
+ const width = NodeSpace.getNodeDynamicWidth(this.board, this.element);
3061
3194
  this.textManage.updateWidth(width);
3062
3195
  }
3063
3196
  }
3064
3197
  updateTopic() {
3065
3198
  this.textManage.updateText(this.element.data.topic);
3066
3199
  this.textManage.updateRectangle();
3200
+ if (this.element.manualWidth) {
3201
+ const width = NodeSpace.getNodeDynamicWidth(this.board, this.element);
3202
+ this.textManage.updateWidth(width);
3203
+ }
3067
3204
  }
3068
3205
  editTopic() {
3069
3206
  this.activeDrawer.draw(this.element, this.g, { selected: this.selected, isEditing: true });
@@ -3112,73 +3249,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImpor
3112
3249
  }]
3113
3250
  }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }, { type: i0.ChangeDetectorRef }]; } });
3114
3251
 
3115
- const getLayoutOptions = (board) => {
3116
- function getMainAxle(element, parent) {
3117
- const strokeWidth = element.strokeWidth || STROKE_WIDTH;
3118
- if (element.isRoot) {
3119
- return BASE * 12;
3120
- }
3121
- if (parent && parent.isRoot()) {
3122
- return BASE * 3 + strokeWidth / 2;
3123
- }
3124
- return BASE * 3 + strokeWidth / 2;
3125
- }
3126
- function getSecondAxle(element, parent) {
3127
- const strokeWidth = element.strokeWidth || STROKE_WIDTH;
3128
- if (element.isRoot) {
3129
- return BASE * 10 + strokeWidth / 2;
3130
- }
3131
- return BASE * 6 + strokeWidth / 2;
3132
- }
3133
- return {
3134
- getHeight(element) {
3135
- return NodeSpace.getNodeHeight(board, element);
3136
- },
3137
- getWidth(element) {
3138
- return NodeSpace.getNodeWidth(board, element);
3139
- },
3140
- getHorizontalGap(element, parent) {
3141
- const _layout = (parent && parent.layout) || getRootLayout(element);
3142
- const isHorizontal = isHorizontalLayout(_layout);
3143
- const strokeWidth = element.strokeWidth || STROKE_WIDTH;
3144
- if (isIndentedLayout(_layout)) {
3145
- return BASE * 4 + strokeWidth;
3146
- }
3147
- if (!isHorizontal) {
3148
- return getMainAxle(element, parent);
3149
- }
3150
- else {
3151
- return getSecondAxle(element, parent);
3152
- }
3153
- },
3154
- getVerticalGap(element, parent) {
3155
- const _layout = (parent && parent.layout) || getRootLayout(element);
3156
- if (isIndentedLayout(_layout)) {
3157
- return BASE;
3158
- }
3159
- const isHorizontal = isHorizontalLayout(_layout);
3160
- if (isHorizontal) {
3161
- return getMainAxle(element, parent);
3162
- }
3163
- else {
3164
- return getSecondAxle(element, parent);
3165
- }
3166
- },
3167
- getVerticalConnectingPosition(element, parent) {
3168
- if (element.shape === MindElementShape.underline && parent && isHorizontalLogicLayout(parent.layout)) {
3169
- return ConnectingPosition.bottom;
3170
- }
3171
- return undefined;
3172
- },
3173
- getExtendHeight(node) {
3174
- return BASE * 6;
3175
- },
3176
- getIndentedCrossLevelGap() {
3177
- return BASE * 2;
3178
- }
3179
- };
3180
- };
3181
-
3182
3252
  class PlaitMindComponent extends MindNodeComponent {
3183
3253
  ngOnInit() {
3184
3254
  this.updateMindLayout();
@@ -3914,7 +3984,7 @@ const withNodeHoverDetect = (board) => {
3914
3984
  };
3915
3985
 
3916
3986
  const withNodeImage = (board) => {
3917
- const { keydown, mousedown, globalMouseup } = board;
3987
+ const { keydown, mousedown, globalMouseup, insertFragment } = board;
3918
3988
  board.mousedown = (event) => {
3919
3989
  const selectedImageElement = getSelectedImageElement(board);
3920
3990
  if (PlaitBoard.isReadonly(board) || !isMainPointer(event) || !PlaitBoard.isPointer(board, PlaitPointerType.selection)) {
@@ -3940,7 +4010,6 @@ const withNodeImage = (board) => {
3940
4010
  if (hitImage) {
3941
4011
  temporaryDisableSelection(board);
3942
4012
  setImageFocus(board, hitElements[0], true);
3943
- clearSelectedElement(board);
3944
4013
  }
3945
4014
  mousedown(event);
3946
4015
  };
@@ -3964,6 +4033,21 @@ const withNodeImage = (board) => {
3964
4033
  }
3965
4034
  globalMouseup(event);
3966
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
+ };
3967
4051
  return board;
3968
4052
  };
3969
4053
 
@@ -3993,7 +4077,7 @@ const withNodeResize = (board) => {
3993
4077
  addResizing(board, targetElement);
3994
4078
  targetElementRef = {
3995
4079
  minWidth: NodeSpace.getNodeResizableMinWidth(board, targetElement),
3996
- currentWidth: NodeSpace.getNodeResizableWidth(board, targetElement),
4080
+ currentWidth: NodeSpace.getNodeDynamicWidth(board, targetElement),
3997
4081
  path: PlaitBoard.findPath(board, targetElement),
3998
4082
  textManage: PlaitElement.getComponent(targetElement).textManage
3999
4083
  };
@@ -4009,7 +4093,7 @@ const withNodeResize = (board) => {
4009
4093
  const offsetX = endPoint[0] - startPoint[0];
4010
4094
  const zoom = board.viewport.zoom;
4011
4095
  let resizedWidth = targetElementRef.currentWidth + offsetX / zoom;
4012
- if (resizedWidth < targetElementRef.minWidth) {
4096
+ if (resizedWidth <= targetElementRef.minWidth) {
4013
4097
  resizedWidth = targetElementRef.minWidth;
4014
4098
  }
4015
4099
  const newTarget = PlaitNode.get(board, targetElementRef.path);
@@ -4236,6 +4320,42 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImpor
4236
4320
  args: ['mousedown']
4237
4321
  }] } });
4238
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
+
4239
4359
  /*
4240
4360
  * Public API Surface of mind
4241
4361
  */
@@ -4244,5 +4364,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImpor
4244
4364
  * Generated bundle index. Do not edit.
4245
4365
  */
4246
4366
 
4247
- 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 };
4248
4368
  //# sourceMappingURL=plait-mind.mjs.map