@plait/common 0.59.0 → 0.62.0-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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 +26 -0
  13. package/esm2022/image/image.generator.mjs +96 -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/plugins/with-resize.mjs +1 -5
  18. package/esm2022/public-api.mjs +5 -4
  19. package/esm2022/text/index.mjs +5 -0
  20. package/esm2022/text/text-manage.mjs +138 -0
  21. package/esm2022/text/text-measure.mjs +61 -0
  22. package/esm2022/text/types.mjs +7 -0
  23. package/esm2022/text/with-text.mjs +8 -0
  24. package/esm2022/transforms/index.mjs +1 -2
  25. package/esm2022/utils/image.mjs +3 -3
  26. package/esm2022/utils/text.mjs +22 -20
  27. package/fesm2022/plait-common.mjs +337 -218
  28. package/fesm2022/plait-common.mjs.map +1 -1
  29. package/generators/index.d.ts +1 -1
  30. package/image/image-base.component.d.ts +17 -0
  31. package/{generators → image}/image.generator.d.ts +11 -10
  32. package/image/index.d.ts +3 -0
  33. package/image/with-image.d.ts +15 -0
  34. package/package.json +1 -3
  35. package/plugins/index.d.ts +0 -1
  36. package/public-api.d.ts +4 -3
  37. package/text/index.d.ts +4 -0
  38. package/text/text-manage.d.ts +41 -0
  39. package/text/text-measure.d.ts +8 -0
  40. package/text/types.d.ts +24 -0
  41. package/text/with-text.d.ts +25 -0
  42. package/transforms/index.d.ts +0 -1
  43. package/utils/image.d.ts +1 -5
  44. package/utils/text.d.ts +9 -6
  45. package/core/image-base.component.d.ts +0 -29
  46. package/esm2022/core/image-base.component.mjs +0 -95
  47. package/esm2022/generators/image.generator.mjs +0 -59
  48. package/esm2022/plugins/text-options.mjs +0 -2
  49. package/esm2022/transforms/text.mjs +0 -71
  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,98 @@ const removeRotating = (board) => {
1280
1226
  setDragging(board, false);
1281
1227
  };
1282
1228
 
