@plait/common 0.61.2 → 0.62.0-next.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.
Files changed (51) hide show
  1. package/constants/default.d.ts +1 -0
  2. package/core/element-flavour.d.ts +1 -1
  3. package/core/index.d.ts +4 -0
  4. package/core/render-component.d.ts +4 -0
  5. package/esm2022/constants/default.mjs +2 -1
  6. package/esm2022/core/element-flavour.mjs +1 -1
  7. package/esm2022/core/group.component.mjs +3 -3
  8. package/esm2022/core/index.mjs +5 -0
  9. package/esm2022/core/render-component.mjs +2 -0
  10. package/esm2022/generators/generator.mjs +1 -1
  11. package/esm2022/generators/index.mjs +2 -2
  12. package/esm2022/image/image-base.component.mjs +28 -0
  13. package/esm2022/image/image.generator.mjs +99 -0
  14. package/esm2022/image/index.mjs +4 -0
  15. package/esm2022/image/with-image.mjs +8 -0
  16. package/esm2022/plugins/index.mjs +1 -2
  17. package/esm2022/public-api.mjs +5 -4
  18. package/esm2022/text/index.mjs +5 -0
  19. package/esm2022/text/text-manage.mjs +138 -0
  20. package/esm2022/text/text-measure.mjs +61 -0
  21. package/esm2022/text/types.mjs +7 -0
  22. package/esm2022/text/with-text.mjs +8 -0
  23. package/esm2022/transforms/index.mjs +1 -2
  24. package/esm2022/utils/image.mjs +3 -3
  25. package/esm2022/utils/text.mjs +22 -20
  26. package/fesm2022/plait-common.mjs +341 -214
  27. package/fesm2022/plait-common.mjs.map +1 -1
  28. package/generators/index.d.ts +1 -1
  29. package/image/image-base.component.d.ts +17 -0
  30. package/image/image.generator.d.ts +27 -0
  31. package/image/index.d.ts +3 -0
  32. package/image/with-image.d.ts +15 -0
  33. package/package.json +1 -3
  34. package/plugins/index.d.ts +0 -1
  35. package/public-api.d.ts +4 -3
  36. package/text/index.d.ts +4 -0
  37. package/text/text-manage.d.ts +41 -0
  38. package/text/text-measure.d.ts +8 -0
  39. package/text/types.d.ts +24 -0
  40. package/text/with-text.d.ts +25 -0
  41. package/transforms/index.d.ts +0 -1
  42. package/utils/image.d.ts +1 -5
  43. package/utils/text.d.ts +9 -6
  44. package/core/image-base.component.d.ts +0 -29
  45. package/esm2022/core/image-base.component.mjs +0 -95
  46. package/esm2022/generators/image.generator.mjs +0 -59
  47. package/esm2022/plugins/text-options.mjs +0 -2
  48. package/esm2022/transforms/text.mjs +0 -71
  49. package/generators/image.generator.d.ts +0 -24
  50. package/plugins/text-options.d.ts +0 -5
  51. package/transforms/text.d.ts +0 -9
@@ -1,9 +1,7 @@
1
- import { PlaitGroupElement, getSelectionAngle, getElementsInGroup, setAngleForG, RectangleClient, drawCircle, PlaitBoard, RESIZE_HANDLE_CLASS_NAME, createG, setStrokeLinecap, drawRectangle, SELECTION_RECTANGLE_CLASS_NAME, createForeignObject, updateForeignObject, ResizeCursorClass, RESIZE_CURSORS, setDragging, rotatePoints, isSelectionMoving, getSelectedElements, distanceBetweenPointAndPoint, Point, Direction, hotkeys, PlaitContextService, createDebugGenerator, Transforms, getHighestSelectedElements, getRectangleByElements, MERGING, PlaitPointerType, isMainPointer, toViewBoxPoint, toHostPoint, preventTouchMove, PRESS_AND_MOVE_BUFFER, isDragging, throttleRAF, handleTouchTarget, ACTIVE_STROKE_WIDTH, getRectangleByGroup, ElementFlavour, isSelectedElementOrGroup, Selection, getHitElementsBySelection, createGroupRectangleG, getSelectedGroups, getHighestSelectedGroups, getSelectedIsolatedElements, idCreator, getSelectedIsolatedElementsCanAddToGroup, getGroupByElement } from '@plait/core';
1
+ import { PlaitGroupElement, getSelectionAngle, getElementsInGroup, setAngleForG, RectangleClient, drawCircle, PlaitBoard, RESIZE_HANDLE_CLASS_NAME, createG, setStrokeLinecap, drawRectangle, SELECTION_RECTANGLE_CLASS_NAME, ResizeCursorClass, RESIZE_CURSORS, setDragging, rotatePoints, isSelectionMoving, getSelectedElements, distanceBetweenPointAndPoint, Point, Direction, hotkeys, createDebugGenerator, createForeignObject, ACTIVE_STROKE_WIDTH, updateForeignObject, Transforms, getHighestSelectedElements, getRectangleByElements, MERGING, PlaitPointerType, isMainPointer, toViewBoxPoint, toHostPoint, preventTouchMove, PRESS_AND_MOVE_BUFFER, isDragging, throttleRAF, handleTouchTarget, getRectangleByGroup, ElementFlavour, isSelectedElementOrGroup, Selection, getHitElementsBySelection, createGroupRectangleG, getSelectedGroups, getHighestSelectedGroups, getSelectedIsolatedElements, idCreator, getSelectedIsolatedElementsCanAddToGroup, getGroupByElement, updateForeignObjectWidth, IS_TEXT_EDITABLE } from '@plait/core';
2
2
  import { isKeyHotkey } from 'is-hotkey';
