@plait/mind 0.23.1 → 0.24.1

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,329 @@ 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
+ if (Math.abs(newHeight / board.viewport.zoom - element.height) > 2) {
1123
+ return newHeight;
1124
+ }
1125
+ return undefined;
1126
+ };
1127
+
1128
+ const removeImage = (board, element) => {
1129
+ setImageFocus(board, element, false);
1130
+ const newElement = {
1131
+ data: { ...element.data }
1132
+ };
1133
+ delete newElement.data.image;
1134
+ const path = PlaitBoard.findPath(board, element);
1135
+ const newDynamicWidth = NodeSpace.getNodeNewDynamicWidth(board, element, 0);
1136
+ const newHeight = getNewNodeHeight(board, element, newDynamicWidth);
1137
+ if (newHeight) {
1138
+ newElement.height = newHeight / board.viewport.zoom;
1139
+ }
1140
+ Transforms.setNode(board, newElement, path);
1141
+ };
1142
+ const setImage = (board, element, imageItem) => {
1143
+ const newElement = {
1144
+ data: { ...element.data, image: imageItem }
1145
+ };
1146
+ const newDynamicWidth = NodeSpace.getNodeNewDynamicWidth(board, element, imageItem.width);
1147
+ const newHeight = getNewNodeHeight(board, element, newDynamicWidth);
1148
+ if (newHeight) {
1149
+ newElement.height = newHeight / board.viewport.zoom;
1150
+ }
1151
+ const path = PlaitBoard.findPath(board, element);
1152
+ Transforms.setNode(board, newElement, path);
1153
+ };
1154
+
1155
+ const MindTransforms = {
1156
+ setLayout,
1157
+ setTopic,
1158
+ setTopicSize,
1159
+ setNodeManualWidth,
1160
+ addEmoji,
1161
+ removeEmoji,
1162
+ replaceEmoji,
1163
+ insertAbstract,
1164
+ setAbstractsByRefs,
1165
+ setAbstractByStandardLayout,
1166
+ removeElements,
1167
+ insertNodes,
1168
+ insertAbstractNodes,
1169
+ setRightNodeCountByRefs,
1170
+ removeImage,
1171
+ setImage
1172
+ };
1173
+
1174
+ const PICTURE_ACCEPTED_UPLOAD_SIZE = 20;
1175
+ const acceptImageTypes = ['png', 'jpeg', 'gif', 'bmp'];
1176
+ const DEFAULT_IMAGE_WIDTH = 240;
1177
+
1178
+ const BOARD_TO_SELECTED_IMAGE_ELEMENT = new WeakMap();
1179
+ const getSelectedImageElement = (board) => {
1180
+ return BOARD_TO_SELECTED_IMAGE_ELEMENT.get(board);
1181
+ };
1182
+ const addSelectedImageElement = (board, element) => {
1183
+ BOARD_TO_SELECTED_IMAGE_ELEMENT.set(board, element);
1184
+ };
1185
+ const removeSelectedImageElement = (board) => {
1186
+ BOARD_TO_SELECTED_IMAGE_ELEMENT.delete(board);
1187
+ };
1188
+ const setImageFocus = (board, element, isFocus) => {
1189
+ if (isFocus) {
1190
+ addSelectedImageElement(board, element);
1191
+ }
1192
+ else {
1193
+ removeSelectedImageElement(board);
1194
+ }
1195
+ const elementComponent = PlaitElement.getComponent(element);
1196
+ elementComponent.imageDrawer.componentRef.instance.isFocus = isFocus;
1197
+ elementComponent.imageDrawer.componentRef.instance.cdr.markForCheck();
1198
+ };
1199
+ const selectImage = (board, element, acceptImageTypes = ['png', 'jpeg', 'gif', 'bmp']) => {
1200
+ const inputFile = document.createElement('input');
1201
+ inputFile.setAttribute('type', 'file');
1202
+ const acceptImageTypesString = '.' + acceptImageTypes.join(',.');
1203
+ inputFile.setAttribute('accept', acceptImageTypesString);
1204
+ inputFile.onchange = (event) => {
1205
+ buildImage(board, element, event.target.files[0]);
1206
+ };
1207
+ inputFile.click();
1208
+ };
1209
+ const buildImage = async (board, element, imageFile) => {
1210
+ let width = 0, height = 0;
1211
+ await getImageSize(imageFile).then((value) => {
1212
+ width = value.width;
1213
+ height = value.height;
1214
+ });
1215
+ let imageItem = null;
1216
+ const url = URL.createObjectURL(imageFile);
1217
+ const context = PlaitBoard.getComponent(board).viewContainerRef.injector.get(PlaitContextService);
1218
+ context.setUploadingFile({ url, file: imageFile });
1219
+ imageItem = {
1220
+ url,
1221
+ width,
1222
+ height
1223
+ };
1224
+ MindTransforms.setImage(board, element, imageItem);
1225
+ };
1226
+ function getImageSize(file, defaultImageWidth = DEFAULT_IMAGE_WIDTH) {
1227
+ return new Promise((resolve, reject) => {
1228
+ const image = new Image();
1229
+ image.src = URL.createObjectURL(file);
1230
+ image.onload = function () {
1231
+ const width = defaultImageWidth;
1232
+ const height = (defaultImageWidth * image.naturalHeight) / image.naturalWidth;
1233
+ resolve(image.naturalWidth > defaultImageWidth ? { width, height } : { width: image.naturalWidth, height: image.naturalHeight });
1234
+ };
1235
+ });
1236
+ }
1237
+
1238
+ const getAvailableProperty = (board, element, propertyKey) => {
1239
+ return element[propertyKey];
1240
+ };
1241
+
1242
+ /**
1243
+ * Processing of branch color, width, style, etc. of the mind node
1244
+ */
1245
+ const getBranchColorByMindElement = (board, element) => {
1246
+ if (AbstractNode.isAbstract(element) || isChildOfAbstract(board, element)) {
1247
+ return getAbstractBranchColor(board, element);
1248
+ }
1249
+ const branchColor = getAvailableProperty(board, element, 'branchColor');
1250
+ return branchColor || getDefaultBranchColor(board, element);
1251
+ };
1252
+ const getBranchShapeByMindElement = (board, element) => {
1253
+ const branchShape = getAvailableProperty(board, element, 'branchShape');
1254
+ return branchShape || BranchShape.bight;
1255
+ };
1256
+ const getBranchWidthByMindElement = (board, element) => {
1257
+ const branchWidth = getAvailableProperty(board, element, 'branchWidth');
1258
+ return branchWidth || BRANCH_WIDTH;
1259
+ };
1260
+ const getAbstractBranchWidth = (board, element) => {
1261
+ if (!isNullOrUndefined(element.branchWidth)) {
1262
+ return element.branchWidth;
1263
+ }
1264
+ return DefaultAbstractNodeStyle.branch.width;
1265
+ };
1266
+ const getAbstractBranchColor = (board, element) => {
1267
+ if (element.branchColor) {
1268
+ return element.branchColor;
1269
+ }
1270
+ return DefaultAbstractNodeStyle.branch.color;
1271
+ };
1272
+ const getNextBranchColor = (board, root) => {
1273
+ const index = root.children.length;
1274
+ return getDefaultBranchColorByIndex(board, index);
1275
+ };
1276
+ const getDefaultBranchColor = (board, element) => {
1277
+ const path = PlaitBoard.findPath(board, element);
1278
+ return getDefaultBranchColorByIndex(board, path[1]);
1279
+ };
1280
+ const getDefaultBranchColorByIndex = (board, index) => {
1281
+ const themeColor = getMindThemeColor(board);
1282
+ const length = themeColor.branchColors.length;
1283
+ const remainder = index % length;
1284
+ return themeColor.branchColors[remainder];
1285
+ };
1286
+ const getMindThemeColor = (board) => {
1287
+ const themeColors = PlaitBoard.getThemeColors(board);
1288
+ const themeColor = themeColors.find(val => val.mode === board.theme.themeColorMode);
1289
+ if (themeColor && MindThemeColor.isMindThemeColor(themeColor)) {
1290
+ return themeColor;
1291
+ }
1292
+ else {
1293
+ return MindDefaultThemeColor;
1294
+ }
1295
+ };
1296
+
1297
+ const getStrokeByMindElement = (board, element) => {
1298
+ if (PlaitMind.isMind(element)) {
1299
+ const defaultRootStroke = getMindThemeColor(board).rootFill;
1300
+ return element.strokeColor || defaultRootStroke;
1301
+ }
1302
+ if (AbstractNode.isAbstract(element) || isChildOfAbstract(board, element)) {
1303
+ return element.strokeColor || DefaultAbstractNodeStyle.shape.strokeColor;
1304
+ }
1305
+ return getAvailableProperty(board, element, 'strokeColor') || getDefaultBranchColor(board, element);
1306
+ };
1307
+ const getStrokeWidthByElement = (board, element) => {
1308
+ const strokeWidth = element.strokeWidth ||
1309
+ (AbstractNode.isAbstract(element) ? DefaultAbstractNodeStyle.shape.strokeWidth : DefaultNodeStyle.shape.strokeWidth);
1310
+ return strokeWidth;
1311
+ };
1312
+ const getFillByElement = (board, element) => {
1313
+ if (element.fill) {
990
1314
  return element.fill;
991
1315
  }
992
1316
  const defaultRootFill = getMindThemeColor(board).rootFill;
@@ -1865,6 +2189,73 @@ const deleteElementsHandleRightNodeCount = (board, deletableElements, effectedRi
1865
2189
  return effectedRightNodeCount;
1866
2190
  };
1867
2191
 
2192
+ const getLayoutOptions = (board) => {
2193
+ function getMainAxle(element, parent) {
2194
+ const strokeWidth = element.strokeWidth || STROKE_WIDTH;
2195
+ if (element.isRoot) {
2196
+ return BASE * 12;
2197
+ }
2198
+ if (parent && parent.isRoot()) {
2199
+ return BASE * 3 + strokeWidth / 2;
2200
+ }
2201
+ return BASE * 3 + strokeWidth / 2;
2202
+ }
2203
+ function getSecondAxle(element, parent) {
2204
+ const strokeWidth = element.strokeWidth || STROKE_WIDTH;
2205
+ if (element.isRoot) {
2206
+ return BASE * 10 + strokeWidth / 2;
2207
+ }
2208
+ return BASE * 6 + strokeWidth / 2;
2209
+ }
2210
+ return {
2211
+ getHeight(element) {
2212
+ return NodeSpace.getNodeHeight(board, element);
2213
+ },
2214
+ getWidth(element) {
2215
+ return NodeSpace.getNodeWidth(board, element);
2216
+ },
2217
+ getHorizontalGap(element, parent) {
2218
+ const _layout = (parent && parent.layout) || getRootLayout(element);
2219
+ const isHorizontal = isHorizontalLayout(_layout);
2220
+ const strokeWidth = element.strokeWidth || STROKE_WIDTH;
2221
+ if (isIndentedLayout(_layout)) {
2222
+ return BASE * 4 + strokeWidth;
2223
+ }
2224
+ if (!isHorizontal) {
2225
+ return getMainAxle(element, parent);
2226
+ }
2227
+ else {
2228
+ return getSecondAxle(element, parent);
2229
+ }
2230
+ },
2231
+ getVerticalGap(element, parent) {
2232
+ const _layout = (parent && parent.layout) || getRootLayout(element);
2233
+ if (isIndentedLayout(_layout)) {
2234
+ return BASE;
2235
+ }
2236
+ const isHorizontal = isHorizontalLayout(_layout);
2237
+ if (isHorizontal) {
2238
+ return getMainAxle(element, parent);
2239
+ }
2240
+ else {
2241
+ return getSecondAxle(element, parent);
2242
+ }
2243
+ },
2244
+ getVerticalConnectingPosition(element, parent) {
2245
+ if (element.shape === MindElementShape.underline && parent && isHorizontalLogicLayout(parent.layout)) {
2246
+ return ConnectingPosition.bottom;
2247
+ }
2248
+ return undefined;
2249
+ },
2250
+ getExtendHeight(node) {
2251
+ return BASE * 6;
2252
+ },
2253
+ getIndentedCrossLevelGap() {
2254
+ return BASE * 2;
2255
+ }
2256
+ };
2257
+ };
2258
+
1868
2259
  /**
1869
2260
  * get correctly layout:
1870
2261
  * 1. root is standard -> left or right
@@ -2165,309 +2556,80 @@ function drawAbstractLink(board, node, isHorizontal) {
2165
2556
  g.appendChild(straightLine);
2166
2557
  return g;
2167
2558
  }
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;
2425
- }
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;
2559
+ 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]}`, {
2560
+ stroke: branchColor,
2561
+ strokeWidth: branchWidth
2438
2562
  });
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
- };
2563
+ return link;
2564
+ }
2453
2565
 
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
- };
2566
+ class EmojiDrawer {
2567
+ constructor(board, viewContainerRef) {
2568
+ this.board = board;
2569
+ this.viewContainerRef = viewContainerRef;
2570
+ this.componentRef = null;
2571
+ }
2572
+ draw(emoji, element) {
2573
+ this.destroy();
2574
+ const componentType = this.board.drawEmoji(emoji, element);
2575
+ this.componentRef = this.viewContainerRef.createComponent(componentType);
2576
+ this.componentRef.instance.emojiItem = emoji;
2577
+ this.componentRef.instance.board = this.board;
2578
+ this.componentRef.instance.element = element;
2579
+ this.componentRef.instance.fontSize = getEmojiFontSize(element);
2580
+ }
2581
+ get nativeElement() {
2582
+ if (this.componentRef) {
2583
+ return this.componentRef.instance.nativeElement;
2584
+ }
2585
+ else {
2586
+ return null;
2587
+ }
2588
+ }
2589
+ destroy() {
2590
+ if (this.componentRef) {
2591
+ this.componentRef.destroy();
2592
+ this.componentRef = null;
2593
+ }
2594
+ }
2595
+ }
2596
+ class NodeEmojisDrawer {
2597
+ constructor(board, viewContainerRef) {
2598
+ this.board = board;
2599
+ this.viewContainerRef = viewContainerRef;
2600
+ this.emojiDrawers = [];
2601
+ }
2602
+ drawEmojis(element) {
2603
+ this.destroy();
2604
+ if (MindElement.hasEmojis(element)) {
2605
+ this.g = createG();
2606
+ this.g.classList.add('emojis');
2607
+ const foreignRectangle = getEmojiForeignRectangle(this.board, element);
2608
+ const foreignObject = createForeignObject(foreignRectangle.x, foreignRectangle.y, foreignRectangle.width, foreignRectangle.height);
2609
+ this.g.append(foreignObject);
2610
+ const container = document.createElement('div');
2611
+ container.classList.add('node-emojis-container');
2612
+ foreignObject.append(container);
2613
+ this.emojiDrawers = element.data.emojis.map(emojiItem => {
2614
+ const drawer = new EmojiDrawer(this.board, this.viewContainerRef);
2615
+ drawer.draw(emojiItem, element);
2616
+ return drawer;
2617
+ });
2618
+ this.emojiDrawers.forEach(drawer => {
2619
+ container.append(drawer.nativeElement);
2620
+ });
2621
+ return this.g;
2622
+ }
2623
+ return undefined;
2624
+ }
2625
+ destroy() {
2626
+ if (this.g) {
2627
+ this.g.remove();
2628
+ }
2629
+ this.emojiDrawers.forEach(drawer => drawer.destroy());
2630
+ this.emojiDrawers = [];
2631
+ }
2632
+ }
2471
2633
 
2472
2634
  class BaseDrawer {
2473
2635
  constructor(board) {
@@ -2826,36 +2988,6 @@ class CollapseDrawer extends BaseDrawer {
2826
2988
  }
2827
2989
  }
2828
2990
 
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
2991
  class NodeImageDrawer {
2860
2992
  constructor(board, viewContainerRef) {
2861
2993
  this.board = board;
@@ -2869,9 +3001,9 @@ class NodeImageDrawer {
2869
3001
  }
2870
3002
  this.g = createG();
2871
3003
  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;
3004
+ this.foreignObject = createForeignObject(foreignRectangle.x, foreignRectangle.y, foreignRectangle.width, foreignRectangle.height);
3005
+ this.g.append(this.foreignObject);
3006
+ const componentType = this.board.getPluginOptions(WithMindPluginKey).imageComponentType;
2875
3007
  if (!componentType) {
2876
3008
  throw new Error('Not implement drawEmoji method error.');
2877
3009
  }
@@ -2880,7 +3012,7 @@ class NodeImageDrawer {
2880
3012
  this.componentRef.instance.element = element;
2881
3013
  this.componentRef.instance.imageItem = element.data.image;
2882
3014
  this.componentRef.instance.cdr.markForCheck();
2883
- foreignObject.append(this.componentRef.instance.nativeElement);
3015
+ this.foreignObject.append(this.componentRef.instance.nativeElement);
2884
3016
  nodeG.appendChild(this.g);
2885
3017
  }
2886
3018
  updateImage(nodeG, previous, current) {
@@ -2894,6 +3026,10 @@ class NodeImageDrawer {
2894
3026
  }
2895
3027
  const currentForeignObject = getImageForeignRectangle(this.board, current);
2896
3028
  updateForeignObject(this.g, currentForeignObject.width, currentForeignObject.height, currentForeignObject.x, currentForeignObject.y);
3029
+ // solve image lose on move node
3030
+ if (this.foreignObject.children.length === 0) {
3031
+ this.foreignObject.append(this.componentRef.instance.nativeElement);
3032
+ }
2897
3033
  this.componentRef?.instance.cdr.markForCheck();
2898
3034
  }
2899
3035
  destroy() {
@@ -2931,8 +3067,6 @@ class MindNodeComponent extends PlaitPluginElementComponent {
2931
3067
  this.textManage = new TextManage(this.board, this.viewContainerRef, () => {
2932
3068
  const rect = getTopicRectangleByNode(this.board, this.node);
2933
3069
  return rect;
2934
- }, (point) => {
2935
- return isHitMindElement(this.board, point, this.element);
2936
3070
  }, (textManageRef) => {
2937
3071
  const width = textManageRef.width;
2938
3072
  const height = textManageRef.height;
@@ -3057,20 +3191,35 @@ class MindNodeComponent extends PlaitPluginElementComponent {
3057
3191
  this.textManage.draw(this.element.data.topic);
3058
3192
  this.g.append(this.textManage.g);
3059
3193
  if (this.element.manualWidth) {
3060
- const width = NodeSpace.getNodeResizableWidth(this.board, this.element);
3194
+ const width = NodeSpace.getNodeDynamicWidth(this.board, this.element);
3061
3195
  this.textManage.updateWidth(width);
3062
3196
  }
3063
3197
  }
3064
3198
  updateTopic() {
3065
3199
  this.textManage.updateText(this.element.data.topic);
3066
3200
  this.textManage.updateRectangle();
3201
+ if (this.element.manualWidth) {
3202
+ const width = NodeSpace.getNodeDynamicWidth(this.board, this.element);
3203
+ this.textManage.updateWidth(width);
3204
+ }
3067
3205
  }
3068
3206
  editTopic() {
3069
3207
  this.activeDrawer.draw(this.element, this.g, { selected: this.selected, isEditing: true });
3208
+ // update text max-width when image width greater than topic default max width to cover node topic default max width style
3209
+ const defaultMaxWidth = TOPIC_DEFAULT_MAX_WORD_COUNT * (PlaitMind.isMind(this.element) ? ROOT_TOPIC_FONT_SIZE : TOPIC_FONT_SIZE);
3210
+ let hasMaxWidth = false;
3211
+ if (!this.element.manualWidth && MindElement.hasImage(this.element) && this.element.data.image.width > defaultMaxWidth) {
3212
+ const width = NodeSpace.getNodeDynamicWidth(this.board, this.element);
3213
+ this.textManage.updateWidth(width);
3214
+ hasMaxWidth = true;
3215
+ }
3070
3216
  this.textManage.edit((origin) => {
3071
3217
  if (origin === ExitOrigin.default) {
3072
3218
  this.activeDrawer.draw(this.element, this.g, { selected: this.selected, isEditing: false });
3073
3219
  }
3220
+ if (hasMaxWidth) {
3221
+ this.textManage.updateWidth(0);
3222
+ }
3074
3223
  });
3075
3224
  }
3076
3225
  ngOnDestroy() {
@@ -3112,73 +3261,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImpor
3112
3261
  }]
3113
3262
  }], ctorParameters: function () { return [{ type: i0.ViewContainerRef }, { type: i0.ChangeDetectorRef }]; } });
3114
3263
 
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
3264
  class PlaitMindComponent extends MindNodeComponent {
3183
3265
  ngOnInit() {
3184
3266
  this.updateMindLayout();
@@ -3914,7 +3996,7 @@ const withNodeHoverDetect = (board) => {
3914
3996
  };
3915
3997
 
3916
3998
  const withNodeImage = (board) => {
3917
- const { keydown, mousedown, globalMouseup } = board;
3999
+ const { keydown, mousedown, globalMouseup, insertFragment } = board;
3918
4000
  board.mousedown = (event) => {
3919
4001
  const selectedImageElement = getSelectedImageElement(board);
3920
4002
  if (PlaitBoard.isReadonly(board) || !isMainPointer(event) || !PlaitBoard.isPointer(board, PlaitPointerType.selection)) {
@@ -3940,7 +4022,6 @@ const withNodeImage = (board) => {
3940
4022
  if (hitImage) {
3941
4023
  temporaryDisableSelection(board);
3942
4024
  setImageFocus(board, hitElements[0], true);
3943
- clearSelectedElement(board);
3944
4025
  }
3945
4026
  mousedown(event);
3946
4027
  };
@@ -3964,6 +4045,21 @@ const withNodeImage = (board) => {
3964
4045
  }
3965
4046
  globalMouseup(event);
3966
4047
  };
4048
+ board.insertFragment = (data, targetPoint) => {
4049
+ const selectedElements = getSelectedElements(board);
4050
+ const isSelectedImage = !!getSelectedImageElement(board);
4051
+ const isSingleSelection = selectedElements.length === 1 && MindElement.isMindElement(board, selectedElements[0]);
4052
+ if (data?.files.length && (isSingleSelection || isSelectedImage)) {
4053
+ const selectedElement = (selectedElements[0] || getSelectedImageElement(board));
4054
+ const acceptImageArray = acceptImageTypes.map(type => 'image/' + type);
4055
+ if (acceptImageArray.includes(data?.files[0].type)) {
4056
+ const imageFile = data.files[0];
4057
+ buildImage(board, selectedElement, imageFile);
4058
+ return;
4059
+ }
4060
+ }
4061
+ insertFragment(data, targetPoint);
4062
+ };
3967
4063
  return board;
3968
4064
  };
3969
4065
 
@@ -3993,7 +4089,7 @@ const withNodeResize = (board) => {
3993
4089
  addResizing(board, targetElement);
3994
4090
  targetElementRef = {
3995
4091
  minWidth: NodeSpace.getNodeResizableMinWidth(board, targetElement),
3996
- currentWidth: NodeSpace.getNodeResizableWidth(board, targetElement),
4092
+ currentWidth: NodeSpace.getNodeDynamicWidth(board, targetElement),
3997
4093
  path: PlaitBoard.findPath(board, targetElement),
3998
4094
  textManage: PlaitElement.getComponent(targetElement).textManage
3999
4095
  };
@@ -4009,7 +4105,7 @@ const withNodeResize = (board) => {
4009
4105
  const offsetX = endPoint[0] - startPoint[0];
4010
4106
  const zoom = board.viewport.zoom;
4011
4107
  let resizedWidth = targetElementRef.currentWidth + offsetX / zoom;
4012
- if (resizedWidth < targetElementRef.minWidth) {
4108
+ if (resizedWidth <= targetElementRef.minWidth) {
4013
4109
  resizedWidth = targetElementRef.minWidth;
4014
4110
  }
4015
4111
  const newTarget = PlaitNode.get(board, targetElementRef.path);
@@ -4236,6 +4332,42 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImpor
4236
4332
  args: ['mousedown']
4237
4333
  }] } });
4238
4334
 
4335
+ class MindImageBaseComponent {
4336
+ set imageItem(value) {
4337
+ this.afterImageItemChange(this._imageItem, value);
4338
+ this._imageItem = value;
4339
+ }
4340
+ get imageItem() {
4341
+ return this._imageItem;
4342
+ }
4343
+ get nativeElement() {
4344
+ return this.elementRef.nativeElement;
4345
+ }
4346
+ constructor(elementRef, cdr) {
4347
+ this.elementRef = elementRef;
4348
+ this.cdr = cdr;
4349
+ this.isFocus = false;
4350
+ }
4351
+ }
4352
+ 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 });
4353
+ 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 });
4354
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImport: i0, type: MindImageBaseComponent, decorators: [{
4355
+ type: Directive,
4356
+ args: [{
4357
+ host: {
4358
+ class: 'mind-node-image'
4359
+ }
4360
+ }]
4361
+ }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { imageItem: [{
4362
+ type: Input
4363
+ }], board: [{
4364
+ type: Input
4365
+ }], element: [{
4366
+ type: Input
4367
+ }], isFocus: [{
4368
+ type: Input
4369
+ }] } });
4370
+
4239
4371
  /*
4240
4372
  * Public API Surface of mind
4241
4373
  */
@@ -4244,5 +4376,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.5", ngImpor
4244
4376
  * Generated bundle index. Do not edit.
4245
4377
  */
4246
4378
 
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 };
4379
+ 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
4380
  //# sourceMappingURL=plait-mind.mjs.map