@excalidraw/excalidraw 0.17.1-7500-ac247a0 → 0.17.1-b7babe5
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.
- package/CHANGELOG.md +56 -2
- package/dist/browser/dev/excalidraw-assets-dev/{chunk-2W5GQUR4.js → chunk-6NMK7JTV.js} +13 -6
- package/dist/browser/dev/excalidraw-assets-dev/chunk-6NMK7JTV.js.map +7 -0
- package/dist/browser/dev/excalidraw-assets-dev/chunk-CX3RATXT.js +20324 -0
- package/dist/browser/dev/excalidraw-assets-dev/chunk-CX3RATXT.js.map +7 -0
- package/dist/browser/dev/excalidraw-assets-dev/{en-OC6JWP3X.js → en-BZY7JRTM.js} +4 -2
- package/dist/browser/dev/excalidraw-assets-dev/{image-5TVMINCA.js → image-CVN3YKRW.js} +2 -4
- package/dist/browser/dev/excalidraw-assets-dev/image-LK4UNFRZ.css +6 -0
- package/dist/browser/dev/excalidraw-assets-dev/image-LK4UNFRZ.css.map +7 -0
- package/dist/browser/dev/excalidraw-assets-dev/roundRect-T5BX56ZF.js +161 -0
- package/dist/browser/dev/excalidraw-assets-dev/roundRect-T5BX56ZF.js.map +7 -0
- package/dist/browser/dev/index.css +189 -129
- package/dist/browser/dev/index.css.map +3 -3
- package/dist/browser/dev/index.js +34964 -37
- package/dist/browser/dev/index.js.map +4 -4
- package/dist/browser/prod/excalidraw-assets/chunk-VJAIK3AX.js +55 -0
- package/dist/browser/prod/excalidraw-assets/chunk-YYO5DFUW.js +11 -0
- package/dist/browser/prod/excalidraw-assets/en-O2YCQM2W.js +1 -0
- package/dist/browser/prod/excalidraw-assets/image-6FKY54X5.js +1 -0
- package/dist/browser/prod/excalidraw-assets/image-X66R2EM5.css +1 -0
- package/dist/browser/prod/excalidraw-assets/roundRect-2ACQK4DA.js +1 -0
- package/dist/browser/prod/index.css +1 -1
- package/dist/browser/prod/index.js +203 -1
- package/dist/{prod/en-RLIAOBCI.json → dev/en-EY7E2L5O.json} +10 -5
- package/dist/dev/index.css +189 -129
- package/dist/dev/index.css.map +3 -3
- package/dist/dev/index.js +38702 -39409
- package/dist/dev/index.js.map +4 -4
- package/dist/excalidraw/actions/actionAddToLibrary.d.ts +15 -15
- package/dist/excalidraw/actions/actionAlign.d.ts +6 -6
- package/dist/excalidraw/actions/actionAlign.js +2 -1
- package/dist/excalidraw/actions/actionBoundText.d.ts +10 -10
- package/dist/excalidraw/actions/actionBoundText.js +8 -8
- package/dist/excalidraw/actions/actionCanvas.d.ts +58 -58
- package/dist/excalidraw/actions/actionClipboard.d.ts +34 -34
- package/dist/excalidraw/actions/actionClipboard.js +9 -2
- package/dist/excalidraw/actions/actionDeleteSelected.d.ts +15 -15
- package/dist/excalidraw/actions/actionDeleteSelected.js +3 -2
- package/dist/excalidraw/actions/actionDistribute.d.ts +2 -2
- package/dist/excalidraw/actions/actionDistribute.js +1 -1
- package/dist/excalidraw/actions/actionDuplicateSelection.d.ts +1 -1
- package/dist/excalidraw/actions/actionDuplicateSelection.js +4 -3
- package/dist/excalidraw/actions/actionElementLock.d.ts +10 -10
- package/dist/excalidraw/actions/actionExport.d.ts +43 -43
- package/dist/excalidraw/actions/actionExport.js +4 -4
- package/dist/excalidraw/actions/actionFinalize.d.ts +9 -9
- package/dist/excalidraw/actions/actionFinalize.js +7 -6
- package/dist/excalidraw/actions/actionFlip.d.ts +2 -2
- package/dist/excalidraw/actions/actionFlip.js +11 -11
- package/dist/excalidraw/actions/actionFrame.d.ts +16 -16
- package/dist/excalidraw/actions/actionFrame.js +1 -1
- package/dist/excalidraw/actions/actionGroup.d.ts +10 -10
- package/dist/excalidraw/actions/actionGroup.js +3 -2
- package/dist/excalidraw/actions/actionLinearEditor.d.ts +5 -5
- package/dist/excalidraw/actions/actionLinearEditor.js +1 -1
- package/dist/excalidraw/{element/Hyperlink.d.ts → actions/actionLink.d.ts} +29 -51
- package/dist/excalidraw/actions/actionLink.js +40 -0
- package/dist/excalidraw/actions/actionMenu.d.ts +13 -13
- package/dist/excalidraw/actions/actionNavigate.d.ts +10 -10
- package/dist/excalidraw/actions/actionNavigate.js +1 -1
- package/dist/excalidraw/actions/actionProperties.d.ts +77 -77
- package/dist/excalidraw/actions/actionProperties.js +32 -27
- package/dist/excalidraw/actions/actionSelectAll.d.ts +5 -5
- package/dist/excalidraw/actions/actionSelectAll.js +1 -1
- package/dist/excalidraw/actions/actionStyles.d.ts +7 -7
- package/dist/excalidraw/actions/actionStyles.js +4 -4
- package/dist/excalidraw/actions/actionToggleGridMode.d.ts +5 -5
- package/dist/excalidraw/actions/actionToggleObjectsSnapMode.d.ts +5 -5
- package/dist/excalidraw/actions/actionToggleStats.d.ts +5 -5
- package/dist/excalidraw/actions/actionToggleViewMode.d.ts +5 -5
- package/dist/excalidraw/actions/actionToggleZenMode.d.ts +5 -5
- package/dist/excalidraw/actions/index.d.ts +1 -1
- package/dist/excalidraw/actions/index.js +1 -1
- package/dist/excalidraw/actions/manager.js +2 -1
- package/dist/excalidraw/align.d.ts +2 -2
- package/dist/excalidraw/align.js +2 -2
- package/dist/excalidraw/animated-trail.d.ts +33 -0
- package/dist/excalidraw/animated-trail.js +96 -0
- package/dist/excalidraw/animation-frame-handler.d.ts +16 -0
- package/dist/excalidraw/animation-frame-handler.js +55 -0
- package/dist/excalidraw/appState.d.ts +1 -1
- package/dist/excalidraw/appState.js +1 -3
- package/dist/excalidraw/clipboard.js +5 -5
- package/dist/excalidraw/components/Actions.d.ts +3 -3
- package/dist/excalidraw/components/Actions.js +18 -7
- package/dist/excalidraw/components/App.d.ts +23 -16
- package/dist/excalidraw/components/App.js +387 -272
- package/dist/excalidraw/components/Button.d.ts +1 -1
- package/dist/excalidraw/components/FilledButton.d.ts +2 -2
- package/dist/excalidraw/components/FilledButton.js +27 -3
- package/dist/excalidraw/components/FollowMode/FollowMode.js +1 -1
- package/dist/excalidraw/components/ImageExportDialog.d.ts +2 -1
- package/dist/excalidraw/components/ImageExportDialog.js +17 -13
- package/dist/excalidraw/components/JSONExportDialog.js +1 -1
- package/dist/excalidraw/components/{LaserTool/LaserPointerButton.d.ts → LaserPointerButton.d.ts} +1 -1
- package/dist/excalidraw/components/{LaserTool/LaserPointerButton.js → LaserPointerButton.js} +2 -2
- package/dist/excalidraw/components/LayerUI.js +3 -3
- package/dist/excalidraw/components/MobileMenu.js +1 -1
- package/dist/excalidraw/components/ProjectName.d.ts +0 -1
- package/dist/excalidraw/components/ProjectName.js +1 -1
- package/dist/excalidraw/components/PublishLibrary.js +1 -1
- package/dist/excalidraw/components/SVGLayer.d.ts +8 -0
- package/dist/excalidraw/components/SVGLayer.js +20 -0
- package/dist/excalidraw/components/ShareableLinkDialog.js +10 -10
- package/dist/excalidraw/components/Sidebar/Sidebar.d.ts +1 -1
- package/dist/excalidraw/components/Stack.d.ts +2 -2
- package/dist/excalidraw/components/TTDDialog/common.js +10 -1
- package/dist/excalidraw/components/TextField.d.ts +5 -2
- package/dist/excalidraw/components/TextField.js +6 -3
- package/dist/excalidraw/components/Toast.d.ts +3 -2
- package/dist/excalidraw/components/Toast.js +2 -2
- package/dist/excalidraw/components/ToolButton.js +2 -1
- package/dist/excalidraw/components/canvases/InteractiveCanvas.d.ts +2 -2
- package/dist/excalidraw/components/canvases/InteractiveCanvas.js +6 -5
- package/dist/excalidraw/components/canvases/StaticCanvas.d.ts +4 -3
- package/dist/excalidraw/components/canvases/StaticCanvas.js +7 -5
- package/dist/excalidraw/components/dropdownMenu/DropdownMenuContent.js +22 -2
- package/dist/excalidraw/components/hyperlink/Hyperlink.d.ts +19 -0
- package/dist/excalidraw/{element → components/hyperlink}/Hyperlink.js +40 -115
- package/dist/excalidraw/components/hyperlink/helpers.d.ts +7 -0
- package/dist/excalidraw/components/hyperlink/helpers.js +49 -0
- package/dist/excalidraw/components/icons.d.ts +2 -1
- package/dist/excalidraw/components/icons.js +2 -1
- package/dist/excalidraw/components/live-collaboration/LiveCollaborationTrigger.js +3 -2
- package/dist/excalidraw/components/main-menu/DefaultItems.js +5 -2
- package/dist/excalidraw/constants.d.ts +6 -0
- package/dist/excalidraw/constants.js +6 -0
- package/dist/excalidraw/data/blob.js +13 -14
- package/dist/excalidraw/data/filesystem.d.ts +1 -1
- package/dist/excalidraw/data/index.d.ts +2 -1
- package/dist/excalidraw/data/index.js +20 -16
- package/dist/excalidraw/data/json.d.ts +1 -1
- package/dist/excalidraw/data/json.js +5 -3
- package/dist/excalidraw/data/library.d.ts +60 -8
- package/dist/excalidraw/data/library.js +302 -33
- package/dist/excalidraw/data/resave.d.ts +1 -1
- package/dist/excalidraw/data/resave.js +2 -2
- package/dist/excalidraw/data/restore.js +8 -13
- package/dist/excalidraw/data/transform.js +13 -9
- package/dist/excalidraw/distribute.d.ts +2 -2
- package/dist/excalidraw/distribute.js +2 -2
- package/dist/excalidraw/element/ElementCanvasButtons.d.ts +3 -2
- package/dist/excalidraw/element/ElementCanvasButtons.js +4 -4
- package/dist/excalidraw/element/binding.d.ts +9 -9
- package/dist/excalidraw/element/binding.js +61 -59
- package/dist/excalidraw/element/bounds.d.ts +5 -5
- package/dist/excalidraw/element/bounds.js +29 -32
- package/dist/excalidraw/element/collision.d.ts +11 -11
- package/dist/excalidraw/element/collision.js +49 -46
- package/dist/excalidraw/element/containerCache.d.ts +11 -0
- package/dist/excalidraw/element/containerCache.js +14 -0
- package/dist/excalidraw/element/dragElements.js +10 -19
- package/dist/excalidraw/element/embeddable.d.ts +12 -13
- package/dist/excalidraw/element/embeddable.js +17 -27
- package/dist/excalidraw/element/image.js +1 -2
- package/dist/excalidraw/element/index.d.ts +8 -1
- package/dist/excalidraw/element/index.js +23 -1
- package/dist/excalidraw/element/linearElementEditor.d.ts +36 -36
- package/dist/excalidraw/element/linearElementEditor.js +79 -80
- package/dist/excalidraw/element/newElement.d.ts +4 -6
- package/dist/excalidraw/element/newElement.js +11 -16
- package/dist/excalidraw/element/resizeElements.d.ts +6 -6
- package/dist/excalidraw/element/resizeElements.js +40 -46
- package/dist/excalidraw/element/resizeTest.d.ts +3 -3
- package/dist/excalidraw/element/resizeTest.js +4 -4
- package/dist/excalidraw/element/sizeHelpers.d.ts +2 -2
- package/dist/excalidraw/element/sizeHelpers.js +2 -2
- package/dist/excalidraw/element/textElement.d.ts +34 -21
- package/dist/excalidraw/element/textElement.js +87 -111
- package/dist/excalidraw/element/textWysiwyg.d.ts +1 -6
- package/dist/excalidraw/element/textWysiwyg.js +15 -37
- package/dist/excalidraw/element/transformHandles.d.ts +4 -4
- package/dist/excalidraw/element/transformHandles.js +6 -6
- package/dist/excalidraw/element/typeChecks.js +4 -1
- package/dist/excalidraw/element/types.d.ts +24 -11
- package/dist/excalidraw/frame.d.ts +26 -20
- package/dist/excalidraw/frame.js +157 -84
- package/dist/excalidraw/groups.d.ts +3 -3
- package/dist/excalidraw/groups.js +11 -3
- package/dist/excalidraw/history.d.ts +1 -1
- package/dist/excalidraw/hooks/useLibraryItemSvg.js +1 -1
- package/dist/excalidraw/index.d.ts +9 -10
- package/dist/excalidraw/index.js +16 -12
- package/dist/excalidraw/laser-trails.d.ts +19 -0
- package/dist/excalidraw/laser-trails.js +95 -0
- package/dist/excalidraw/locales/en.json +10 -5
- package/dist/excalidraw/queue.d.ts +9 -0
- package/dist/excalidraw/queue.js +27 -0
- package/dist/excalidraw/reactUtils.d.ts +14 -0
- package/dist/excalidraw/reactUtils.js +45 -0
- package/dist/excalidraw/renderer/helpers.d.ts +13 -0
- package/dist/excalidraw/renderer/helpers.js +39 -0
- package/dist/excalidraw/renderer/interactiveScene.d.ts +20 -0
- package/dist/excalidraw/renderer/{renderScene.js → interactiveScene.js} +199 -474
- package/dist/excalidraw/renderer/renderElement.d.ts +6 -6
- package/dist/excalidraw/renderer/renderElement.js +54 -366
- package/dist/excalidraw/renderer/staticScene.d.ts +11 -0
- package/dist/excalidraw/renderer/staticScene.js +205 -0
- package/dist/excalidraw/renderer/staticSvgScene.d.ts +5 -0
- package/dist/excalidraw/renderer/staticSvgScene.js +385 -0
- package/dist/excalidraw/scene/Fonts.js +2 -1
- package/dist/excalidraw/scene/Renderer.d.ts +1 -1
- package/dist/excalidraw/scene/Renderer.js +32 -20
- package/dist/excalidraw/scene/Scene.d.ts +10 -9
- package/dist/excalidraw/scene/Scene.js +45 -21
- package/dist/excalidraw/scene/Shape.d.ts +3 -1
- package/dist/excalidraw/scene/Shape.js +7 -5
- package/dist/excalidraw/scene/ShapeCache.d.ts +2 -1
- package/dist/excalidraw/scene/ShapeCache.js +1 -0
- package/dist/excalidraw/scene/comparisons.js +2 -1
- package/dist/excalidraw/scene/export.d.ts +3 -0
- package/dist/excalidraw/scene/export.js +20 -40
- package/dist/excalidraw/scene/index.d.ts +0 -1
- package/dist/excalidraw/scene/index.js +0 -1
- package/dist/excalidraw/scene/scrollbars.d.ts +1 -1
- package/dist/excalidraw/scene/scrollbars.js +1 -1
- package/dist/excalidraw/scene/selection.d.ts +5 -5
- package/dist/excalidraw/scene/selection.js +16 -14
- package/dist/excalidraw/scene/types.d.ts +11 -5
- package/dist/excalidraw/snapping.d.ts +7 -7
- package/dist/excalidraw/snapping.js +21 -20
- package/dist/excalidraw/types.d.ts +16 -17
- package/dist/excalidraw/utility-types.d.ts +7 -0
- package/dist/excalidraw/utils.d.ts +21 -16
- package/dist/excalidraw/utils.js +43 -45
- package/dist/{dev/en-RLIAOBCI.json → prod/en-EY7E2L5O.json} +10 -5
- package/dist/prod/index.css +1 -1
- package/dist/prod/index.js +42 -42
- package/dist/utils/bbox.d.ts +2 -2
- package/dist/utils/export.d.ts +3 -3
- package/dist/utils/export.js +3 -13
- package/dist/utils/index.d.ts +2 -2
- package/dist/utils/index.js +2 -2
- package/dist/utils/withinBounds.d.ts +1 -1
- package/dist/utils/withinBounds.js +5 -2
- package/package.json +4 -4
- package/dist/browser/dev/excalidraw-assets-dev/chunk-2W5GQUR4.js.map +0 -7
- package/dist/browser/dev/excalidraw-assets-dev/chunk-KGZXLFLR.js +0 -53497
- package/dist/browser/dev/excalidraw-assets-dev/chunk-KGZXLFLR.js.map +0 -7
- package/dist/browser/dev/excalidraw-assets-dev/image-3MFRCKYM.css +0 -5797
- package/dist/browser/dev/excalidraw-assets-dev/image-3MFRCKYM.css.map +0 -7
- package/dist/browser/prod/excalidraw-assets/chunk-4YN2HN3S.js +0 -257
- package/dist/browser/prod/excalidraw-assets/chunk-OWLL6VOG.js +0 -11
- package/dist/browser/prod/excalidraw-assets/en-ERQOR3OC.js +0 -1
- package/dist/browser/prod/excalidraw-assets/image-LTLHTTSE.js +0 -1
- package/dist/browser/prod/excalidraw-assets/image-QBL334OA.css +0 -1
- package/dist/excalidraw/components/LaserTool/LaserPathManager.d.ts +0 -28
- package/dist/excalidraw/components/LaserTool/LaserPathManager.js +0 -225
- package/dist/excalidraw/components/LaserTool/LaserTool.d.ts +0 -8
- package/dist/excalidraw/components/LaserTool/LaserTool.js +0 -15
- package/dist/excalidraw/renderer/renderScene.d.ts +0 -25
- package/dist/excalidraw/vite.config.d.mts +0 -2
- package/dist/excalidraw/vite.config.mjs +0 -13
- /package/dist/browser/dev/excalidraw-assets-dev/{en-OC6JWP3X.js.map → en-BZY7JRTM.js.map} +0 -0
- /package/dist/browser/dev/excalidraw-assets-dev/{image-5TVMINCA.js.map → image-CVN3YKRW.js.map} +0 -0
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { getFontString, arrayToMap, isTestEnv } from "../utils";
|
|
1
|
+
import { getFontString, arrayToMap, isTestEnv, normalizeEOL } from "../utils";
|
|
2
2
|
import { mutateElement } from "./mutateElement";
|
|
3
|
-
import { ARROW_LABEL_FONT_SIZE_TO_MIN_WIDTH_RATIO, ARROW_LABEL_WIDTH_FRACTION, BOUND_TEXT_PADDING, DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE, FONT_FAMILY,
|
|
4
|
-
import Scene from "../scene/Scene";
|
|
3
|
+
import { ARROW_LABEL_FONT_SIZE_TO_MIN_WIDTH_RATIO, ARROW_LABEL_WIDTH_FRACTION, BOUND_TEXT_PADDING, DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE, FONT_FAMILY, TEXT_ALIGN, VERTICAL_ALIGN, } from "../constants";
|
|
5
4
|
import { isTextElement } from ".";
|
|
6
5
|
import { isBoundToContainer, isArrowElement } from "./typeChecks";
|
|
7
6
|
import { LinearElementEditor } from "./linearElementEditor";
|
|
@@ -9,18 +8,16 @@ import { isTextBindableContainer } from "./typeChecks";
|
|
|
9
8
|
import { getElementAbsoluteCoords } from ".";
|
|
10
9
|
import { getSelectedElements } from "../scene";
|
|
11
10
|
import { isHittingElementNotConsideringBoundingBox } from "./collision";
|
|
12
|
-
import { resetOriginalContainerCache, updateOriginalContainerCache, } from "./
|
|
11
|
+
import { resetOriginalContainerCache, updateOriginalContainerCache, } from "./containerCache";
|
|
13
12
|
export const normalizeText = (text) => {
|
|
14
|
-
return (text
|
|
13
|
+
return (normalizeEOL(text)
|
|
15
14
|
// replace tabs with spaces so they render and measure correctly
|
|
16
|
-
.replace(/\t/g, " ")
|
|
17
|
-
// normalize newlines
|
|
18
|
-
.replace(/\r?\n|\r/g, "\n"));
|
|
15
|
+
.replace(/\t/g, " "));
|
|
19
16
|
};
|
|
20
|
-
|
|
17
|
+
const splitIntoLines = (text) => {
|
|
21
18
|
return normalizeText(text).split("\n");
|
|
22
19
|
};
|
|
23
|
-
export const redrawTextBoundingBox = (textElement, container) => {
|
|
20
|
+
export const redrawTextBoundingBox = (textElement, container, elementsMap) => {
|
|
24
21
|
let maxWidth = undefined;
|
|
25
22
|
const boundTextUpdates = {
|
|
26
23
|
x: textElement.x,
|
|
@@ -28,7 +25,6 @@ export const redrawTextBoundingBox = (textElement, container) => {
|
|
|
28
25
|
text: textElement.text,
|
|
29
26
|
width: textElement.width,
|
|
30
27
|
height: textElement.height,
|
|
31
|
-
baseline: textElement.baseline,
|
|
32
28
|
};
|
|
33
29
|
boundTextUpdates.text = textElement.text;
|
|
34
30
|
if (container) {
|
|
@@ -38,10 +34,9 @@ export const redrawTextBoundingBox = (textElement, container) => {
|
|
|
38
34
|
const metrics = measureText(boundTextUpdates.text, getFontString(textElement), textElement.lineHeight);
|
|
39
35
|
boundTextUpdates.width = metrics.width;
|
|
40
36
|
boundTextUpdates.height = metrics.height;
|
|
41
|
-
boundTextUpdates.baseline = metrics.baseline;
|
|
42
37
|
if (container) {
|
|
43
38
|
const maxContainerHeight = getBoundTextMaxHeight(container, textElement);
|
|
44
|
-
const maxContainerWidth = getBoundTextMaxWidth(container);
|
|
39
|
+
const maxContainerWidth = getBoundTextMaxWidth(container, textElement);
|
|
45
40
|
if (!isArrowElement(container) && metrics.height > maxContainerHeight) {
|
|
46
41
|
const nextHeight = computeContainerDimensionForBoundText(metrics.height, container.type);
|
|
47
42
|
mutateElement(container, { height: nextHeight });
|
|
@@ -55,21 +50,21 @@ export const redrawTextBoundingBox = (textElement, container) => {
|
|
|
55
50
|
...textElement,
|
|
56
51
|
...boundTextUpdates,
|
|
57
52
|
};
|
|
58
|
-
const { x, y } = computeBoundTextPosition(container, updatedTextElement);
|
|
53
|
+
const { x, y } = computeBoundTextPosition(container, updatedTextElement, elementsMap);
|
|
59
54
|
boundTextUpdates.x = x;
|
|
60
55
|
boundTextUpdates.y = y;
|
|
61
56
|
}
|
|
62
57
|
mutateElement(textElement, boundTextUpdates);
|
|
63
58
|
};
|
|
64
|
-
export const bindTextToShapeAfterDuplication = (
|
|
65
|
-
const
|
|
59
|
+
export const bindTextToShapeAfterDuplication = (newElements, oldElements, oldIdToDuplicatedId) => {
|
|
60
|
+
const newElementsMap = arrayToMap(newElements);
|
|
66
61
|
oldElements.forEach((element) => {
|
|
67
62
|
const newElementId = oldIdToDuplicatedId.get(element.id);
|
|
68
63
|
const boundTextElementId = getBoundTextElementId(element);
|
|
69
64
|
if (boundTextElementId) {
|
|
70
65
|
const newTextElementId = oldIdToDuplicatedId.get(boundTextElementId);
|
|
71
66
|
if (newTextElementId) {
|
|
72
|
-
const newContainer =
|
|
67
|
+
const newContainer = newElementsMap.get(newElementId);
|
|
73
68
|
if (newContainer) {
|
|
74
69
|
mutateElement(newContainer, {
|
|
75
70
|
boundElements: (element.boundElements || [])
|
|
@@ -81,7 +76,7 @@ export const bindTextToShapeAfterDuplication = (sceneElements, oldElements, oldI
|
|
|
81
76
|
}),
|
|
82
77
|
});
|
|
83
78
|
}
|
|
84
|
-
const newTextElement =
|
|
79
|
+
const newTextElement = newElementsMap.get(newTextElementId);
|
|
85
80
|
if (newTextElement && isTextElement(newTextElement)) {
|
|
86
81
|
mutateElement(newTextElement, {
|
|
87
82
|
containerId: newContainer ? newElementId : null,
|
|
@@ -91,25 +86,23 @@ export const bindTextToShapeAfterDuplication = (sceneElements, oldElements, oldI
|
|
|
91
86
|
}
|
|
92
87
|
});
|
|
93
88
|
};
|
|
94
|
-
export const handleBindTextResize = (container, transformHandleType, shouldMaintainAspectRatio = false) => {
|
|
89
|
+
export const handleBindTextResize = (container, elementsMap, transformHandleType, shouldMaintainAspectRatio = false) => {
|
|
95
90
|
const boundTextElementId = getBoundTextElementId(container);
|
|
96
91
|
if (!boundTextElementId) {
|
|
97
92
|
return;
|
|
98
93
|
}
|
|
99
94
|
resetOriginalContainerCache(container.id);
|
|
100
|
-
|
|
95
|
+
const textElement = getBoundTextElement(container, elementsMap);
|
|
101
96
|
if (textElement && textElement.text) {
|
|
102
97
|
if (!container) {
|
|
103
98
|
return;
|
|
104
99
|
}
|
|
105
|
-
textElement = Scene.getScene(container).getElement(boundTextElementId);
|
|
106
100
|
let text = textElement.text;
|
|
107
101
|
let nextHeight = textElement.height;
|
|
108
102
|
let nextWidth = textElement.width;
|
|
109
|
-
const maxWidth = getBoundTextMaxWidth(container);
|
|
103
|
+
const maxWidth = getBoundTextMaxWidth(container, textElement);
|
|
110
104
|
const maxHeight = getBoundTextMaxHeight(container, textElement);
|
|
111
105
|
let containerHeight = container.height;
|
|
112
|
-
let nextBaseLine = textElement.baseline;
|
|
113
106
|
if (shouldMaintainAspectRatio ||
|
|
114
107
|
(transformHandleType !== "n" && transformHandleType !== "s")) {
|
|
115
108
|
if (text) {
|
|
@@ -118,7 +111,6 @@ export const handleBindTextResize = (container, transformHandleType, shouldMaint
|
|
|
118
111
|
const metrics = measureText(text, getFontString(textElement), textElement.lineHeight);
|
|
119
112
|
nextHeight = metrics.height;
|
|
120
113
|
nextWidth = metrics.width;
|
|
121
|
-
nextBaseLine = metrics.baseline;
|
|
122
114
|
}
|
|
123
115
|
// increase height in case text element height exceeds
|
|
124
116
|
if (nextHeight > maxHeight) {
|
|
@@ -140,20 +132,19 @@ export const handleBindTextResize = (container, transformHandleType, shouldMaint
|
|
|
140
132
|
text,
|
|
141
133
|
width: nextWidth,
|
|
142
134
|
height: nextHeight,
|
|
143
|
-
baseline: nextBaseLine,
|
|
144
135
|
});
|
|
145
136
|
if (!isArrowElement(container)) {
|
|
146
|
-
mutateElement(textElement, computeBoundTextPosition(container, textElement));
|
|
137
|
+
mutateElement(textElement, computeBoundTextPosition(container, textElement, elementsMap));
|
|
147
138
|
}
|
|
148
139
|
}
|
|
149
140
|
};
|
|
150
|
-
export const computeBoundTextPosition = (container, boundTextElement) => {
|
|
141
|
+
export const computeBoundTextPosition = (container, boundTextElement, elementsMap) => {
|
|
151
142
|
if (isArrowElement(container)) {
|
|
152
|
-
return LinearElementEditor.getBoundTextElementPosition(container, boundTextElement);
|
|
143
|
+
return LinearElementEditor.getBoundTextElementPosition(container, boundTextElement, elementsMap);
|
|
153
144
|
}
|
|
154
145
|
const containerCoords = getContainerCoords(container);
|
|
155
146
|
const maxContainerHeight = getBoundTextMaxHeight(container, boundTextElement);
|
|
156
|
-
const maxContainerWidth = getBoundTextMaxWidth(container);
|
|
147
|
+
const maxContainerWidth = getBoundTextMaxWidth(container, boundTextElement);
|
|
157
148
|
let x;
|
|
158
149
|
let y;
|
|
159
150
|
if (boundTextElement.verticalAlign === VERTICAL_ALIGN.TOP) {
|
|
@@ -179,7 +170,6 @@ export const computeBoundTextPosition = (container, boundTextElement) => {
|
|
|
179
170
|
}
|
|
180
171
|
return { x, y };
|
|
181
172
|
};
|
|
182
|
-
// https://github.com/grassator/canvas-text-editor/blob/master/lib/FontMetrics.js
|
|
183
173
|
export const measureText = (text, font, lineHeight) => {
|
|
184
174
|
text = text
|
|
185
175
|
.split("\n")
|
|
@@ -190,47 +180,7 @@ export const measureText = (text, font, lineHeight) => {
|
|
|
190
180
|
const fontSize = parseFloat(font);
|
|
191
181
|
const height = getTextHeight(text, fontSize, lineHeight);
|
|
192
182
|
const width = getTextWidth(text, font);
|
|
193
|
-
|
|
194
|
-
return { width, height, baseline };
|
|
195
|
-
};
|
|
196
|
-
export const measureBaseline = (text, font, lineHeight, wrapInContainer) => {
|
|
197
|
-
const container = document.createElement("div");
|
|
198
|
-
container.style.position = "absolute";
|
|
199
|
-
container.style.whiteSpace = "pre";
|
|
200
|
-
container.style.font = font;
|
|
201
|
-
container.style.minHeight = "1em";
|
|
202
|
-
if (wrapInContainer) {
|
|
203
|
-
container.style.overflow = "hidden";
|
|
204
|
-
container.style.wordBreak = "break-word";
|
|
205
|
-
container.style.whiteSpace = "pre-wrap";
|
|
206
|
-
}
|
|
207
|
-
container.style.lineHeight = String(lineHeight);
|
|
208
|
-
container.innerText = text;
|
|
209
|
-
// Baseline is important for positioning text on canvas
|
|
210
|
-
document.body.appendChild(container);
|
|
211
|
-
const span = document.createElement("span");
|
|
212
|
-
span.style.display = "inline-block";
|
|
213
|
-
span.style.overflow = "hidden";
|
|
214
|
-
span.style.width = "1px";
|
|
215
|
-
span.style.height = "1px";
|
|
216
|
-
container.appendChild(span);
|
|
217
|
-
let baseline = span.offsetTop + span.offsetHeight;
|
|
218
|
-
const height = container.offsetHeight;
|
|
219
|
-
if (isSafari) {
|
|
220
|
-
const canvasHeight = getTextHeight(text, parseFloat(font), lineHeight);
|
|
221
|
-
const fontSize = parseFloat(font);
|
|
222
|
-
// In Safari the font size gets rounded off when rendering hence calculating the safari height and shifting the baseline if it differs
|
|
223
|
-
// from the actual canvas height
|
|
224
|
-
const domHeight = getTextHeight(text, Math.round(fontSize), lineHeight);
|
|
225
|
-
if (canvasHeight > height) {
|
|
226
|
-
baseline += canvasHeight - domHeight;
|
|
227
|
-
}
|
|
228
|
-
if (height > canvasHeight) {
|
|
229
|
-
baseline -= domHeight - canvasHeight;
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
document.body.removeChild(container);
|
|
233
|
-
return baseline;
|
|
183
|
+
return { width, height };
|
|
234
184
|
};
|
|
235
185
|
/**
|
|
236
186
|
* To get unitless line-height (if unknown) we can calculate it by dividing
|
|
@@ -249,6 +199,16 @@ export const detectLineHeight = (textElement) => {
|
|
|
249
199
|
export const getLineHeightInPx = (fontSize, lineHeight) => {
|
|
250
200
|
return fontSize * lineHeight;
|
|
251
201
|
};
|
|
202
|
+
/**
|
|
203
|
+
* Calculates vertical offset for a text with alphabetic baseline.
|
|
204
|
+
*/
|
|
205
|
+
export const getVerticalOffset = (fontFamily, fontSize, lineHeightPx) => {
|
|
206
|
+
const { unitsPerEm, ascender, descender } = FONT_METRICS[fontFamily] || FONT_METRICS[FONT_FAMILY.Helvetica];
|
|
207
|
+
const fontSizeEm = fontSize / unitsPerEm;
|
|
208
|
+
const lineGap = lineHeightPx - fontSizeEm * ascender + fontSizeEm * descender;
|
|
209
|
+
const verticalOffset = fontSizeEm * ascender + lineGap;
|
|
210
|
+
return verticalOffset;
|
|
211
|
+
};
|
|
252
212
|
// FIXME rename to getApproxMinContainerHeight
|
|
253
213
|
export const getApproxMinLineHeight = (fontSize, lineHeight) => {
|
|
254
214
|
return getLineHeightInPx(fontSize, lineHeight) + BOUND_TEXT_PADDING * 2;
|
|
@@ -486,42 +446,44 @@ export const getBoundTextElementId = (container) => {
|
|
|
486
446
|
null
|
|
487
447
|
: null;
|
|
488
448
|
};
|
|
489
|
-
export const getBoundTextElement = (element) => {
|
|
449
|
+
export const getBoundTextElement = (element, elementsMap) => {
|
|
490
450
|
if (!element) {
|
|
491
451
|
return null;
|
|
492
452
|
}
|
|
493
453
|
const boundTextElementId = getBoundTextElementId(element);
|
|
494
454
|
if (boundTextElementId) {
|
|
495
|
-
return (
|
|
455
|
+
return (elementsMap.get(boundTextElementId) ||
|
|
456
|
+
null);
|
|
496
457
|
}
|
|
497
458
|
return null;
|
|
498
459
|
};
|
|
499
|
-
export const getContainerElement = (element) => {
|
|
460
|
+
export const getContainerElement = (element, elementsMap) => {
|
|
500
461
|
if (!element) {
|
|
501
462
|
return null;
|
|
502
463
|
}
|
|
503
464
|
if (element.containerId) {
|
|
504
|
-
return
|
|
465
|
+
return (elementsMap.get(element.containerId) ||
|
|
466
|
+
null);
|
|
505
467
|
}
|
|
506
468
|
return null;
|
|
507
469
|
};
|
|
508
|
-
export const getContainerCenter = (container, appState) => {
|
|
470
|
+
export const getContainerCenter = (container, appState, elementsMap) => {
|
|
509
471
|
if (!isArrowElement(container)) {
|
|
510
472
|
return {
|
|
511
473
|
x: container.x + container.width / 2,
|
|
512
474
|
y: container.y + container.height / 2,
|
|
513
475
|
};
|
|
514
476
|
}
|
|
515
|
-
const points = LinearElementEditor.getPointsGlobalCoordinates(container);
|
|
477
|
+
const points = LinearElementEditor.getPointsGlobalCoordinates(container, elementsMap);
|
|
516
478
|
if (points.length % 2 === 1) {
|
|
517
479
|
const index = Math.floor(container.points.length / 2);
|
|
518
|
-
const midPoint = LinearElementEditor.getPointGlobalCoordinates(container, container.points[index]);
|
|
480
|
+
const midPoint = LinearElementEditor.getPointGlobalCoordinates(container, container.points[index], elementsMap);
|
|
519
481
|
return { x: midPoint[0], y: midPoint[1] };
|
|
520
482
|
}
|
|
521
483
|
const index = container.points.length / 2 - 1;
|
|
522
|
-
let midSegmentMidpoint = LinearElementEditor.getEditorMidPoints(container, appState)[index];
|
|
484
|
+
let midSegmentMidpoint = LinearElementEditor.getEditorMidPoints(container, elementsMap, appState)[index];
|
|
523
485
|
if (!midSegmentMidpoint) {
|
|
524
|
-
midSegmentMidpoint = LinearElementEditor.getSegmentMidPoint(container, points[index], points[index + 1], index + 1);
|
|
486
|
+
midSegmentMidpoint = LinearElementEditor.getSegmentMidPoint(container, points[index], points[index + 1], index + 1, elementsMap);
|
|
525
487
|
}
|
|
526
488
|
return { x: midSegmentMidpoint[0], y: midSegmentMidpoint[1] };
|
|
527
489
|
};
|
|
@@ -543,34 +505,22 @@ export const getContainerCoords = (container) => {
|
|
|
543
505
|
y: container.y + offsetY,
|
|
544
506
|
};
|
|
545
507
|
};
|
|
546
|
-
export const getTextElementAngle = (textElement) => {
|
|
547
|
-
const container = getContainerElement(textElement);
|
|
508
|
+
export const getTextElementAngle = (textElement, container) => {
|
|
548
509
|
if (!container || isArrowElement(container)) {
|
|
549
510
|
return textElement.angle;
|
|
550
511
|
}
|
|
551
512
|
return container.angle;
|
|
552
513
|
};
|
|
553
|
-
export const
|
|
554
|
-
const container = getContainerElement(boundTextElement);
|
|
555
|
-
if (!container || !boundTextElement) {
|
|
556
|
-
return 0;
|
|
557
|
-
}
|
|
514
|
+
export const getBoundTextElementPosition = (container, boundTextElement, elementsMap) => {
|
|
558
515
|
if (isArrowElement(container)) {
|
|
559
|
-
return
|
|
516
|
+
return LinearElementEditor.getBoundTextElementPosition(container, boundTextElement, elementsMap);
|
|
560
517
|
}
|
|
561
|
-
return BOUND_TEXT_PADDING;
|
|
562
518
|
};
|
|
563
|
-
export const
|
|
564
|
-
if (isArrowElement(container)) {
|
|
565
|
-
return LinearElementEditor.getBoundTextElementPosition(container, boundTextElement);
|
|
566
|
-
}
|
|
567
|
-
};
|
|
568
|
-
export const shouldAllowVerticalAlign = (selectedElements) => {
|
|
519
|
+
export const shouldAllowVerticalAlign = (selectedElements, elementsMap) => {
|
|
569
520
|
return selectedElements.some((element) => {
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
if (isTextElement(element) && isArrowElement(container)) {
|
|
521
|
+
if (isBoundToContainer(element)) {
|
|
522
|
+
const container = getContainerElement(element, elementsMap);
|
|
523
|
+
if (isArrowElement(container)) {
|
|
574
524
|
return false;
|
|
575
525
|
}
|
|
576
526
|
return true;
|
|
@@ -578,12 +528,11 @@ export const shouldAllowVerticalAlign = (selectedElements) => {
|
|
|
578
528
|
return false;
|
|
579
529
|
});
|
|
580
530
|
};
|
|
581
|
-
export const suppportsHorizontalAlign = (selectedElements) => {
|
|
531
|
+
export const suppportsHorizontalAlign = (selectedElements, elementsMap) => {
|
|
582
532
|
return selectedElements.some((element) => {
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
if (isTextElement(element) && isArrowElement(container)) {
|
|
533
|
+
if (isBoundToContainer(element)) {
|
|
534
|
+
const container = getContainerElement(element, elementsMap);
|
|
535
|
+
if (isArrowElement(container)) {
|
|
587
536
|
return false;
|
|
588
537
|
}
|
|
589
538
|
return true;
|
|
@@ -591,7 +540,7 @@ export const suppportsHorizontalAlign = (selectedElements) => {
|
|
|
591
540
|
return isTextElement(element);
|
|
592
541
|
});
|
|
593
542
|
};
|
|
594
|
-
export const getTextBindableContainerAtPosition = (elements, appState, x, y) => {
|
|
543
|
+
export const getTextBindableContainerAtPosition = (elements, appState, x, y, elementsMap) => {
|
|
595
544
|
const selectedElements = getSelectedElements(elements, appState);
|
|
596
545
|
if (selectedElements.length === 1) {
|
|
597
546
|
return isTextBindableContainer(selectedElements[0], false)
|
|
@@ -604,9 +553,9 @@ export const getTextBindableContainerAtPosition = (elements, appState, x, y) =>
|
|
|
604
553
|
if (elements[index].isDeleted) {
|
|
605
554
|
continue;
|
|
606
555
|
}
|
|
607
|
-
const [x1, y1, x2, y2] = getElementAbsoluteCoords(elements[index]);
|
|
556
|
+
const [x1, y1, x2, y2] = getElementAbsoluteCoords(elements[index], elementsMap);
|
|
608
557
|
if (isArrowElement(elements[index]) &&
|
|
609
|
-
isHittingElementNotConsideringBoundingBox(elements[index], appState, null, [x, y])) {
|
|
558
|
+
isHittingElementNotConsideringBoundingBox(elements[index], appState, null, [x, y], elementsMap)) {
|
|
610
559
|
hitElement = elements[index];
|
|
611
560
|
break;
|
|
612
561
|
}
|
|
@@ -638,7 +587,7 @@ export const computeContainerDimensionForBoundText = (dimension, containerType)
|
|
|
638
587
|
}
|
|
639
588
|
return dimension + padding;
|
|
640
589
|
};
|
|
641
|
-
export const getBoundTextMaxWidth = (container, boundTextElement
|
|
590
|
+
export const getBoundTextMaxWidth = (container, boundTextElement) => {
|
|
642
591
|
const { width } = container;
|
|
643
592
|
if (isArrowElement(container)) {
|
|
644
593
|
const minWidth = (boundTextElement?.fontSize ?? DEFAULT_FONT_SIZE) *
|
|
@@ -702,12 +651,39 @@ const DEFAULT_LINE_HEIGHT = {
|
|
|
702
651
|
// ~1.25 is the average for Virgil in WebKit and Blink.
|
|
703
652
|
// Gecko (FF) uses ~1.28.
|
|
704
653
|
[FONT_FAMILY.Virgil]: 1.25,
|
|
705
|
-
// ~1.15 is the average for
|
|
706
|
-
// Gecko if all over the place.
|
|
654
|
+
// ~1.15 is the average for Helvetica in WebKit and Blink.
|
|
707
655
|
[FONT_FAMILY.Helvetica]: 1.15,
|
|
708
|
-
// ~1.2 is the average for
|
|
656
|
+
// ~1.2 is the average for Cascadia in WebKit and Blink, and kinda Gecko too
|
|
709
657
|
[FONT_FAMILY.Cascadia]: 1.2,
|
|
710
658
|
};
|
|
659
|
+
/**
|
|
660
|
+
* Hardcoded metrics for default fonts, read by https://opentype.js.org/font-inspector.html.
|
|
661
|
+
* For custom fonts, read these metrics from OS/2 table and extend this object.
|
|
662
|
+
*
|
|
663
|
+
* WARN: opentype does NOT open WOFF2 correctly, make sure to convert WOFF2 to TTF first.
|
|
664
|
+
*/
|
|
665
|
+
export const FONT_METRICS = {
|
|
666
|
+
[FONT_FAMILY.Virgil]: {
|
|
667
|
+
unitsPerEm: 1000,
|
|
668
|
+
ascender: 886,
|
|
669
|
+
descender: -374,
|
|
670
|
+
},
|
|
671
|
+
[FONT_FAMILY.Helvetica]: {
|
|
672
|
+
unitsPerEm: 2048,
|
|
673
|
+
ascender: 1577,
|
|
674
|
+
descender: -471,
|
|
675
|
+
},
|
|
676
|
+
[FONT_FAMILY.Cascadia]: {
|
|
677
|
+
unitsPerEm: 2048,
|
|
678
|
+
ascender: 1977,
|
|
679
|
+
descender: -480,
|
|
680
|
+
},
|
|
681
|
+
[FONT_FAMILY.Assistant]: {
|
|
682
|
+
unitsPerEm: 1000,
|
|
683
|
+
ascender: 1021,
|
|
684
|
+
descender: -287,
|
|
685
|
+
},
|
|
686
|
+
};
|
|
711
687
|
export const getDefaultLineHeight = (fontFamily) => {
|
|
712
688
|
if (fontFamily in DEFAULT_LINE_HEIGHT) {
|
|
713
689
|
return DEFAULT_LINE_HEIGHT[fontFamily];
|
|
@@ -1,10 +1,5 @@
|
|
|
1
|
-
import { ExcalidrawElement, ExcalidrawTextElement
|
|
1
|
+
import { ExcalidrawElement, ExcalidrawTextElement } from "./types";
|
|
2
2
|
import App from "../components/App";
|
|
3
|
-
export declare const updateOriginalContainerCache: (id: ExcalidrawTextContainer["id"], height: ExcalidrawTextContainer["height"]) => {
|
|
4
|
-
height: ExcalidrawTextContainer["height"];
|
|
5
|
-
};
|
|
6
|
-
export declare const resetOriginalContainerCache: (id: ExcalidrawTextContainer["id"]) => void;
|
|
7
|
-
export declare const getOriginalContainerHeightFromCache: (id: ExcalidrawTextContainer["id"]) => number | null;
|
|
8
3
|
export declare const textWysiwyg: ({ id, onChange, onSubmit, getViewportCoords, element, canvas, excalidrawContainer, app, }: {
|
|
9
4
|
id: ExcalidrawElement["id"];
|
|
10
5
|
onChange?: ((text: string) => void) | undefined;
|
|
@@ -2,13 +2,14 @@ import { CODES, KEYS } from "../keys";
|
|
|
2
2
|
import { isWritableElement, getFontString, getFontFamilyString, isTestEnv, } from "../utils";
|
|
3
3
|
import Scene from "../scene/Scene";
|
|
4
4
|
import { isArrowElement, isBoundToContainer, isTextElement, } from "./typeChecks";
|
|
5
|
-
import { CLASSES
|
|
5
|
+
import { CLASSES } from "../constants";
|
|
6
6
|
import { bumpVersion, mutateElement } from "./mutateElement";
|
|
7
|
-
import { getBoundTextElementId, getContainerElement, getTextElementAngle, getTextWidth, normalizeText, redrawTextBoundingBox, wrapText, getBoundTextMaxHeight, getBoundTextMaxWidth, computeContainerDimensionForBoundText,
|
|
7
|
+
import { getBoundTextElementId, getContainerElement, getTextElementAngle, getTextWidth, normalizeText, redrawTextBoundingBox, wrapText, getBoundTextMaxHeight, getBoundTextMaxWidth, computeContainerDimensionForBoundText, computeBoundTextPosition, getBoundTextElement, } from "./textElement";
|
|
8
8
|
import { actionDecreaseFontSize, actionIncreaseFontSize, } from "../actions/actionProperties";
|
|
9
9
|
import { actionZoomIn, actionZoomOut } from "../actions/actionCanvas";
|
|
10
10
|
import { LinearElementEditor } from "./linearElementEditor";
|
|
11
11
|
import { parseClipboard } from "../clipboard";
|
|
12
|
+
import { originalContainerCache, updateOriginalContainerCache, } from "./containerCache";
|
|
12
13
|
const getTransform = (width, height, angle, appState, maxWidth, maxHeight) => {
|
|
13
14
|
const { zoom } = appState;
|
|
14
15
|
const degree = (180 * angle) / Math.PI;
|
|
@@ -22,20 +23,6 @@ const getTransform = (width, height, angle, appState, maxWidth, maxHeight) => {
|
|
|
22
23
|
}
|
|
23
24
|
return `translate(${translateX}px, ${translateY}px) scale(${zoom.value}) rotate(${degree}deg)`;
|
|
24
25
|
};
|
|
25
|
-
const originalContainerCache = {};
|
|
26
|
-
export const updateOriginalContainerCache = (id, height) => {
|
|
27
|
-
const data = originalContainerCache[id] || (originalContainerCache[id] = { height });
|
|
28
|
-
data.height = height;
|
|
29
|
-
return data;
|
|
30
|
-
};
|
|
31
|
-
export const resetOriginalContainerCache = (id) => {
|
|
32
|
-
if (originalContainerCache[id]) {
|
|
33
|
-
delete originalContainerCache[id];
|
|
34
|
-
}
|
|
35
|
-
};
|
|
36
|
-
export const getOriginalContainerHeightFromCache = (id) => {
|
|
37
|
-
return originalContainerCache[id]?.height ?? null;
|
|
38
|
-
};
|
|
39
26
|
export const textWysiwyg = ({ id, onChange, onSubmit, getViewportCoords, element, canvas, excalidrawContainer, app, }) => {
|
|
40
27
|
const textPropertiesUpdated = (updatedTextElement, editable) => {
|
|
41
28
|
if (!editable.style.fontFamily || !editable.style.fontSize) {
|
|
@@ -58,10 +45,11 @@ export const textWysiwyg = ({ id, onChange, onSubmit, getViewportCoords, element
|
|
|
58
45
|
return;
|
|
59
46
|
}
|
|
60
47
|
const { textAlign, verticalAlign } = updatedTextElement;
|
|
48
|
+
const elementsMap = app.scene.getNonDeletedElementsMap();
|
|
61
49
|
if (updatedTextElement && isTextElement(updatedTextElement)) {
|
|
62
50
|
let coordX = updatedTextElement.x;
|
|
63
51
|
let coordY = updatedTextElement.y;
|
|
64
|
-
const container = getContainerElement(updatedTextElement);
|
|
52
|
+
const container = getContainerElement(updatedTextElement, app.scene.getNonDeletedElementsMap());
|
|
65
53
|
let maxWidth = updatedTextElement.width;
|
|
66
54
|
let maxHeight = updatedTextElement.height;
|
|
67
55
|
let textElementWidth = updatedTextElement.width;
|
|
@@ -70,7 +58,7 @@ export const textWysiwyg = ({ id, onChange, onSubmit, getViewportCoords, element
|
|
|
70
58
|
const textElementHeight = updatedTextElement.height;
|
|
71
59
|
if (container && updatedTextElement.containerId) {
|
|
72
60
|
if (isArrowElement(container)) {
|
|
73
|
-
const boundTextCoords = LinearElementEditor.getBoundTextElementPosition(container, updatedTextElement);
|
|
61
|
+
const boundTextCoords = LinearElementEditor.getBoundTextElementPosition(container, updatedTextElement, elementsMap);
|
|
74
62
|
coordX = boundTextCoords.x;
|
|
75
63
|
coordY = boundTextCoords.y;
|
|
76
64
|
}
|
|
@@ -85,7 +73,7 @@ export const textWysiwyg = ({ id, onChange, onSubmit, getViewportCoords, element
|
|
|
85
73
|
originalContainerData = updateOriginalContainerCache(container.id, container.height);
|
|
86
74
|
}
|
|
87
75
|
}
|
|
88
|
-
maxWidth = getBoundTextMaxWidth(container);
|
|
76
|
+
maxWidth = getBoundTextMaxWidth(container, updatedTextElement);
|
|
89
77
|
maxHeight = getBoundTextMaxHeight(container, updatedTextElement);
|
|
90
78
|
// autogrow container height if text exceeds
|
|
91
79
|
if (!isArrowElement(container) && textElementHeight > maxHeight) {
|
|
@@ -103,7 +91,7 @@ export const textWysiwyg = ({ id, onChange, onSubmit, getViewportCoords, element
|
|
|
103
91
|
mutateElement(container, { height: targetContainerHeight });
|
|
104
92
|
}
|
|
105
93
|
else {
|
|
106
|
-
const { y } = computeBoundTextPosition(container, updatedTextElement);
|
|
94
|
+
const { y } = computeBoundTextPosition(container, updatedTextElement, elementsMap);
|
|
107
95
|
coordY = y;
|
|
108
96
|
}
|
|
109
97
|
}
|
|
@@ -125,28 +113,17 @@ export const textWysiwyg = ({ id, onChange, onSubmit, getViewportCoords, element
|
|
|
125
113
|
maxWidth = (appState.width - 8 - viewportX) / appState.zoom.value;
|
|
126
114
|
textElementWidth = Math.min(textElementWidth, maxWidth);
|
|
127
115
|
}
|
|
128
|
-
else {
|
|
129
|
-
textElementWidth += 0.5;
|
|
130
|
-
}
|
|
131
|
-
let lineHeight = updatedTextElement.lineHeight;
|
|
132
|
-
// In Safari the font size gets rounded off when rendering hence calculating the line height by rounding off font size
|
|
133
|
-
if (isSafari) {
|
|
134
|
-
lineHeight = detectLineHeight({
|
|
135
|
-
...updatedTextElement,
|
|
136
|
-
fontSize: Math.round(updatedTextElement.fontSize),
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
116
|
// Make sure text editor height doesn't go beyond viewport
|
|
140
117
|
const editorMaxHeight = (appState.height - viewportY) / appState.zoom.value;
|
|
141
118
|
Object.assign(editable.style, {
|
|
142
119
|
font: getFontString(updatedTextElement),
|
|
143
120
|
// must be defined *after* font ¯\_(ツ)_/¯
|
|
144
|
-
lineHeight,
|
|
121
|
+
lineHeight: updatedTextElement.lineHeight,
|
|
145
122
|
width: `${textElementWidth}px`,
|
|
146
123
|
height: `${textElementHeight}px`,
|
|
147
124
|
left: `${viewportX}px`,
|
|
148
125
|
top: `${viewportY}px`,
|
|
149
|
-
transform: getTransform(textElementWidth, textElementHeight, getTextElementAngle(updatedTextElement), appState, maxWidth, editorMaxHeight),
|
|
126
|
+
transform: getTransform(textElementWidth, textElementHeight, getTextElementAngle(updatedTextElement, container), appState, maxWidth, editorMaxHeight),
|
|
150
127
|
textAlign,
|
|
151
128
|
verticalAlign,
|
|
152
129
|
color: updatedTextElement.strokeColor,
|
|
@@ -208,13 +185,14 @@ export const textWysiwyg = ({ id, onChange, onSubmit, getViewportCoords, element
|
|
|
208
185
|
if (!data) {
|
|
209
186
|
return;
|
|
210
187
|
}
|
|
211
|
-
const container = getContainerElement(element);
|
|
188
|
+
const container = getContainerElement(element, app.scene.getNonDeletedElementsMap());
|
|
212
189
|
const font = getFontString({
|
|
213
190
|
fontSize: app.state.currentItemFontSize,
|
|
214
191
|
fontFamily: app.state.currentItemFontFamily,
|
|
215
192
|
});
|
|
216
193
|
if (container) {
|
|
217
|
-
const
|
|
194
|
+
const boundTextElement = getBoundTextElement(container, app.scene.getNonDeletedElementsMap());
|
|
195
|
+
const wrappedText = wrapText(`${editable.value}${data}`, font, getBoundTextMaxWidth(container, boundTextElement));
|
|
218
196
|
const width = getTextWidth(wrappedText, font);
|
|
219
197
|
editable.style.width = `${width}px`;
|
|
220
198
|
}
|
|
@@ -357,7 +335,7 @@ export const textWysiwyg = ({ id, onChange, onSubmit, getViewportCoords, element
|
|
|
357
335
|
return;
|
|
358
336
|
}
|
|
359
337
|
let text = editable.value;
|
|
360
|
-
const container = getContainerElement(updateElement);
|
|
338
|
+
const container = getContainerElement(updateElement, app.scene.getNonDeletedElementsMap());
|
|
361
339
|
if (container) {
|
|
362
340
|
text = updateElement.text;
|
|
363
341
|
if (editable.value.trim()) {
|
|
@@ -380,7 +358,7 @@ export const textWysiwyg = ({ id, onChange, onSubmit, getViewportCoords, element
|
|
|
380
358
|
boundElements: container.boundElements?.filter((ele) => !isTextElement(ele)),
|
|
381
359
|
});
|
|
382
360
|
}
|
|
383
|
-
redrawTextBoundingBox(updateElement, container);
|
|
361
|
+
redrawTextBoundingBox(updateElement, container, app.scene.getNonDeletedElementsMap());
|
|
384
362
|
}
|
|
385
363
|
onSubmit({
|
|
386
364
|
text,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ExcalidrawElement, NonDeletedExcalidrawElement, PointerType } from "./types";
|
|
1
|
+
import { ElementsMap, ExcalidrawElement, NonDeletedExcalidrawElement, PointerType } from "./types";
|
|
2
2
|
import { Bounds } from "./bounds";
|
|
3
3
|
import { InteractiveCanvasAppState, Zoom } from "../types";
|
|
4
4
|
export type TransformHandleDirection = "n" | "s" | "w" | "e" | "nw" | "ne" | "sw" | "se";
|
|
@@ -23,14 +23,14 @@ export declare const OMIT_SIDES_FOR_FRAME: {
|
|
|
23
23
|
};
|
|
24
24
|
export declare const getTransformHandlesFromCoords: ([x1, y1, x2, y2, cx, cy]: [number, number, number, number, number, number], angle: number, zoom: Zoom, pointerType: PointerType, omitSides?: {
|
|
25
25
|
s?: boolean | undefined;
|
|
26
|
-
e?: boolean | undefined;
|
|
27
|
-
w?: boolean | undefined;
|
|
28
26
|
n?: boolean | undefined;
|
|
27
|
+
w?: boolean | undefined;
|
|
28
|
+
e?: boolean | undefined;
|
|
29
29
|
nw?: boolean | undefined;
|
|
30
30
|
ne?: boolean | undefined;
|
|
31
31
|
sw?: boolean | undefined;
|
|
32
32
|
se?: boolean | undefined;
|
|
33
33
|
rotation?: boolean | undefined;
|
|
34
34
|
}, margin?: number) => TransformHandles;
|
|
35
|
-
export declare const getTransformHandles: (element: ExcalidrawElement, zoom: Zoom, pointerType?: PointerType) => TransformHandles;
|
|
35
|
+
export declare const getTransformHandles: (element: ExcalidrawElement, zoom: Zoom, elementsMap: ElementsMap, pointerType?: PointerType) => TransformHandles;
|
|
36
36
|
export declare const shouldShowBoundingBox: (elements: readonly NonDeletedExcalidrawElement[], appState: InteractiveCanvasAppState) => boolean;
|
|
@@ -2,7 +2,7 @@ import { getElementAbsoluteCoords } from "./bounds";
|
|
|
2
2
|
import { rotate } from "../math";
|
|
3
3
|
import { isTextElement } from ".";
|
|
4
4
|
import { isFrameLikeElement, isLinearElement } from "./typeChecks";
|
|
5
|
-
import {
|
|
5
|
+
import { DEFAULT_TRANSFORM_HANDLE_SPACING } from "../constants";
|
|
6
6
|
const transformHandleSizes = {
|
|
7
7
|
mouse: 8,
|
|
8
8
|
pen: 16,
|
|
@@ -55,7 +55,7 @@ export const getTransformHandlesFromCoords = ([x1, y1, x2, y2, cx, cy], angle, z
|
|
|
55
55
|
const width = x2 - x1;
|
|
56
56
|
const height = y2 - y1;
|
|
57
57
|
const dashedLineMargin = margin / zoom.value;
|
|
58
|
-
const centeringOffset = (size -
|
|
58
|
+
const centeringOffset = (size - DEFAULT_TRANSFORM_HANDLE_SPACING * 2) / (2 * zoom.value);
|
|
59
59
|
const transformHandles = {
|
|
60
60
|
nw: omitSides.nw
|
|
61
61
|
? undefined
|
|
@@ -98,7 +98,7 @@ export const getTransformHandlesFromCoords = ([x1, y1, x2, y2, cx, cy], angle, z
|
|
|
98
98
|
}
|
|
99
99
|
return transformHandles;
|
|
100
100
|
};
|
|
101
|
-
export const getTransformHandles = (element, zoom, pointerType = "mouse") => {
|
|
101
|
+
export const getTransformHandles = (element, zoom, elementsMap, pointerType = "mouse") => {
|
|
102
102
|
// so that when locked element is selected (especially when you toggle lock
|
|
103
103
|
// via keyboard) the locked element is visually distinct, indicating
|
|
104
104
|
// you can't move/resize
|
|
@@ -136,9 +136,9 @@ export const getTransformHandles = (element, zoom, pointerType = "mouse") => {
|
|
|
136
136
|
};
|
|
137
137
|
}
|
|
138
138
|
const dashedLineMargin = isLinearElement(element)
|
|
139
|
-
?
|
|
140
|
-
:
|
|
141
|
-
return getTransformHandlesFromCoords(getElementAbsoluteCoords(element, true), element.angle, zoom, pointerType, omitSides, dashedLineMargin);
|
|
139
|
+
? DEFAULT_TRANSFORM_HANDLE_SPACING + 8
|
|
140
|
+
: DEFAULT_TRANSFORM_HANDLE_SPACING;
|
|
141
|
+
return getTransformHandlesFromCoords(getElementAbsoluteCoords(element, elementsMap, true), element.angle, zoom, pointerType, omitSides, dashedLineMargin);
|
|
142
142
|
};
|
|
143
143
|
export const shouldShowBoundingBox = (elements, appState) => {
|
|
144
144
|
if (appState.editingLinearElement) {
|
|
@@ -110,7 +110,10 @@ export const isBoundToContainer = (element) => {
|
|
|
110
110
|
element.containerId !== null &&
|
|
111
111
|
isTextElement(element));
|
|
112
112
|
};
|
|
113
|
-
export const isUsingAdaptiveRadius = (type) => type === "rectangle" ||
|
|
113
|
+
export const isUsingAdaptiveRadius = (type) => type === "rectangle" ||
|
|
114
|
+
type === "embeddable" ||
|
|
115
|
+
type === "iframe" ||
|
|
116
|
+
type === "image";
|
|
114
117
|
export const isUsingProportionalRadius = (type) => type === "line" || type === "arrow" || type === "diamond";
|
|
115
118
|
export const canApplyRoundnessTypeToElement = (roundnessType, element) => {
|
|
116
119
|
if ((roundnessType === ROUNDNESS.ADAPTIVE_RADIUS ||
|