@plait/common 0.60.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 (50) 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/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 +337 -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/{generators → image}/image.generator.d.ts +11 -10
  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/plugins/text-options.d.ts +0 -5
  50. 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];
@@ -1707,7 +1678,7 @@ class GroupComponent extends CommonElementFlavour {
1707
1678
  initialize() {
1708
1679
  super.initialize();
1709
1680
  this.initializeGenerator();
1710
- const contextService = PlaitBoard.getViewContainerRef(this.board).injector.get(PlaitContextService);
1681
+ const contextService = PlaitBoard.getBoardContext(this.board);
1711
1682
  this.onStableSubscription = contextService.onStable().subscribe(() => {
1712
1683
  const elementsInGroup = getElementsInGroup(this.board, this.element, false, true);
1713
1684
  const isPartialSelectGroup = elementsInGroup.some(item => isSelectedElementOrGroup(this.board, item)) &&
@@ -1915,94 +1886,246 @@ const updateSiblingElementGroupId = (board, removeGroups) => {
1915
1886
  };
1916
1887
 
1917
1888
  class ImageBaseComponent {
1889
+ constructor() {
1890
+ this.initialized = false;
1891
+ }
1918
1892
  set imageItem(value) {
1919
- this.afterImageItemChange(this._imageItem, value);
1920
1893
  this._imageItem = value;
1921
- this.drawFocus();
1894
+ if (this.initialized) {
1895
+ this.afterImageItemChange(this._imageItem, value);
1896
+ }
1922
1897
  }
1923
1898
  get imageItem() {
1924
1899
  return this._imageItem;
1925
1900
  }
1926
1901
  set isFocus(value) {
1927
1902
  this._isFocus = value;
1928
- this.drawFocus();
1929
1903
  }
1930
1904
  get isFocus() {
1931
1905
  return this._isFocus;
1932
1906
  }
1933
- get nativeElement() {
1934
- return this.elementRef.nativeElement;
1907
+ initialize() {
1908
+ this.initialized = true;
1935
1909
  }
1936
- constructor(elementRef, cdr) {
1937
- this.elementRef = elementRef;
1938
- this.cdr = cdr;
1939
- this.initialized = false;
1910
+ destroy() {
1940
1911
  }
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;
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;
1956
1952
  }
1957
- else {
1958
- 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);
1959
2010
  }
1960
2011
  },
1961
- getRectangle: () => {
1962
- return this.getRectangle();
2012
+ afterInit: (editor) => {
2013
+ this.editor = editor;
1963
2014
  },
1964
- hasResizeHandle: () => {
1965
- const isSelectedImageElement = canResize(this.board, this.element);
1966
- const isSelectedImage = !!getElementOfFocusedImage(this.board);
1967
- 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
+ }
1968
2022
  }
1969
- });
1970
- this.initialized = true;
2023
+ };
2024
+ this.textComponentRef = this.board.renderText(this.foreignObject, props);
1971
2025
  }
1972
- drawFocus() {
1973
- if (this.initialized) {
1974
- const activeG = PlaitBoard.getElementActiveHost(this.board);
1975
- this.activeGenerator.processDrawing(this.element, activeG, { selected: this._isFocus });
1976
- }
2026
+ updateRectangleWidth(width) {
2027
+ updateForeignObjectWidth(this.g, width);
1977
2028
  }
1978
- ngOnDestroy() {
1979
- if (this.activeGenerator) {
1980
- this.activeGenerator.destroy();
1981
- }
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();
1982
2091
  }
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
2092
  }
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
- }] } });
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
+ };
2006
2129
 
2007
2130
  /*
2008
2131
  * Public API Surface of utils
@@ -2012,5 +2135,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.2.4", ngImpor
2012
2135
  * Generated bundle index. Do not edit.
2013
2136
  */
2014
2137
 
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 };
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 };
2016
2139
  //# sourceMappingURL=plait-common.mjs.map