3
- import { PlaitMarkEditor, MarkTypes, AlignEditor } from '@plait/text';
4
- import { Node, Transforms as Transforms$1, Editor } from 'slate';
5
- import * as i0 from '@angular/core';
6
- import { Directive, Input } from '@angular/core';
3
+ import { Node, Operation, Transforms as Transforms$1, Range, Editor } from 'slate';
4
+ import { fromEvent, timer } from 'rxjs';
7
5
 
8
6
  const BASE = 4;
9
7
  const PRIMARY_COLOR = '#6698FF';
@@ -13,6 +11,7 @@ const DEFAULT_ROUTE_MARGIN = 30;
13
11
  const TRANSPARENT = 'transparent';
14
12
  const ROTATE_HANDLE_DISTANCE_TO_ELEMENT = 20;
15
13
  const ROTATE_HANDLE_SIZE = 18;
14
+ const DEFAULT_FONT_FAMILY = 'PingFangSC-Regular, "PingFang SC"';
16
15
 
17
16
  var MediaKeys;
18
17
  (function (MediaKeys) {
@@ -183,62 +182,6 @@ class ActiveGenerator extends Generator {
183
182
  }
184
183
  }
185
184
 
186
- class ImageGenerator extends Generator {
187
- static { this.key = 'image-generator'; }
188
- constructor(board, options) {
189
- super(board, options);
190
- this.board = board;
191
- this.options = options;
192
- }
193
- canDraw(element, data) {
194
- return !!this.options.getImageItem(element);
195
- }
196
- draw(element, viewContainerRef) {
197
- const g = createG();
198
- const foreignRectangle = this.options.getRectangle(element);
199
- this.foreignObject = createForeignObject(foreignRectangle.x, foreignRectangle.y, foreignRectangle.width, foreignRectangle.height);
200
- g.append(this.foreignObject);
201
- const componentType = this.board.getPluginOptions(WithCommonPluginKey)
202
- .imageComponentType;
203
- if (!componentType) {
204
- throw new Error('Not implement ImageBaseComponent error.');
205
- }
206
- this.componentRef = viewContainerRef.createComponent(componentType);
207
- this.componentRef.instance.board = this.board;
208
- this.componentRef.instance.imageItem = this.options.getImageItem(element);
209
- this.componentRef.instance.element = element;
210
- this.componentRef.instance.getRectangle = () => {
211
- return this.options.getRectangle(element);
212
- };
213
- this.componentRef.instance.cdr.markForCheck();
214
- this.foreignObject.append(this.componentRef.instance.nativeElement);
215
- return g;
216
- }
217
- updateImage(nodeG, previous, current) {
218
- if (previous !== current && this.componentRef) {
219
- this.componentRef.instance.imageItem = this.options.getImageItem(current);
220
- this.componentRef.instance.element = current;
221
- this.componentRef.instance.getRectangle = () => {
222
- return this.options.getRectangle(current);
223
- };
224
- }
225
- const currentForeignObject = this.options.getRectangle(current);
226
- updateForeignObject(this.g, currentForeignObject.width, currentForeignObject.height, currentForeignObject.x, currentForeignObject.y);
227
- if (currentForeignObject && current.angle) {
228
- setAngleForG(this.g, RectangleClient.getCenterPoint(currentForeignObject), current.angle);
229
- }
230
- // solve image lose on move node
231
- if (this.foreignObject.children.length === 0) {
232
- this.foreignObject.append(this.componentRef.instance.nativeElement);
233
- }
234
- this.componentRef?.instance.cdr.markForCheck();
235
- }
236
- destroy() {
237
- super.destroy();
238
- this.componentRef?.destroy();
239
- }
240
- }
241
-
242
185
  const getResizeHandleByIndex = (index) => {
243
186
  return `${index}`;
244
187
  };
@@ -749,7 +692,7 @@ const getFirstTextManage = (element) => {
749
692
  };
750
693
  const getTextEditorsByElement = (element) => {
751
694
  return getTextManages(element).map(manage => {
752
- return manage.componentRef.instance.editor;
695
+ return manage.editor;
753
696
  });
754
697
  };
755
698
  const getFirstTextEditor = (element) => {
@@ -770,20 +713,6 @@ const findFirstTextEditor = (board) => {
770
713
  });
771
714
  return firstEditor;
772
715
  };