1229
+ class ImageGenerator extends Generator {
1230
+ static { this.key = 'image-generator'; }
1231
+ constructor(board, options) {
1232
+ super(board, options);
1233
+ this.board = board;
1234
+ this.options = options;
1235
+ this.isFocus = false;
1236
+ }
1237
+ canDraw(element) {
1238
+ return !!this.options.getImageItem(element);
1239
+ }
1240
+ draw(element) {
1241
+ this.element = element;
1242
+ const g = createG();
1243
+ const foreignRectangle = this.options.getRectangle(element);
1244
+ this.foreignObject = createForeignObject(foreignRectangle.x, foreignRectangle.y, foreignRectangle.width, foreignRectangle.height);
1245
+ g.append(this.foreignObject);
1246
+ const props = {
1247
+ board: this.board,
1248
+ imageItem: this.options.getImageItem(element),
1249
+ element,
1250
+ getRectangle: () => {
1251
+ return this.options.getRectangle(element);
1252
+ }
1253
+ };
1254
+ this.imageComponentRef = this.board.renderImage(this.foreignObject, props);
1255
+ this.activeGenerator = new ActiveGenerator(this.board, {
1256
+ getStrokeWidth: () => {
1257
+ const selectedElements = getSelectedElements(this.board);
1258
+ if (!(selectedElements.length === 1 && !isSelectionMoving(this.board))) {
1259
+ return ACTIVE_STROKE_WIDTH;
1260
+ }
1261
+ else {
1262
+ return ACTIVE_STROKE_WIDTH;
1263
+ }
1264
+ },
1265
+ getStrokeOpacity: () => {
1266
+ const selectedElements = getSelectedElements(this.board);
1267
+ if ((selectedElements.length === 1 && !isSelectionMoving(this.board)) || !selectedElements.length) {
1268
+ return 1;
1269
+ }
1270
+ else {
1271
+ return 0.5;
1272
+ }
1273
+ },
1274
+ getRectangle: () => {
1275
+ return this.options.getRectangle(this.element);
1276
+ },
1277
+ hasResizeHandle: () => {
1278
+ const isSelectedImageElement = canResize(this.board, this.element);
1279
+ const isSelectedImage = !!getElementOfFocusedImage(this.board);
1280
+ return isSelectedImage || isSelectedImageElement;
1281
+ }
1282
+ });
1283
+ return g;
1284
+ }
1285
+ updateImage(nodeG, previous, current) {
1286
+ this.element = current;
1287
+ if (previous !== current && this.imageComponentRef) {
1288
+ const props = {
1289
+ imageItem: this.options.getImageItem(current),
1290
+ element: current,
1291
+ getRectangle: () => {
1292
+ return this.options.getRectangle(current);
1293
+ }
1294
+ };
1295
+ this.imageComponentRef.update(props);
1296
+ }
1297
+ const currentForeignObject = this.options.getRectangle(current);
1298
+ updateForeignObject(this.g, currentForeignObject.width, currentForeignObject.height, currentForeignObject.x, currentForeignObject.y);
1299
+ if (currentForeignObject && current.angle) {
1300
+ setAngleForG(this.g, RectangleClient.getCenterPoint(currentForeignObject), current.angle);
1301
+ }
1302
+ const activeG = PlaitBoard.getElementActiveHost(this.board);
1303
+ this.activeGenerator.processDrawing(current, activeG, { selected: this.isFocus });
1304
+ }
1305
+ setFocus(element, isFocus) {
1306
+ this.isFocus = isFocus;
1307
+ const activeG = PlaitBoard.getElementActiveHost(this.board);
1308
+ this.activeGenerator.processDrawing(element, activeG, { selected: isFocus });
1309
+ const props = {
1310
+ isFocus
1311
+ };
1312
+ this.imageComponentRef.update(props);
1313
+ }
1314
+ destroy() {
1315
+ super.destroy();
1316
+ this.imageComponentRef?.destroy();
1317
+ this.activeGenerator?.destroy();
1318
+ }
1319
+ }
1320
+
1283
1321
  const setProperty = (board, properties, options) => {
1284
1322
  const selectedElements = getSelectedElements(board);
1285
1323
  selectedElements.forEach(element => {
@@ -1433,73 +1471,6 @@ const AlignTransform = {
1433
1471
  distributeVertical
1434
1472
  };
1435
1473
 
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
1474
  const normalizeShapePoints = (points, shift = false) => {
1504
1475
  let start = points[0];
1505
1476
  let end = points[1];
@@ -1547,8 +1518,6 @@ const withResize = (board, options) => {
1547
1518
  options: resizeHitTestRef.options
1548
1519
  };
1549
1520
  preventTouchMove(board, event, true);
1550
- // prevent text from being selected when user pressed shift and pointer down
1551
- event.preventDefault();
1552
1521
  return;
1553
1522
  }
1554
1523
  pointerDown(event);
@@ -1560,8 +1529,6 @@ const withResize = (board, options) => {
1560
1529
  return;
1561
1530
  }
1562
1531
  if (startPoint && resizeHitTestRef && !isResizing(board)) {
1563
- // prevent text from being selected
1564
- event.preventDefault();
1565
1532
  const endPoint = [event.x, event.y];
1566
1533
  const distance = distanceBetweenPointAndPoint(startPoint[0], startPoint[1], endPoint[0], endPoint[1]);
1567
1534
  if (distance > PRESS_AND_MOVE_BUFFER) {
@@ -1711,7 +1678,7 @@ class GroupComponent extends CommonElementFlavour {
1711
1678
  initialize() {
1712
1679
  super.initialize();
1713
1680
  this.initializeGenerator();
1714
- const contextService = PlaitBoard.getViewContainerRef(this.board).injector.get(PlaitContextService);
1681
+ const contextService = PlaitBoard.getBoardContext(this.board);
1715
1682
  this.onStableSubscription = contextService.onStable().subscribe(() => {
1716
1683
  const elementsInGroup = getElementsInGroup(this.board, this.element, false, true);
1717
1684
  const isPartialSelectGroup = elementsInGroup.some(item => isSelectedElementOrGroup(this.board, item)) &&
@@ -1919,94 +1886,246 @@ const updateSiblingElementGroupId = (board, removeGroups) => {
1919
1886
  };
1920
1887
 
1921
1888
  class ImageBaseComponent {
1889
+ constructor() {
1890
+ this.initialized = false;
1891
+ }
1922
1892
  set imageItem(value) {
1923
- this.afterImageItemChange(this._imageItem, value);
1924
1893
  this._imageItem = value;
1925
- this.drawFocus();
1894
+ if (this.initialized) {
1895
+ this.afterImageItemChange(this._imageItem, value);
1896
+ }
1926
1897
  }
1927
1898
  get imageItem() {
1928
1899
  return this._imageItem;
1929
1900
  }
1930
1901
  set isFocus(value) {
1931
1902
  this._isFocus = value;
1932
- this.drawFocus();
1933
1903
  }
1934
1904
  get isFocus() {
1935
1905
  return this._isFocus;
1936
1906
  }
1937
- get nativeElement() {
1938
- return this.elementRef.nativeElement;
1907
+ initialize() {
1908
+ this.initialized = true;
1939
1909
  }
1940
- constructor(elementRef, cdr) {
1941
- this.elementRef = elementRef;
1942
- this.cdr = cdr;
1943
- this.initialized = false;
1910
+ destroy() {
1944
1911
  }
1945
- ngOnInit() {
1946
- this.activeGenerator = new ActiveGenerator(this.board, {
1947
- getStrokeWidth: () => {
1948
- const selectedElements = getSelectedElements(this.board);
1949
- if (!(selectedElements.length === 1 && !isSelectionMoving(this.board))) {
1950
- return ACTIVE_STROKE_WIDTH;
1951
- }
1952
- else {
1953
- return ACTIVE_STROKE_WIDTH;
1954
- }
1955
- },
1956
- getStrokeOpacity: () => {
1957
- const selectedElements = getSelectedElements(this.board);
1958
- if ((selectedElements.length === 1 && !isSelectionMoving(this.board)) || !selectedElements.length) {
1959
- return 1;
1912
+ }
1913
+
1914
+ function measureElement(element, options, containerMaxWidth = 10000) {
1915
+ const canvas = document.createElement('canvas');
1916
+ const ctx = canvas.getContext('2d');
1917
+ const textEntries = Node.texts(element);
1918
+ const lines = [[]];
1919
+ for (const textEntry of textEntries) {
1920
+ const [text] = textEntry;
1921
+ const textString = Node.string(text);
1922
+ const textArray = textString.split('\n');
1923
+ textArray.forEach((segmentTextString, index) => {
1924
+ const segmentText = { ...text, text: segmentTextString };
1925
+ if (index === 0) {
1926
+ const currentLine = lines[lines.length - 1];
1927
+ currentLine.push(segmentText);
1928
+ }
1929
+ else {
1930
+ const newLine = [];
1931
+ newLine.push(segmentText);
1932
+ lines.push(newLine);
1933
+ }
1934
+ });
1935
+ }
1936
+ let width = 0;
1937
+ let height = 0;
1938
+ lines.forEach((lineTexts, index) => {
1939
+ let lineWidth = 0;
1940
+ let maxLineHeight = getLineHeightByFontSize(options.fontSize);
1941
+ lineTexts.forEach((text, index) => {
1942
+ const font = getFont(text, { fontFamily: options.fontFamily, fontSize: options.fontSize });
1943
+ ctx.font = font;
1944
+ const textMetrics = ctx.measureText(text.text);
1945
+ lineWidth += textMetrics.width;
1946
+ const isLast = index === lineTexts.length - 1;
1947
+ // skip when text is empty and is not last text of line
1948
+ if (text['font-size'] && (isLast || text.text !== '')) {
1949
+ const lineHeight = getLineHeightByFontSize(parseFloat(text['font-size']));
1950
+ if (lineHeight > maxLineHeight) {
1951
+ maxLineHeight = lineHeight;
1960
1952
  }
1961
- else {
1962
- return 0.5;
1953
+ }
1954
+ });
1955
+ if (lineWidth <= containerMaxWidth) {
1956
+ if (lineWidth > width) {
1957
+ width = lineWidth;
1958
+ }
1959
+ height += maxLineHeight;
1960
+ }
1961
+ else {
1962
+ width = containerMaxWidth;
1963
+ const lineWrapNumber = Math.ceil(lineWidth / containerMaxWidth);
1964
+ height += maxLineHeight * lineWrapNumber;
1965
+ }
1966
+ });
1967
+ return { width, height };
1968
+ }
1969
+ const getFont = (text, options) => {
1970
+ return `${text.italic ? 'italic ' : ''} ${text.bold ? 'bold ' : ''} ${text['font-size'] || options.fontSize}px ${options.fontFamily} `;
1971
+ };
1972
+
1973
+ class TextManage {
1974
+ constructor(board, options) {
1975
+ this.board = board;
1976
+ this.options = options;
1977
+ this.isEditing = false;
1978
+ this.getSize = (element) => {
1979
+ const computedStyle = window.getComputedStyle(this.foreignObject.children[0]);
1980
+ const fontFamily = computedStyle.fontFamily;
1981
+ const fontSize = parseFloat(computedStyle.fontSize);
1982
+ const target = element || this.editor.children[0];
1983
+ return measureElement(target, {
1984
+ fontSize: fontSize,
1985
+ fontFamily
1986
+ }, this.options.getMaxWidth());
1987
+ };
1988
+ this.getText = () => {
1989
+ return this.editor.children[0];
1990
+ };
1991
+ if (!this.options.getMaxWidth) {
1992
+ this.options.getMaxWidth = () => 999;
1993
+ }
1994
+ }
1995
+ draw(text) {
1996
+ const _rectangle = this.options.getRectangle();
1997
+ this.g = createG();
1998
+ this.foreignObject = createForeignObject(_rectangle.x, _rectangle.y, _rectangle.width, _rectangle.height);
1999
+ this.g.append(this.foreignObject);
2000
+ this.g.classList.add('text');
2001
+ const props = {
2002
+ board: this.board,
2003
+ text,
2004
+ textPlugins: this.options.textPlugins,
2005
+ onChange: (data) => {
2006
+ if (data.operations.some(op => !Operation.isSelectionOperation(op))) {
2007
+ const { width, height } = this.getSize();
2008
+ this.options.onChange && this.options.onChange({ ...data, width, height });
2009
+ MERGING.set(this.board, true);
1963
2010
  }
1964
2011
  },
1965
- getRectangle: () => {
1966
- return this.getRectangle();
2012
+ afterInit: (editor) => {
2013
+ this.editor = editor;
1967
2014
  },
1968
- hasResizeHandle: () => {
1969
- const isSelectedImageElement = canResize(this.board, this.element);
1970
- const isSelectedImage = !!getElementOfFocusedImage(this.board);
1971
- return isSelectedImage || isSelectedImageElement;
2015
+ onComposition: (event) => {
2016
+ const fakeRoot = buildCompositionData(this.editor, event.data);
2017
+ if (fakeRoot) {
2018
+ const sizeData = this.getSize(fakeRoot.children[0]);
2019
+ this.options.onChange && this.options.onChange(sizeData);
2020
+ MERGING.set(this.board, true);
2021
+ }
1972
2022
  }
1973
- });
1974
- this.initialized = true;
2023
+ };
2024
+ this.textComponentRef = this.board.renderText(this.foreignObject, props);
1975
2025
  }
1976
- drawFocus() {
1977
- if (this.initialized) {
1978
- const activeG = PlaitBoard.getElementActiveHost(this.board);
1979
- this.activeGenerator.processDrawing(this.element, activeG, { selected: this._isFocus });
1980
- }
2026
+ updateRectangleWidth(width) {
2027
+ updateForeignObjectWidth(this.g, width);
1981
2028
  }
1982
- ngOnDestroy() {
1983
- if (this.activeGenerator) {
1984
- this.activeGenerator.destroy();
1985
- }
2029
+ updateAngle(centerPoint, angle = 0) {
2030
+ setAngleForG(this.g, centerPoint, angle);
2031
+ }
2032
+ updateRectangle(rectangle) {
2033
+ const { x, y, width, height } = rectangle || this.options.getRectangle();
2034
+ updateForeignObject(this.g, width, height, x, y);
2035
+ }
2036
+ updateText(newText) {
2037
+ const props = {
2038
+ text: newText
2039
+ };
2040
+ this.textComponentRef.update(props);
2041
+ }
2042
+ edit(callback) {
2043
+ this.isEditing = true;
2044
+ IS_TEXT_EDITABLE.set(this.board, true);
2045
+ const props = {
2046
+ readonly: false
2047
+ };
2048
+ this.textComponentRef.update(props);
2049
+ Transforms$1.select(this.editor, [0]);
2050
+ const mousedown$ = fromEvent(document, 'mousedown').subscribe((event) => {
2051
+ const point = toViewBoxPoint(this.board, toHostPoint(this.board, event.x, event.y));
2052
+ const textRec = this.options.getRenderRectangle ? this.options.getRenderRectangle() : this.options.getRectangle();
2053
+ const clickInText = RectangleClient.isHit(RectangleClient.getRectangleByPoints([point, point]), textRec);
2054
+ const isAttached = event.target.closest('.plait-board-attached');
2055
+ if (!clickInText && !isAttached) {
2056
+ // handle composition input state, like: Chinese IME Composition Input
2057
+ timer(0).subscribe(() => {
2058
+ exitCallback();
2059
+ });
2060
+ }
2061
+ });
2062
+ const keydown$ = fromEvent(document, 'keydown').subscribe((event) => {
2063
+ if (event.isComposing) {
2064
+ return;
2065
+ }
2066
+ if (event.key === 'Escape' || (event.key === 'Enter' && !event.shiftKey) || event.key === 'Tab') {
2067
+ event.preventDefault();
2068
+ event.stopPropagation();
2069
+ exitCallback();
2070
+ return;
2071
+ }
2072
+ });
2073
+ const exitCallback = () => {
2074
+ this.updateRectangle();
2075
+ mousedown$.unsubscribe();
2076
+ keydown$.unsubscribe();
2077
+ IS_TEXT_EDITABLE.set(this.board, false);
2078
+ MERGING.set(this.board, false);
2079
+ callback && callback();
2080
+ const props = {
2081
+ readonly: true
2082
+ };
2083
+ this.textComponentRef.update(props);
2084
+ this.isEditing = false;
2085
+ };
2086
+ return exitCallback;
2087
+ }
2088
+ destroy() {
2089
+ this.g?.remove();
2090
+ this.textComponentRef?.destroy();
1986
2091
  }
1987
- 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 }); }
1988
- 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 }); }
1989
2092
  }
1990
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.2.4", ngImport: i0, type: ImageBaseComponent, decorators: [{
1991
- type: Directive,
1992
- args: [{
1993
- host: {
1994
- class: 'plait-image-container'
1995
- }
1996
- }]
1997
- }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }], propDecorators: { element: [{
1998
- type: Input
1999
- }], imageItem: [{
2000
- type: Input
2001
- }], board: [{
2002
- type: Input
2003
- }], isFocus: [{
2004
- type: Input
2005
- }], getRectangle: [{
2006
- type: Input
2007
- }], hasResizeHandle: [{
2008
- type: Input
2009
- }] } });
2093
+ const buildCompositionData = (editor, data) => {
2094
+ if (editor.selection && Range.isCollapsed(editor.selection)) {
2095
+ const [textNode, textPath] = Editor.node(editor, editor.selection);
2096
+ const offset = editor.selection.anchor.offset;
2097
+ const clonedElement = JSON.parse(JSON.stringify(editor.children[0]));
2098
+ const root = { children: [clonedElement] };
2099
+ const newTextString = textNode.text.slice(0, offset + 1) + data + textNode.text.slice(offset + 1);
2100
+ const clonedTextNode = Node.get(root, textPath);
2101
+ clonedTextNode.text = newTextString;
2102
+ return root;
2103
+ }
2104
+ return null;
2105
+ };
2106
+
2107
+ const withText = (board) => {
2108
+ const newBoard = board;
2109
+ newBoard.renderText = (container, props) => {
2110
+ throw new Error('No implementation for renderText method.');
2111
+ };
2112
+ return newBoard;
2113
+ };
2114
+
2115
+ var Alignment;
2116
+ (function (Alignment) {
2117
+ Alignment["left"] = "left";
2118
+ Alignment["center"] = "center";
2119
+ Alignment["right"] = "right";
2120
+ })(Alignment || (Alignment = {}));
2121
+
2122
+ const withImage = (board) => {
2123
+ const newBoard = board;
2124
+ newBoard.renderImage = (container, props) => {
2125
+ throw new Error('No implementation for renderImage method.');
2126
+ };
2127
+ return newBoard;
2128
+ };
2010
2129
 
2011
2130
  /*
2012
2131
  * Public API Surface of utils
@@ -2016,5 +2135,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.2.4", ngImpor
2016
2135
  * Generated bundle index. Do not edit.
2017
2136
  */
2018
2137
 
2019
- 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 };
2138
+ export { AStar, ActiveGenerator, AlignTransform, Alignment, BASE, BoardCreationMode, CommonElementFlavour, DEFAULT_FONT_FAMILY, DEFAULT_ROUTE_MARGIN, ELEMENT_TO_TEXT_MANAGES, Generator, GroupComponent, 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 };
2020
2139
  //# sourceMappingURL=plait-common.mjs.map