773
- const getTextMarksByElement = (element) => {
774
- const editors = getTextEditorsByElement(element);
775
- const editor = editors[0];
776
- if (!editor) {
777
- return {};
778
- }
779
- if (editor.children.length === 0) {
780
- const textManage = getTextManages(element)[0];
781
- const currentMarks = PlaitMarkEditor.getMarksByElement(textManage.componentRef.instance.children[0]);
782
- return currentMarks;
783
- }
784
- const currentMarks = PlaitMarkEditor.getMarks(editor);
785
- return currentMarks;
786
- };
787
716
  const getElementsText = (elements) => {
788
717
  return elements
789
718
  .map(item => {
@@ -815,10 +744,10 @@ const getTextEditors = (board, elements) => {
815
744
  });
816
745
  const editingTextManage = textManages.find(textManage => textManage.isEditing);
817
746
  if (editingTextManage) {
818
- return [editingTextManage.componentRef.instance.editor];
747
+ return [editingTextManage.editor];
819
748
  }
820
749
  return textManages.map(item => {
821
- return item.componentRef.instance.editor;
750
+ return item.editor;
822
751
  });
823
752
  }
824
753
  return undefined;
@@ -831,10 +760,27 @@ const getEditingTextEditor = (board, elements) => {
831
760
  });
832
761
  const editingTextManage = textManages.find(textManage => textManage.isEditing);
833
762
  if (editingTextManage) {
834
- return editingTextManage.componentRef.instance.editor;
763
+ return editingTextManage.editor;
835
764
  }
836
765
  return undefined;
837
766
  };
767
+ const buildText = (text, align, properties) => {
768
+ properties = properties || {};
769
+ const plaitText = typeof text === 'string' ? { children: [{ text, ...properties }] } : text;
770
+ if (align) {
771
+ plaitText.align = align;
772
+ }
773
+ return plaitText;
774
+ };
775
+ const getLineHeightByFontSize = (fontSize) => {
776
+ if (fontSize === 14) {
777
+ return 20;
778
+ }
779
+ if (fontSize === 18) {
780
+ return 25;
781
+ }
782
+ return fontSize * 1.5;
783
+ };
838
784
  const ELEMENT_TO_TEXT_MANAGES = new WeakMap();
839
785
 
840
786
  const selectImage = (board, defaultImageWidth, handle, acceptImageTypes = ['png', 'jpeg', 'gif', 'bmp']) => {
@@ -855,7 +801,7 @@ const buildImage = async (board, imageFile, defaultImageWidth, handle) => {
855
801
  });
856
802
  let imageItem = null;
857
803
  const url = URL.createObjectURL(imageFile);
858
- const context = PlaitBoard.getComponent(board).viewContainerRef.injector.get(PlaitContextService);
804
+ const context = PlaitBoard.getBoardContext(board);
859
805
  context.setUploadingFile({ url, file: imageFile });
860
806
  imageItem = {
861
807
  url,
@@ -1280,6 +1226,101 @@ const removeRotating = (board) => {
1280
1226
  setDragging(board, false);
1281
1227
  };
1282
1228
 
1229
+ const FOREIGN_OBJECT_IMAGE_CLASS_NAME = 'foreign-object-image';
1230
+ const IMAGE_CONTAINER_CLASS_NAME = 'plait-image-container';
1231
+ class ImageGenerator extends Generator {
1232
+ static { this.key = 'image-generator'; }
1233
+ constructor(board, options) {
1234
+ super(board, options);
1235
+ this.board = board;
1236
+ this.options = options;
1237
+ this.isFocus = false;
1238
+ }
1239
+ canDraw(element) {
1240
+ return !!this.options.getImageItem(element);
1241
+ }
1242
+ draw(element) {
1243
+ this.element = element;
1244
+ const g = createG();
1245
+ const foreignRectangle = this.options.getRectangle(element);
1246
+ this.foreignObject = createForeignObject(foreignRectangle.x, foreignRectangle.y, foreignRectangle.width, foreignRectangle.height);
1247
+ this.foreignObject.classList.add(FOREIGN_OBJECT_IMAGE_CLASS_NAME);
1248
+ g.append(this.foreignObject);
1249
+ const props = {
1250
+ board: this.board,
1251
+ imageItem: this.options.getImageItem(element),
1252
+ element,
1253
+ getRectangle: () => {
1254
+ return this.options.getRectangle(element);
1255
+ }
1256
+ };
1257
+ this.imageComponentRef = this.board.renderImage(this.foreignObject, props);
1258
+ this.activeGenerator = new ActiveGenerator(this.board, {
1259
+ getStrokeWidth: () => {
1260
+ const selectedElements = getSelectedElements(this.board);
1261
+ if (!(selectedElements.length === 1 && !isSelectionMoving(this.board))) {
1262
+ return ACTIVE_STROKE_WIDTH;
1263
+ }
1264
+ else {
1265
+ return ACTIVE_STROKE_WIDTH;
1266
+ }
1267
+ },
1268
+ getStrokeOpacity: () => {
1269
+ const selectedElements = getSelectedElements(this.board);
1270
+ if ((selectedElements.length === 1 && !isSelectionMoving(this.board)) || !selectedElements.length) {
1271
+ return 1;
1272
+ }
1273
+ else {
1274
+ return 0.5;
1275
+ }
1276
+ },
1277
+ getRectangle: () => {
1278
+ return this.options.getRectangle(this.element);
1279
+ },
1280
+ hasResizeHandle: () => {
1281
+ const isSelectedImageElement = canResize(this.board, this.element);
1282
+ const isSelectedImage = !!getElementOfFocusedImage(this.board);
1283
+ return isSelectedImage || isSelectedImageElement;
1284
+ }
1285
+ });
1286
+ return g;
1287
+ }
1288
+ updateImage(nodeG, previous, current) {
1289
+ this.element = current;
1290
+ if (previous !== current && this.imageComponentRef) {
1291
+ const props = {
1292
+ imageItem: this.options.getImageItem(current),
1293
+ element: current,
1294
+ getRectangle: () => {
1295
+ return this.options.getRectangle(current);
1296
+ }
1297
+ };
1298
+ this.imageComponentRef.update(props);
1299
+ }
1300
+ const currentForeignObject = this.options.getRectangle(current);
1301
+ updateForeignObject(this.g, currentForeignObject.width, currentForeignObject.height, currentForeignObject.x, currentForeignObject.y);
1302
+ if (currentForeignObject && current.angle) {
1303
+ setAngleForG(this.g, RectangleClient.getCenterPoint(currentForeignObject), current.angle);
1304
+ }
1305
+ const activeG = PlaitBoard.getElementActiveHost(this.board);
1306
+ this.activeGenerator.processDrawing(current, activeG, { selected: this.isFocus });
1307
+ }
1308
+ setFocus(element, isFocus) {
1309
+ this.isFocus = isFocus;
1310
+ const activeG = PlaitBoard.getElementActiveHost(this.board);
1311
+ this.activeGenerator.processDrawing(element, activeG, { selected: isFocus });
1312
+ const props = {
1313
+ isFocus
1314
+ };
1315
+ this.imageComponentRef.update(props);
1316
+ }
1317
+ destroy() {
1318
+ super.destroy();
1319
+ this.imageComponentRef?.destroy();
1320
+ this.activeGenerator?.destroy();
1321
+ }
1322
+ }
1323
+
1283
1324
  const setProperty = (board, properties, options) => {
1284
1325
  const selectedElements = getSelectedElements(board);
1285
1326
  selectedElements.forEach(element => {
@@ -1433,73 +1474,6 @@ const AlignTransform = {
1433
1474
  distributeVertical
1434
1475
  };
1435
1476
 
1436
- const setTextMarks = (board, mark) => {
1437
- const selectedElements = getSelectedElements(board);
1438
- if (selectedElements.length) {
1439
- const firstEditor = findFirstTextEditor(board);
1440
- if (!firstEditor) {
1441
- return;
1442
- }
1443
- const activeMarks = PlaitMarkEditor.getMarks(firstEditor);
1444
- const elements = selectedElements.filter(element => {
1445
- const editors = getTextEditorsByElement(element);
1446
- return editors.some(editor => {
1447
- const elementMarks = PlaitMarkEditor.getMarks(editor);
1448
- return elementMarks[mark] === activeMarks[mark];
1449
- });
1450
- });
1451
- const editors = getTextEditors(board, elements);
1452
- if (editors && editors.length) {
1453
- editors.forEach(editor => {
1454
- PlaitMarkEditor.toggleMark(editor, mark);
1455
- });
1456
- }
1457
- }
1458
- };
1459
- const setFontSize = (board, size, defaultFontSize) => {
1460
- const editors = getTextEditors(board);
1461
- if (editors && editors.length) {
1462
- const selectedElements = getSelectedElements(board);
1463
- editors.forEach(editor => {
1464
- let finalDefaultFontSize;
1465
- if (typeof defaultFontSize === 'function') {
1466
- const element = selectedElements.find(element => {
1467
- const textEditors = getTextEditorsByElement(element);
1468
- return textEditors.includes(editor);
1469
- });
1470
- finalDefaultFontSize = defaultFontSize(element);
1471
- }
1472
- else {
1473
- finalDefaultFontSize = defaultFontSize;
1474
- }
1475
- PlaitMarkEditor.setFontSizeMark(editor, size, finalDefaultFontSize);
1476
- });
1477
- }
1478
- };
1479
- const setTextColor = (board, color, textSelection) => {
1480
- const editors = getTextEditors(board);
1481
- if (editors && editors.length) {
1482
- editors.forEach(editor => {
1483
- if (textSelection) {
1484
- Transforms$1.select(editor, textSelection);
1485
- }
1486
- if (color === 'transparent') {
1487
- Editor.removeMark(editor, MarkTypes.color);
1488
- }
1489
- else {
1490
- PlaitMarkEditor.setColorMark(editor, color);
1491
- }
1492
- });
1493
- }
1494
- };
1495
- const setTextAlign = (board, align) => {
1496
- const editors = getTextEditors(board);
1497
- if (editors && editors.length) {
1498
- editors.forEach(editor => AlignEditor.setAlign(editor, align));
1499
- }
1500
- };
1501
- const TextTransforms = { setTextAlign, setTextColor, setFontSize, setTextMarks };
1502
-
1503
1477
  const normalizeShapePoints = (points, shift = false) => {
1504
1478
  let start = points[0];
1505
1479
  let end = points[1];
@@ -1707,7 +1681,7 @@ class GroupComponent extends CommonElementFlavour {
1707
1681
  initialize() {
1708
1682
  super.initialize();
1709
1683
  this.initializeGenerator();
1710
- const contextService = PlaitBoard.getViewContainerRef(this.board).injector.get(PlaitContextService);
1684
+ const contextService = PlaitBoard.getBoardContext(this.board);
1711
1685
  this.onStableSubscription = contextService.onStable().subscribe(() => {
1712
1686
  const elementsInGroup = getElementsInGroup(this.board, this.element, false, true);
1713
1687
  const isPartialSelectGroup = elementsInGroup.some(item => isSelectedElementOrGroup(this.board, item)) &&
@@ -1915,94 +1889,247 @@ const updateSiblingElementGroupId = (board, removeGroups) => {
1915
1889
  };
1916
1890
 
1917
1891
  class ImageBaseComponent {
1892
+ constructor() {
1893
+ this.initialized = false;
1894
+ }
1918
1895
  set imageItem(value) {
1919
- this.afterImageItemChange(this._imageItem, value);
1920
1896
  this._imageItem = value;
1921
- this.drawFocus();
1897
+ if (this.initialized) {
1898
+ this.afterImageItemChange(this._imageItem, value);
1899
+ }
1922
1900
  }
1923
1901
  get imageItem() {
1924
1902
  return this._imageItem;
1925
1903
  }
1926
1904
  set isFocus(value) {
1927
1905
  this._isFocus = value;
1928
- this.drawFocus();
1929
1906
  }
1930
1907
  get isFocus() {
1931
1908
  return this._isFocus;
1932
1909
  }
1933
- get nativeElement() {
1934
- return this.elementRef.nativeElement;
1910
+ initialize() {
1911
+ this.initialized = true;
1912
+ this.nativeElement().classList.add(IMAGE_CONTAINER_CLASS_NAME);
1935
1913
  }
1936
- constructor(elementRef, cdr) {
1937
- this.elementRef = elementRef;
1938
- this.cdr = cdr;
1939
- this.initialized = false;
1914
+ destroy() {
1940
1915
  }
1941
- ngOnInit() {
1942
- this.activeGenerator = new ActiveGenerator(this.board, {
1943
- getStrokeWidth: () => {
1944
- const selectedElements = getSelectedElements(this.board);
1945
- if (!(selectedElements.length === 1 && !isSelectionMoving(this.board))) {
1946
- return ACTIVE_STROKE_WIDTH;
1947
- }
1948
- else {
1949
- return ACTIVE_STROKE_WIDTH;
1950
- }
1951
- },
1952
- getStrokeOpacity: () => {
1953
- const selectedElements = getSelectedElements(this.board);
1954
- if ((selectedElements.length === 1 && !isSelectionMoving(this.board)) || !selectedElements.length) {
1955
- return 1;
1916
+ }
1917
+
1918
+ function measureElement(element, options, containerMaxWidth = 10000) {
1919
+ const canvas = document.createElement('canvas');
1920
+ const ctx = canvas.getContext('2d');
1921
+ const textEntries = Node.texts(element);
1922
+ const lines = [[]];
1923
+ for (const textEntry of textEntries) {
1924
+ const [text] = textEntry;
1925
+ const textString = Node.string(text);
1926
+ const textArray = textString.split('\n');
1927
+ textArray.forEach((segmentTextString, index) => {
1928
+ const segmentText = { ...text, text: segmentTextString };
1929
+ if (index === 0) {
1930
+ const currentLine = lines[lines.length - 1];
1931
+ currentLine.push(segmentText);
1932
+ }
1933
+ else {
1934
+ const newLine = [];
1935
+ newLine.push(segmentText);
1936
+ lines.push(newLine);
1937
+ }
1938
+ });
1939
+ }
1940
+ let width = 0;
1941
+ let height = 0;
1942
+ lines.forEach((lineTexts, index) => {
1943
+ let lineWidth = 0;
1944
+ let maxLineHeight = getLineHeightByFontSize(options.fontSize);
1945
+ lineTexts.forEach((text, index) => {
1946
+ const font = getFont(text, { fontFamily: options.fontFamily, fontSize: options.fontSize });
1947
+ ctx.font = font;
1948
+ const textMetrics = ctx.measureText(text.text);
1949
+ lineWidth += textMetrics.width;
1950
+ const isLast = index === lineTexts.length - 1;
1951
+ // skip when text is empty and is not last text of line
1952
+ if (text['font-size'] && (isLast || text.text !== '')) {
1953
+ const lineHeight = getLineHeightByFontSize(parseFloat(text['font-size']));
1954
+ if (lineHeight > maxLineHeight) {
1955
+ maxLineHeight = lineHeight;
1956
1956
  }
1957
- else {
1958
- return 0.5;
1957
+ }
1958
+ });
1959
+ if (lineWidth <= containerMaxWidth) {
1960
+ if (lineWidth > width) {
1961
+ width = lineWidth;
1962
+ }
1963
+ height += maxLineHeight;
1964
+ }
1965
+ else {
1966
+ width = containerMaxWidth;
1967
+ const lineWrapNumber = Math.ceil(lineWidth / containerMaxWidth);
1968
+ height += maxLineHeight * lineWrapNumber;
1969
+ }
1970
+ });
1971
+ return { width, height };
1972
+ }
1973
+ const getFont = (text, options) => {
1974
+ return `${text.italic ? 'italic ' : ''} ${text.bold ? 'bold ' : ''} ${text['font-size'] || options.fontSize}px ${options.fontFamily} `;
1975
+ };
1976
+
1977
+ class TextManage {
1978
+ constructor(board, options) {
1979
+ this.board = board;
1980
+ this.options = options;
1981
+ this.isEditing = false;
1982
+ this.getSize = (element) => {
1983
+ const computedStyle = window.getComputedStyle(this.foreignObject.children[0]);
1984
+ const fontFamily = computedStyle.fontFamily;
1985
+ const fontSize = parseFloat(computedStyle.fontSize);
1986
+ const target = element || this.editor.children[0];
1987
+ return measureElement(target, {
1988
+ fontSize: fontSize,
1989
+ fontFamily
1990
+ }, this.options.getMaxWidth());
1991
+ };
1992
+ this.getText = () => {
1993
+ return this.editor.children[0];
1994
+ };
1995
+ if (!this.options.getMaxWidth) {
1996
+ this.options.getMaxWidth = () => 999;
1997
+ }
1998
+ }
1999
+ draw(text) {
2000
+ const _rectangle = this.options.getRectangle();
2001
+ this.g = createG();
2002
+ this.foreignObject = createForeignObject(_rectangle.x, _rectangle.y, _rectangle.width, _rectangle.height);
2003
+ this.g.append(this.foreignObject);
2004
+ this.g.classList.add('text');
2005
+ const props = {
2006
+ board: this.board,
2007
+ text,
2008
+ textPlugins: this.options.textPlugins,
2009
+ onChange: (data) => {
2010
+ if (data.operations.some(op => !Operation.isSelectionOperation(op))) {
2011
+ const { width, height } = this.getSize();
2012
+ this.options.onChange && this.options.onChange({ ...data, width, height });
2013
+ MERGING.set(this.board, true);
1959
2014
  }
1960
2015
  },
1961
- getRectangle: () => {
1962
- return this.getRectangle();
2016
+ afterInit: (editor) => {
2017
+ this.editor = editor;
1963
2018
  },
1964
- hasResizeHandle: () => {
1965
- const isSelectedImageElement = canResize(this.board, this.element);
1966
- const isSelectedImage = !!getElementOfFocusedImage(this.board);
1967
- return isSelectedImage || isSelectedImageElement;
2019
+ onComposition: (event) => {
2020
+ const fakeRoot = buildCompositionData(this.editor, event.data);
2021
+ if (fakeRoot) {
2022
+ const sizeData = this.getSize(fakeRoot.children[0]);
2023
+ this.options.onChange && this.options.onChange(sizeData);
2024
+ MERGING.set(this.board, true);
2025
+ }
1968
2026
  }
1969
- });
1970
- this.initialized = true;
2027
+ };
2028
+ this.textComponentRef = this.board.renderText(this.foreignObject, props);
1971
2029
  }
1972
- drawFocus() {
1973
- if (this.initialized) {
1974
- const activeG = PlaitBoard.getElementActiveHost(this.board);
1975
- this.activeGenerator.processDrawing(this.element, activeG, { selected: this._isFocus });
1976
- }
2030
+ updateRectangleWidth(width) {
2031
+ updateForeignObjectWidth(this.g, width);
1977
2032
  }
1978
- ngOnDestroy() {
1979
- if (this.activeGenerator) {
1980
- this.activeGenerator.destroy();
1981
- }
2033
+ updateAngle(centerPoint, angle = 0) {
2034
+ setAngleForG(this.g, centerPoint, angle);
2035
+ }
2036
+ updateRectangle(rectangle) {
2037
+ const { x, y, width, height } = rectangle || this.options.getRectangle();
2038
+ updateForeignObject(this.g, width, height, x, y);
2039
+ }
2040
+ updateText(newText) {
2041
+ const props = {
2042
+ text: newText
2043
+ };
2044
+ this.textComponentRef.update(props);
2045
+ }
2046
+ edit(callback) {
2047
+ this.isEditing = true;
2048
+ IS_TEXT_EDITABLE.set(this.board, true);
2049
+ const props = {
2050
+ readonly: false
2051
+ };
2052
+ this.textComponentRef.update(props);
2053
+ Transforms$1.select(this.editor, [0]);
2054
+ const mousedown$ = fromEvent(document, 'mousedown').subscribe((event) => {
2055
+ const point = toViewBoxPoint(this.board, toHostPoint(this.board, event.x, event.y));
2056
+ const textRec = this.options.getRenderRectangle ? this.options.getRenderRectangle() : this.options.getRectangle();
2057
+ const clickInText = RectangleClient.isHit(RectangleClient.getRectangleByPoints([point, point]), textRec);
2058
+ const isAttached = event.target.closest('.plait-board-attached');
2059
+ if (!clickInText && !isAttached) {
2060
+ // handle composition input state, like: Chinese IME Composition Input
2061
+ timer(0).subscribe(() => {
2062
+ exitCallback();
2063
+ });
2064
+ }
2065
+ });
2066
+ const keydown$ = fromEvent(document, 'keydown').subscribe((event) => {
2067
+ if (event.isComposing) {
2068
+ return;
2069
+ }
2070
+ if (event.key === 'Escape' || (event.key === 'Enter' && !event.shiftKey) || event.key === 'Tab') {
2071
+ event.preventDefault();
2072
+ event.stopPropagation();
2073
+ exitCallback();
2074
+ return;
2075
+ }
2076
+ });
2077
+ const exitCallback = () => {
2078
+ this.updateRectangle();
2079
+ mousedown$.unsubscribe();
2080
+ keydown$.unsubscribe();
2081
+ IS_TEXT_EDITABLE.set(this.board, false);
2082
+ MERGING.set(this.board, false);
2083
+ callback && callback();
2084
+ const props = {
2085
+ readonly: true
2086
+ };
2087
+ this.textComponentRef.update(props);
2088
+ this.isEditing = false;
2089
+ };
2090
+ return exitCallback;
2091
+ }
2092
+ destroy() {
2093
+ this.g?.remove();
2094
+ this.textComponentRef?.destroy();
1982
2095
  }
1983
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.2.4", ngImport: i0, type: ImageBaseComponent, deps: [{ token: i0.ElementRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Directive }); }
1984
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.2.4", type: ImageBaseComponent, inputs: { element: "element", imageItem: "imageItem", board: "board", isFocus: "isFocus", getRectangle: "getRectangle", hasResizeHandle: "hasResizeHandle" }, host: { classAttribute: "plait-image-container" }, ngImport: i0 }); }
1985
2096
  }
1986
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.2.4", ngImport: i0, type: ImageBaseComponent, decorators: [{
1987
- type: Directive,
1988
- args: [{
1989
- host: {
1990
- class: 'plait-image-container'
1991
- }
1992
- }]
1993
- }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }], propDecorators: { element: [{
1994
- type: Input
1995
- }], imageItem: [{
1996
- type: Input
1997
- }], board: [{
1998
- type: Input
1999
- }], isFocus: [{
2000
- type: Input
2001
- }], getRectangle: [{
2002
- type: Input
2003
- }], hasResizeHandle: [{
2004
- type: Input
2005
- }] } });
2097
+ const buildCompositionData = (editor, data) => {
2098
+ if (editor.selection && Range.isCollapsed(editor.selection)) {
2099
+ const [textNode, textPath] = Editor.node(editor, editor.selection);
2100
+ const offset = editor.selection.anchor.offset;
2101
+ const clonedElement = JSON.parse(JSON.stringify(editor.children[0]));
2102
+ const root = { children: [clonedElement] };
2103
+ const newTextString = textNode.text.slice(0, offset + 1) + data + textNode.text.slice(offset + 1);
2104
+ const clonedTextNode = Node.get(root, textPath);
2105
+ clonedTextNode.text = newTextString;
2106
+ return root;
2107
+ }
2108
+ return null;
2109
+ };
2110
+
2111
+ const withText = (board) => {
2112
+ const newBoard = board;
2113
+ newBoard.renderText = (container, props) => {
2114
+ throw new Error('No implementation for renderText method.');
2115
+ };
2116
+ return newBoard;
2117
+ };
2118
+
2119
+ var Alignment;
2120
+ (function (Alignment) {
2121
+ Alignment["left"] = "left";
2122
+ Alignment["center"] = "center";
2123
+ Alignment["right"] = "right";
2124
+ })(Alignment || (Alignment = {}));
2125
+
2126
+ const withImage = (board) => {
2127
+ const newBoard = board;
2128
+ newBoard.renderImage = (container, props) => {
2129
+ throw new Error('No implementation for renderImage method.');
2130
+ };
2131
+ return newBoard;
2132
+ };
2006
2133
 
2007
2134
  /*
2008
2135
  * Public API Surface of utils
@@ -2012,5 +2139,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.2.4", ngImpor
2012
2139
  * Generated bundle index. Do not edit.
2013
2140
  */
2014
2141
 
2015
- export { AStar, ActiveGenerator, AlignTransform, BASE, BoardCreationMode, CommonElementFlavour, DEFAULT_ROUTE_MARGIN, ELEMENT_TO_TEXT_MANAGES, Generator, IS_RESIZING, IS_ROTATING, ImageBaseComponent, ImageGenerator, MediaKeys, PICTURE_ACCEPTED_UPLOAD_SIZE, PRIMARY_COLOR, PlaitCommonElementRef, PointGraph, PointNode, PriorityQueue, PropertyTransforms, RESIZE_HANDLE_DIAMETER, ROTATE_HANDLE_DISTANCE_TO_ELEMENT, ROTATE_HANDLE_SIZE, ResizeHandle, TRANSPARENT, TextTransforms, WithCommonPluginKey, WithTextPluginKey, acceptImageTypes, addElementOfFocusedImage, addResizing, addRotating, alignBottom, alignHorizontalCenter, alignLeft, alignRight, alignTop, alignVerticalCenter, buildImage, calculatePolylineLength, canResize, createGraph, distributeHorizontal, distributeVertical, drawFillPrimaryHandle, drawHandle, drawPrimaryHandle, drawRotateHandle, findFirstTextEditor, generateElbowLineRoute, getCreationMode, getCrossingPointsBetweenPointAndSegment, getDirectionBetweenPointAndPoint, getDirectionByPointOfRectangle, getDirectionByVector, getDirectionFactor, getDirectionFactorByDirectionComponent, getEditingTextEditor, getElementOfFocusedImage, getElementsText, getExtendPoint, getFirstTextEditor, getFirstTextManage, getGraphPoints, getIndexByResizeHandle, getMemorizedLatest, getNextPoint, getOppositeDirection, getPointByVectorComponent, getPointByVectorDirectionComponent, getPointOnPolyline, getPoints, getRatioByPoint, getRectangleResizeHandleRefs, getResizeHandleByIndex, getResizeHandlePointByIndex, getRotatedResizeCursorClassByAngle, getSourceAndTargetOuterRectangle, getSymmetricHandleIndex, getTextEditors, getTextEditorsByElement, getTextManages, getTextMarksByElement, getUnitVectorByPointAndPoint, hasAfterDraw, isCornerHandle, isDelete, isDndMode, isDrawingMode, isEdgeHandle, isEnterHotkey, isExpandHotkey, isPointOnSegment, isResizing, isResizingByCondition, isRotating, isSourceAndTargetIntersect, isSpaceHotkey, isTabHotkey, isVirtualKey, memorizeLatest, normalizeShapePoints, reduceRouteMargin, removeDuplicatePoints, removeElementOfFocusedImage, removeResizing, removeRotating, resetPointsAfterResize, rotateVector, rotateVectorAnti90, routeAdjust, selectImage, setCreationMode, setProperty, simplifyOrthogonalPoints, withGroup, withResize };
2142
+ export { AStar, ActiveGenerator, AlignTransform, Alignment, BASE, BoardCreationMode, CommonElementFlavour, DEFAULT_FONT_FAMILY, DEFAULT_ROUTE_MARGIN, ELEMENT_TO_TEXT_MANAGES, FOREIGN_OBJECT_IMAGE_CLASS_NAME, Generator, GroupComponent, IMAGE_CONTAINER_CLASS_NAME, IS_RESIZING, IS_ROTATING, ImageBaseComponent, ImageGenerator, MediaKeys, PICTURE_ACCEPTED_UPLOAD_SIZE, PRIMARY_COLOR, PlaitCommonElementRef, PointGraph, PointNode, PriorityQueue, PropertyTransforms, RESIZE_HANDLE_DIAMETER, ROTATE_HANDLE_DISTANCE_TO_ELEMENT, ROTATE_HANDLE_SIZE, ResizeHandle, TRANSPARENT, TextManage, WithCommonPluginKey, WithTextPluginKey, acceptImageTypes, addElementOfFocusedImage, addResizing, addRotating, alignBottom, alignHorizontalCenter, alignLeft, alignRight, alignTop, alignVerticalCenter, buildCompositionData, buildImage, buildText, calculatePolylineLength, canResize, createGraph, distributeHorizontal, distributeVertical, drawFillPrimaryHandle, drawHandle, drawPrimaryHandle, drawRotateHandle, findFirstTextEditor, generateElbowLineRoute, getCreationMode, getCrossingPointsBetweenPointAndSegment, getDirectionBetweenPointAndPoint, getDirectionByPointOfRectangle, getDirectionByVector, getDirectionFactor, getDirectionFactorByDirectionComponent, getEditingTextEditor, getElementOfFocusedImage, getElementsText, getExtendPoint, getFirstTextEditor, getFirstTextManage, getGraphPoints, getIndexByResizeHandle, getLineHeightByFontSize, getMemorizedLatest, getNextPoint, getOppositeDirection, getPointByVectorComponent, getPointByVectorDirectionComponent, getPointOnPolyline, getPoints, getRatioByPoint, getRectangleResizeHandleRefs, getResizeHandleByIndex, getResizeHandlePointByIndex, getRotatedResizeCursorClassByAngle, getSourceAndTargetOuterRectangle, getSymmetricHandleIndex, getTextEditors, getTextEditorsByElement, getTextManages, getUnitVectorByPointAndPoint, hasAfterDraw, isCornerHandle, isDelete, isDndMode, isDrawingMode, isEdgeHandle, isEnterHotkey, isExpandHotkey, isPointOnSegment, isResizing, isResizingByCondition, isRotating, isSourceAndTargetIntersect, isSpaceHotkey, isTabHotkey, isVirtualKey, measureElement, memorizeLatest, normalizeShapePoints, reduceRouteMargin, removeDuplicatePoints, removeElementOfFocusedImage, removeResizing, removeRotating, resetPointsAfterResize, rotateVector, rotateVectorAnti90, routeAdjust, selectImage, setCreationMode, setProperty, simplifyOrthogonalPoints, withGroup, withImage, withResize, withText };
2016
2143
  //# sourceMappingURL=plait-common.mjs.map