@excalidraw/excalidraw 0.17.1-d2f67e6 → 0.17.1-e63dd02
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 +4 -0
- package/dist/browser/dev/excalidraw-assets-dev/CascadiaCode-Regular-TMZI7IJ5.woff2 +0 -0
- package/dist/browser/dev/excalidraw-assets-dev/ComicShanns-Regular-6TOETDFT.woff2 +0 -0
- package/dist/browser/dev/excalidraw-assets-dev/Excalifont-Regular-CPKEUDVM.woff2 +0 -0
- package/dist/browser/dev/excalidraw-assets-dev/LiberationSans-Regular-ZQD73GJM.woff2 +0 -0
- package/dist/browser/dev/excalidraw-assets-dev/Virgil-Regular-YHAB2VGJ.woff2 +0 -0
- package/dist/browser/dev/excalidraw-assets-dev/{chunk-EM6LVGFW.js → chunk-IT7T3AIK.js} +23 -5
- package/dist/browser/dev/excalidraw-assets-dev/chunk-IT7T3AIK.js.map +7 -0
- package/dist/browser/dev/excalidraw-assets-dev/{chunk-B4UMSLQQ.js → chunk-RNHSD5AR.js} +7451 -2098
- package/dist/browser/dev/excalidraw-assets-dev/chunk-RNHSD5AR.js.map +7 -0
- package/dist/browser/dev/excalidraw-assets-dev/{dist-6QVAH5JA.js → dist-DNSPZDOZ.js} +31 -19
- package/dist/browser/dev/excalidraw-assets-dev/dist-DNSPZDOZ.js.map +7 -0
- package/dist/browser/dev/excalidraw-assets-dev/{en-AZFA5HJJ.js → en-XV7OZCPP.js} +6 -2
- package/dist/browser/dev/excalidraw-assets-dev/{image-V7E6IT6R.js → image-77HZYGLG.js} +2 -2
- package/dist/browser/dev/excalidraw-assets-dev/{image-O66MQ7WQ.css → image-WDHYGKKP.css} +1 -1
- package/dist/browser/dev/excalidraw-assets-dev/{image-O66MQ7WQ.css.map → image-WDHYGKKP.css.map} +2 -2
- package/dist/browser/dev/index.css +449 -114
- package/dist/browser/dev/index.css.map +3 -3
- package/dist/browser/dev/index.js +4143 -5956
- package/dist/browser/dev/index.js.map +4 -4
- package/dist/browser/prod/excalidraw-assets/CascadiaCode-Regular-TMZI7IJ5.woff2 +0 -0
- package/dist/browser/prod/excalidraw-assets/ComicShanns-Regular-6TOETDFT.woff2 +0 -0
- package/dist/browser/prod/excalidraw-assets/Excalifont-Regular-CPKEUDVM.woff2 +0 -0
- package/dist/browser/prod/excalidraw-assets/LiberationSans-Regular-ZQD73GJM.woff2 +0 -0
- package/dist/browser/prod/excalidraw-assets/Virgil-Regular-YHAB2VGJ.woff2 +0 -0
- package/dist/browser/prod/excalidraw-assets/chunk-OYEADJSR.js +63 -0
- package/dist/browser/prod/excalidraw-assets/{chunk-7DXALCB2.js → chunk-PDYFZJMS.js} +3 -3
- package/dist/browser/prod/excalidraw-assets/dist-NLUQPPQQ.js +7 -0
- package/dist/browser/prod/excalidraw-assets/en-YVAVVILW.js +1 -0
- package/dist/browser/prod/excalidraw-assets/image-X3GFZHNN.js +1 -0
- package/dist/browser/prod/index.css +1 -1
- package/dist/browser/prod/index.js +40 -50
- package/dist/dev/CascadiaCode-Regular-TMZI7IJ5.woff2 +0 -0
- package/dist/dev/ComicShanns-Regular-6TOETDFT.woff2 +0 -0
- package/dist/dev/Excalifont-Regular-CPKEUDVM.woff2 +0 -0
- package/dist/dev/LiberationSans-Regular-ZQD73GJM.woff2 +0 -0
- package/dist/dev/Virgil-Regular-YHAB2VGJ.woff2 +0 -0
- package/dist/dev/{en-EB2MBPAV.json → en-YNVBSAIL.json} +18 -4
- package/dist/dev/index.css +449 -114
- package/dist/dev/index.css.map +3 -3
- package/dist/dev/index.js +21626 -18122
- package/dist/dev/index.js.map +4 -4
- package/dist/excalidraw/actions/actionAddToLibrary.d.ts +9 -3
- package/dist/excalidraw/actions/actionBoundText.d.ts +6 -2
- package/dist/excalidraw/actions/actionCanvas.d.ts +36 -12
- package/dist/excalidraw/actions/actionClipboard.d.ts +22 -7
- package/dist/excalidraw/actions/actionDeleteSelected.d.ts +12 -5
- package/dist/excalidraw/actions/actionDeleteSelected.js +24 -5
- package/dist/excalidraw/actions/actionDuplicateSelection.js +1 -2
- package/dist/excalidraw/actions/actionElementLock.d.ts +6 -2
- package/dist/excalidraw/actions/actionExport.d.ts +27 -9
- package/dist/excalidraw/actions/actionFinalize.d.ts +6 -2
- package/dist/excalidraw/actions/actionFinalize.js +2 -2
- package/dist/excalidraw/actions/actionFlip.js +2 -2
- package/dist/excalidraw/actions/actionFrame.d.ts +12 -4
- package/dist/excalidraw/actions/actionGroup.d.ts +6 -2
- package/dist/excalidraw/actions/actionHistory.js +4 -4
- package/dist/excalidraw/actions/actionLinearEditor.d.ts +3 -1
- package/dist/excalidraw/actions/actionLinearEditor.js +3 -2
- package/dist/excalidraw/actions/actionLink.d.ts +3 -1
- package/dist/excalidraw/actions/actionMenu.d.ts +9 -3
- package/dist/excalidraw/actions/actionNavigate.d.ts +6 -2
- package/dist/excalidraw/actions/actionProperties.d.ts +411 -56
- package/dist/excalidraw/actions/actionProperties.js +383 -58
- package/dist/excalidraw/actions/actionSelectAll.d.ts +3 -1
- package/dist/excalidraw/actions/actionStyles.d.ts +3 -1
- package/dist/excalidraw/actions/actionStyles.js +3 -2
- package/dist/excalidraw/actions/actionToggleGridMode.d.ts +3 -1
- package/dist/excalidraw/actions/actionToggleObjectsSnapMode.d.ts +3 -1
- package/dist/excalidraw/actions/actionToggleStats.d.ts +3 -1
- package/dist/excalidraw/actions/actionToggleViewMode.d.ts +3 -1
- package/dist/excalidraw/actions/actionToggleZenMode.d.ts +3 -1
- package/dist/excalidraw/actions/types.d.ts +1 -1
- package/dist/excalidraw/analytics.js +9 -7
- package/dist/excalidraw/appState.d.ts +1 -0
- package/dist/excalidraw/appState.js +9 -1
- package/dist/excalidraw/binaryheap.d.ts +12 -0
- package/dist/excalidraw/binaryheap.js +93 -0
- package/dist/excalidraw/change.d.ts +2 -1
- package/dist/excalidraw/change.js +6 -4
- package/dist/excalidraw/charts.js +0 -10
- package/dist/excalidraw/components/Actions.js +7 -5
- package/dist/excalidraw/components/App.d.ts +5 -9
- package/dist/excalidraw/components/App.js +218 -161
- package/dist/excalidraw/components/ButtonIcon.d.ts +15 -0
- package/dist/excalidraw/components/ButtonIcon.js +8 -0
- package/dist/excalidraw/components/ButtonIconSelect.js +2 -3
- package/dist/excalidraw/components/ButtonSeparator.d.ts +2 -0
- package/dist/excalidraw/components/ButtonSeparator.js +7 -0
- package/dist/excalidraw/components/ColorPicker/ColorPicker.js +47 -79
- package/dist/excalidraw/components/ColorPicker/Picker.js +1 -1
- package/dist/excalidraw/components/FontPicker/FontPicker.d.ts +21 -0
- package/dist/excalidraw/components/FontPicker/FontPicker.js +49 -0
- package/dist/excalidraw/components/FontPicker/FontPickerList.d.ts +25 -0
- package/dist/excalidraw/components/FontPicker/FontPickerList.js +119 -0
- package/dist/excalidraw/components/FontPicker/FontPickerTrigger.d.ts +7 -0
- package/dist/excalidraw/components/FontPicker/FontPickerTrigger.js +13 -0
- package/dist/excalidraw/components/FontPicker/keyboardNavHandlers.d.ts +14 -0
- package/dist/excalidraw/components/FontPicker/keyboardNavHandlers.js +38 -0
- package/dist/excalidraw/components/HelpDialog.js +1 -1
- package/dist/excalidraw/components/HintViewer.js +6 -3
- package/dist/excalidraw/components/PropertiesPopover.d.ts +15 -0
- package/dist/excalidraw/components/PropertiesPopover.js +31 -0
- package/dist/excalidraw/components/QuickSearch.d.ts +9 -0
- package/dist/excalidraw/components/QuickSearch.js +8 -0
- package/dist/excalidraw/components/ScrollableList.d.ts +9 -0
- package/dist/excalidraw/components/ScrollableList.js +8 -0
- package/dist/excalidraw/components/Stats/Angle.d.ts +7 -3
- package/dist/excalidraw/components/Stats/Angle.js +39 -31
- package/dist/excalidraw/components/Stats/Dimension.d.ts +6 -3
- package/dist/excalidraw/components/Stats/Dimension.js +51 -49
- package/dist/excalidraw/components/Stats/DragInput.d.ts +15 -6
- package/dist/excalidraw/components/Stats/DragInput.js +59 -26
- package/dist/excalidraw/components/Stats/FontSize.d.ts +8 -4
- package/dist/excalidraw/components/Stats/FontSize.js +39 -36
- package/dist/excalidraw/components/Stats/MultiAngle.d.ts +5 -3
- package/dist/excalidraw/components/Stats/MultiAngle.js +43 -34
- package/dist/excalidraw/components/Stats/MultiDimension.d.ts +5 -3
- package/dist/excalidraw/components/Stats/MultiDimension.js +101 -99
- package/dist/excalidraw/components/Stats/MultiFontSize.d.ts +6 -3
- package/dist/excalidraw/components/Stats/MultiFontSize.js +47 -32
- package/dist/excalidraw/components/Stats/MultiPosition.d.ts +3 -1
- package/dist/excalidraw/components/Stats/MultiPosition.js +52 -48
- package/dist/excalidraw/components/Stats/Position.d.ts +5 -1
- package/dist/excalidraw/components/Stats/Position.js +31 -29
- package/dist/excalidraw/components/Stats/index.js +5 -17
- package/dist/excalidraw/components/Stats/utils.d.ts +14 -3
- package/dist/excalidraw/components/Stats/utils.js +48 -9
- package/dist/excalidraw/components/TTDDialog/common.d.ts +2 -2
- package/dist/excalidraw/components/TTDDialog/common.js +3 -7
- package/dist/excalidraw/components/UserList.js +22 -22
- package/dist/excalidraw/components/canvases/StaticCanvas.js +1 -0
- package/dist/excalidraw/components/dropdownMenu/DropdownMenu.d.ts +12 -3
- package/dist/excalidraw/components/dropdownMenu/DropdownMenuItem.d.ts +24 -4
- package/dist/excalidraw/components/dropdownMenu/DropdownMenuItem.js +55 -14
- package/dist/excalidraw/components/dropdownMenu/DropdownMenuItemContent.d.ts +2 -1
- package/dist/excalidraw/components/dropdownMenu/DropdownMenuItemContent.js +2 -2
- package/dist/excalidraw/components/dropdownMenu/common.d.ts +1 -1
- package/dist/excalidraw/components/dropdownMenu/common.js +3 -2
- package/dist/excalidraw/components/icons.d.ts +4 -0
- package/dist/excalidraw/components/icons.js +7 -0
- package/dist/excalidraw/components/main-menu/MainMenu.d.ts +12 -3
- package/dist/excalidraw/components/welcome-screen/WelcomeScreen.Center.js +2 -2
- package/dist/excalidraw/components/welcome-screen/WelcomeScreen.Hints.js +3 -3
- package/dist/excalidraw/constants.d.ts +17 -2
- package/dist/excalidraw/constants.js +21 -4
- package/dist/excalidraw/data/reconcile.js +18 -1
- package/dist/excalidraw/data/restore.js +55 -9
- package/dist/excalidraw/data/transform.js +8 -5
- package/dist/excalidraw/element/binding.d.ts +28 -9
- package/dist/excalidraw/element/binding.js +303 -71
- package/dist/excalidraw/element/collision.d.ts +1 -1
- package/dist/excalidraw/element/collision.js +4 -1
- package/dist/excalidraw/element/dragElements.d.ts +2 -2
- package/dist/excalidraw/element/dragElements.js +13 -3
- package/dist/excalidraw/element/embeddable.d.ts +3 -1
- package/dist/excalidraw/element/heading.d.ts +11 -0
- package/dist/excalidraw/element/heading.js +81 -0
- package/dist/excalidraw/element/index.d.ts +1 -1
- package/dist/excalidraw/element/index.js +1 -1
- package/dist/excalidraw/element/linearElementEditor.d.ts +21 -13
- package/dist/excalidraw/element/linearElementEditor.js +133 -56
- package/dist/excalidraw/element/newElement.d.ts +8 -3
- package/dist/excalidraw/element/newElement.js +15 -2
- package/dist/excalidraw/element/resizeElements.d.ts +4 -3
- package/dist/excalidraw/element/resizeElements.js +47 -23
- package/dist/excalidraw/element/routing.d.ts +13 -0
- package/dist/excalidraw/element/routing.js +641 -0
- package/dist/excalidraw/element/textElement.d.ts +3 -26
- package/dist/excalidraw/element/textElement.js +54 -110
- package/dist/excalidraw/element/textWysiwyg.js +39 -47
- package/dist/excalidraw/element/transformHandles.js +7 -2
- package/dist/excalidraw/element/typeChecks.d.ts +5 -2
- package/dist/excalidraw/element/typeChecks.js +17 -0
- package/dist/excalidraw/element/types.d.ts +12 -1
- package/dist/excalidraw/fonts/ExcalidrawFont.d.ts +21 -0
- package/dist/excalidraw/fonts/ExcalidrawFont.js +112 -0
- package/dist/excalidraw/fonts/index.d.ts +58 -0
- package/dist/excalidraw/fonts/index.js +240 -0
- package/dist/excalidraw/fonts/metadata.d.ts +36 -0
- package/dist/excalidraw/fonts/metadata.js +91 -0
- package/dist/excalidraw/fractionalIndex.d.ts +11 -4
- package/dist/excalidraw/fractionalIndex.js +38 -6
- package/dist/excalidraw/frame.d.ts +1 -1
- package/dist/excalidraw/frame.js +3 -3
- package/dist/excalidraw/history.d.ts +4 -3
- package/dist/excalidraw/history.js +8 -8
- package/dist/excalidraw/index.d.ts +1 -1
- package/dist/excalidraw/index.js +3 -3
- package/dist/excalidraw/locales/en.json +18 -4
- package/dist/excalidraw/math.d.ts +43 -0
- package/dist/excalidraw/math.js +110 -0
- package/dist/excalidraw/mermaid.js +4 -3
- package/dist/excalidraw/renderer/interactiveScene.js +33 -17
- package/dist/excalidraw/renderer/renderElement.d.ts +2 -0
- package/dist/excalidraw/renderer/renderElement.js +74 -54
- package/dist/excalidraw/renderer/staticSvgScene.js +2 -1
- package/dist/excalidraw/scene/Scene.js +9 -3
- package/dist/excalidraw/scene/Shape.js +56 -5
- package/dist/excalidraw/scene/comparisons.d.ts +1 -0
- package/dist/excalidraw/scene/comparisons.js +1 -1
- package/dist/excalidraw/scene/export.d.ts +2 -1
- package/dist/excalidraw/scene/export.js +33 -35
- package/dist/excalidraw/scene/types.d.ts +1 -4
- package/dist/excalidraw/shapes.d.ts +8 -0
- package/dist/excalidraw/shapes.js +57 -0
- package/dist/excalidraw/types.d.ts +8 -3
- package/dist/excalidraw/utils.d.ts +11 -1
- package/dist/excalidraw/utils.js +22 -0
- package/dist/prod/CascadiaCode-Regular-TMZI7IJ5.woff2 +0 -0
- package/dist/prod/ComicShanns-Regular-6TOETDFT.woff2 +0 -0
- package/dist/prod/Excalifont-Regular-CPKEUDVM.woff2 +0 -0
- package/dist/prod/LiberationSans-Regular-ZQD73GJM.woff2 +0 -0
- package/dist/prod/Virgil-Regular-YHAB2VGJ.woff2 +0 -0
- package/dist/prod/{en-EB2MBPAV.json → en-YNVBSAIL.json} +18 -4
- package/dist/prod/index.css +1 -1
- package/dist/prod/index.js +49 -53
- package/dist/utils/export.d.ts +2 -1
- package/dist/utils/export.js +2 -1
- package/dist/utils/geometry/geometry.d.ts +2 -1
- package/dist/utils/geometry/geometry.js +5 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/history.ts +9 -2
- package/package.json +2 -2
- package/dist/browser/dev/Cascadia-CYPE3OJC.woff2 +0 -0
- package/dist/browser/dev/Virgil-UZN6MUT6.woff2 +0 -0
- package/dist/browser/dev/excalidraw-assets-dev/chunk-B4UMSLQQ.js.map +0 -7
- package/dist/browser/dev/excalidraw-assets-dev/chunk-EM6LVGFW.js.map +0 -7
- package/dist/browser/dev/excalidraw-assets-dev/dist-6QVAH5JA.js.map +0 -7
- package/dist/browser/prod/Cascadia-CYPE3OJC.woff2 +0 -0
- package/dist/browser/prod/Virgil-UZN6MUT6.woff2 +0 -0
- package/dist/browser/prod/excalidraw-assets/chunk-EGOLGOLD.js +0 -55
- package/dist/browser/prod/excalidraw-assets/dist-567JAXHK.js +0 -7
- package/dist/browser/prod/excalidraw-assets/en-6E7MYLWO.js +0 -1
- package/dist/browser/prod/excalidraw-assets/image-SI7BKULC.js +0 -1
- package/dist/dev/Cascadia-CYPE3OJC.woff2 +0 -0
- package/dist/dev/Virgil-UZN6MUT6.woff2 +0 -0
- package/dist/excalidraw/scene/Fonts.d.ts +0 -19
- package/dist/excalidraw/scene/Fonts.js +0 -66
- package/dist/prod/Cascadia-CYPE3OJC.woff2 +0 -0
- package/dist/prod/Virgil-UZN6MUT6.woff2 +0 -0
- /package/dist/browser/dev/{Assistant-Bold-ZDZZ6JHA.woff2 → excalidraw-assets-dev/Assistant-Bold-ZDZZ6JHA.woff2} +0 -0
- /package/dist/browser/dev/{Assistant-Medium-DZ25RZU3.woff2 → excalidraw-assets-dev/Assistant-Medium-DZ25RZU3.woff2} +0 -0
- /package/dist/browser/dev/{Assistant-Regular-PLF2XOGW.woff2 → excalidraw-assets-dev/Assistant-Regular-PLF2XOGW.woff2} +0 -0
- /package/dist/browser/dev/{Assistant-SemiBold-CZ5MX6FK.woff2 → excalidraw-assets-dev/Assistant-SemiBold-CZ5MX6FK.woff2} +0 -0
- /package/dist/browser/dev/excalidraw-assets-dev/{en-AZFA5HJJ.js.map → en-XV7OZCPP.js.map} +0 -0
- /package/dist/browser/dev/excalidraw-assets-dev/{image-V7E6IT6R.js.map → image-77HZYGLG.js.map} +0 -0
- /package/dist/browser/prod/{Assistant-Bold-ZDZZ6JHA.woff2 → excalidraw-assets/Assistant-Bold-ZDZZ6JHA.woff2} +0 -0
- /package/dist/browser/prod/{Assistant-Medium-DZ25RZU3.woff2 → excalidraw-assets/Assistant-Medium-DZ25RZU3.woff2} +0 -0
- /package/dist/browser/prod/{Assistant-Regular-PLF2XOGW.woff2 → excalidraw-assets/Assistant-Regular-PLF2XOGW.woff2} +0 -0
- /package/dist/browser/prod/{Assistant-SemiBold-CZ5MX6FK.woff2 → excalidraw-assets/Assistant-SemiBold-CZ5MX6FK.woff2} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { ElementsMap, ExcalidrawElement, ExcalidrawElementType, ExcalidrawTextContainer, ExcalidrawTextElement, ExcalidrawTextElementWithContainer,
|
|
1
|
+
import type { ElementsMap, ExcalidrawElement, ExcalidrawElementType, ExcalidrawTextContainer, ExcalidrawTextElement, ExcalidrawTextElementWithContainer, FontString, NonDeletedExcalidrawElement } from "./types";
|
|
2
2
|
import type { MaybeTransformHandleType } from "./transformHandles";
|
|
3
3
|
import type { AppState } from "../types";
|
|
4
|
-
import type { ExtractSetType
|
|
4
|
+
import type { ExtractSetType } from "../utility-types";
|
|
5
5
|
export declare const normalizeText: (text: string) => string;
|
|
6
6
|
export declare const redrawTextBoundingBox: (textElement: ExcalidrawTextElement, container: ExcalidrawElement | null, elementsMap: ElementsMap, informMutation?: boolean) => void;
|
|
7
7
|
export declare const bindTextToShapeAfterDuplication: (newElements: ExcalidrawElement[], oldElements: ExcalidrawElement[], oldIdToDuplicatedId: Map<ExcalidrawElement["id"], ExcalidrawElement["id"]>) => void;
|
|
@@ -26,12 +26,8 @@ export declare const detectLineHeight: (textElement: ExcalidrawTextElement) => n
|
|
|
26
26
|
* aligning with the W3C spec.
|
|
27
27
|
*/
|
|
28
28
|
export declare const getLineHeightInPx: (fontSize: ExcalidrawTextElement["fontSize"], lineHeight: ExcalidrawTextElement["lineHeight"]) => number;
|
|
29
|
-
/**
|
|
30
|
-
* Calculates vertical offset for a text with alphabetic baseline.
|
|
31
|
-
*/
|
|
32
|
-
export declare const getVerticalOffset: (fontFamily: ExcalidrawTextElement["fontFamily"], fontSize: ExcalidrawTextElement["fontSize"], lineHeightPx: number) => number;
|
|
33
29
|
export declare const getApproxMinLineHeight: (fontSize: ExcalidrawTextElement["fontSize"], lineHeight: ExcalidrawTextElement["lineHeight"]) => number;
|
|
34
|
-
export declare const getTextWidth: (text: string, font: FontString) => number;
|
|
30
|
+
export declare const getTextWidth: (text: string, font: FontString, forceAdvanceWidth?: true) => number;
|
|
35
31
|
export declare const getTextHeight: (text: string, fontSize: number, lineHeight: ExcalidrawTextElement["lineHeight"]) => number;
|
|
36
32
|
export declare const parseTokens: (text: string) => string[];
|
|
37
33
|
export declare const wrapText: (text: string, font: FontString, maxWidth: number) => string;
|
|
@@ -42,7 +38,6 @@ export declare const charWidth: {
|
|
|
42
38
|
export declare const getApproxMinLineWidth: (font: FontString, lineHeight: ExcalidrawTextElement["lineHeight"]) => number;
|
|
43
39
|
export declare const getMinCharWidth: (font: FontString) => number;
|
|
44
40
|
export declare const getMaxCharWidth: (font: FontString) => number;
|
|
45
|
-
export declare const getApproxCharsToFitInWidth: (font: FontString, width: number) => number;
|
|
46
41
|
export declare const getBoundTextElementId: (container: ExcalidrawElement | null) => string | null;
|
|
47
42
|
export declare const getBoundTextElement: (element: ExcalidrawElement | null, elementsMap: ElementsMap) => ExcalidrawTextElementWithContainer | null;
|
|
48
43
|
export declare const getContainerElement: (element: ExcalidrawTextElement | null, elementsMap: ElementsMap) => ExcalidrawTextContainer | null;
|
|
@@ -69,23 +64,5 @@ export declare const computeContainerDimensionForBoundText: (dimension: number,
|
|
|
69
64
|
export declare const getBoundTextMaxWidth: (container: ExcalidrawElement, boundTextElement: ExcalidrawTextElement | null) => number;
|
|
70
65
|
export declare const getBoundTextMaxHeight: (container: ExcalidrawElement, boundTextElement: ExcalidrawTextElementWithContainer) => number;
|
|
71
66
|
export declare const isMeasureTextSupported: () => boolean;
|
|
72
|
-
/** OS/2 sTypoAscender, https://learn.microsoft.com/en-us/typography/opentype/spec/os2#stypoascender */
|
|
73
|
-
type sTypoAscender = number & MakeBrand<"sTypoAscender">;
|
|
74
|
-
/** OS/2 sTypoDescender, https://learn.microsoft.com/en-us/typography/opentype/spec/os2#stypodescender */
|
|
75
|
-
type sTypoDescender = number & MakeBrand<"sTypoDescender">;
|
|
76
|
-
/**
|
|
77
|
-
* Hardcoded metrics for default fonts, read by https://opentype.js.org/font-inspector.html.
|
|
78
|
-
* For custom fonts, read these metrics from OS/2 table and extend this object.
|
|
79
|
-
*
|
|
80
|
-
* WARN: opentype does NOT open WOFF2 correctly, make sure to convert WOFF2 to TTF first.
|
|
81
|
-
*/
|
|
82
|
-
export declare const FONT_METRICS: Record<number, {
|
|
83
|
-
unitsPerEm: number;
|
|
84
|
-
ascender: sTypoAscender;
|
|
85
|
-
descender: sTypoDescender;
|
|
86
|
-
}>;
|
|
87
|
-
export declare const getDefaultLineHeight: (fontFamily: FontFamilyValues) => number & {
|
|
88
|
-
_brand: "unitlessLineHeight";
|
|
89
|
-
};
|
|
90
67
|
export declare const getMinTextElementWidth: (font: FontString, lineHeight: ExcalidrawTextElement["lineHeight"]) => number;
|
|
91
68
|
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
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,
|
|
3
|
+
import { ARROW_LABEL_FONT_SIZE_TO_MIN_WIDTH_RATIO, ARROW_LABEL_WIDTH_FRACTION, BOUND_TEXT_PADDING, DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE, TEXT_ALIGN, VERTICAL_ALIGN, } from "../constants";
|
|
4
4
|
import { isTextElement } from ".";
|
|
5
5
|
import { isBoundToContainer, isArrowElement } from "./typeChecks";
|
|
6
6
|
import { LinearElementEditor } from "./linearElementEditor";
|
|
@@ -201,41 +201,58 @@ export const detectLineHeight = (textElement) => {
|
|
|
201
201
|
export const getLineHeightInPx = (fontSize, lineHeight) => {
|
|
202
202
|
return fontSize * lineHeight;
|
|
203
203
|
};
|
|
204
|
-
/**
|
|
205
|
-
* Calculates vertical offset for a text with alphabetic baseline.
|
|
206
|
-
*/
|
|
207
|
-
export const getVerticalOffset = (fontFamily, fontSize, lineHeightPx) => {
|
|
208
|
-
const { unitsPerEm, ascender, descender } = FONT_METRICS[fontFamily] || FONT_METRICS[FONT_FAMILY.Helvetica];
|
|
209
|
-
const fontSizeEm = fontSize / unitsPerEm;
|
|
210
|
-
const lineGap = lineHeightPx - fontSizeEm * ascender + fontSizeEm * descender;
|
|
211
|
-
const verticalOffset = fontSizeEm * ascender + lineGap;
|
|
212
|
-
return verticalOffset;
|
|
213
|
-
};
|
|
214
204
|
// FIXME rename to getApproxMinContainerHeight
|
|
215
205
|
export const getApproxMinLineHeight = (fontSize, lineHeight) => {
|
|
216
206
|
return getLineHeightInPx(fontSize, lineHeight) + BOUND_TEXT_PADDING * 2;
|
|
217
207
|
};
|
|
218
208
|
let canvas;
|
|
219
|
-
|
|
209
|
+
/**
|
|
210
|
+
* @param forceAdvanceWidth use to force retrieve the "advance width" ~ `metrics.width`, instead of the actual boundind box width.
|
|
211
|
+
*
|
|
212
|
+
* > The advance width is the distance between the glyph's initial pen position and the next glyph's initial pen position.
|
|
213
|
+
*
|
|
214
|
+
* We need to use the advance width as that's the closest thing to the browser wrapping algo, hence using it for:
|
|
215
|
+
* - text wrapping
|
|
216
|
+
* - wysiwyg editor (+padding)
|
|
217
|
+
*
|
|
218
|
+
* Everything else should be based on the actual bounding box width.
|
|
219
|
+
*
|
|
220
|
+
* `Math.ceil` of the final width adds additional buffer which stabilizes slight wrapping incosistencies.
|
|
221
|
+
*/
|
|
222
|
+
const getLineWidth = (text, font, forceAdvanceWidth) => {
|
|
220
223
|
if (!canvas) {
|
|
221
224
|
canvas = document.createElement("canvas");
|
|
222
225
|
}
|
|
223
226
|
const canvas2dContext = canvas.getContext("2d");
|
|
224
227
|
canvas2dContext.font = font;
|
|
225
|
-
const
|
|
228
|
+
const metrics = canvas2dContext.measureText(text);
|
|
229
|
+
const advanceWidth = metrics.width;
|
|
230
|
+
// retrieve the actual bounding box width if these metrics are available (as of now > 95% coverage)
|
|
231
|
+
if (!forceAdvanceWidth &&
|
|
232
|
+
window.TextMetrics &&
|
|
233
|
+
"actualBoundingBoxLeft" in window.TextMetrics.prototype &&
|
|
234
|
+
"actualBoundingBoxRight" in window.TextMetrics.prototype) {
|
|
235
|
+
// could be negative, therefore getting the absolute value
|
|
236
|
+
const actualWidth = Math.abs(metrics.actualBoundingBoxLeft) +
|
|
237
|
+
Math.abs(metrics.actualBoundingBoxRight);
|
|
238
|
+
// fallback to advance width if the actual width is zero, i.e. on text editing start
|
|
239
|
+
// or when actual width does not respect whitespace chars, i.e. spaces
|
|
240
|
+
// otherwise actual width should always be bigger
|
|
241
|
+
return Math.max(actualWidth, advanceWidth);
|
|
242
|
+
}
|
|
226
243
|
// since in test env the canvas measureText algo
|
|
227
244
|
// doesn't measure text and instead just returns number of
|
|
228
245
|
// characters hence we assume that each letteris 10px
|
|
229
246
|
if (isTestEnv()) {
|
|
230
|
-
return
|
|
247
|
+
return advanceWidth * 10;
|
|
231
248
|
}
|
|
232
|
-
return
|
|
249
|
+
return advanceWidth;
|
|
233
250
|
};
|
|
234
|
-
export const getTextWidth = (text, font) => {
|
|
251
|
+
export const getTextWidth = (text, font, forceAdvanceWidth) => {
|
|
235
252
|
const lines = splitIntoLines(text);
|
|
236
253
|
let width = 0;
|
|
237
254
|
lines.forEach((line) => {
|
|
238
|
-
width = Math.max(width, getLineWidth(line, font));
|
|
255
|
+
width = Math.max(width, getLineWidth(line, font, forceAdvanceWidth));
|
|
239
256
|
});
|
|
240
257
|
return width;
|
|
241
258
|
};
|
|
@@ -269,7 +286,7 @@ export const wrapText = (text, font, maxWidth) => {
|
|
|
269
286
|
}
|
|
270
287
|
const lines = [];
|
|
271
288
|
const originalLines = text.split("\n");
|
|
272
|
-
const
|
|
289
|
+
const spaceAdvanceWidth = getLineWidth(" ", font, true);
|
|
273
290
|
let currentLine = "";
|
|
274
291
|
let currentLineWidthTillNow = 0;
|
|
275
292
|
const push = (str) => {
|
|
@@ -281,18 +298,18 @@ export const wrapText = (text, font, maxWidth) => {
|
|
|
281
298
|
currentLine = "";
|
|
282
299
|
currentLineWidthTillNow = 0;
|
|
283
300
|
};
|
|
284
|
-
|
|
285
|
-
const currentLineWidth =
|
|
301
|
+
for (const originalLine of originalLines) {
|
|
302
|
+
const currentLineWidth = getLineWidth(originalLine, font, true);
|
|
286
303
|
// Push the line if its <= maxWidth
|
|
287
304
|
if (currentLineWidth <= maxWidth) {
|
|
288
305
|
lines.push(originalLine);
|
|
289
|
-
|
|
306
|
+
continue;
|
|
290
307
|
}
|
|
291
308
|
const words = parseTokens(originalLine);
|
|
292
309
|
resetParams();
|
|
293
310
|
let index = 0;
|
|
294
311
|
while (index < words.length) {
|
|
295
|
-
const currentWordWidth = getLineWidth(words[index], font);
|
|
312
|
+
const currentWordWidth = getLineWidth(words[index], font, true);
|
|
296
313
|
// This will only happen when single word takes entire width
|
|
297
314
|
if (currentWordWidth === maxWidth) {
|
|
298
315
|
push(words[index]);
|
|
@@ -306,20 +323,24 @@ export const wrapText = (text, font, maxWidth) => {
|
|
|
306
323
|
resetParams();
|
|
307
324
|
while (words[index].length > 0) {
|
|
308
325
|
const currentChar = String.fromCodePoint(words[index].codePointAt(0));
|
|
309
|
-
const
|
|
310
|
-
|
|
326
|
+
const line = currentLine + currentChar;
|
|
327
|
+
// use advance width instead of the actual width as it's closest to the browser wapping algo
|
|
328
|
+
// use width of the whole line instead of calculating individual chars to accomodate for kerning
|
|
329
|
+
const lineAdvanceWidth = getLineWidth(line, font, true);
|
|
330
|
+
const charAdvanceWidth = charWidth.calculate(currentChar, font);
|
|
331
|
+
currentLineWidthTillNow = lineAdvanceWidth;
|
|
311
332
|
words[index] = words[index].slice(currentChar.length);
|
|
312
333
|
if (currentLineWidthTillNow >= maxWidth) {
|
|
313
334
|
push(currentLine);
|
|
314
335
|
currentLine = currentChar;
|
|
315
|
-
currentLineWidthTillNow =
|
|
336
|
+
currentLineWidthTillNow = charAdvanceWidth;
|
|
316
337
|
}
|
|
317
338
|
else {
|
|
318
|
-
currentLine
|
|
339
|
+
currentLine = line;
|
|
319
340
|
}
|
|
320
341
|
}
|
|
321
342
|
// push current line if appending space exceeds max width
|
|
322
|
-
if (currentLineWidthTillNow +
|
|
343
|
+
if (currentLineWidthTillNow + spaceAdvanceWidth >= maxWidth) {
|
|
323
344
|
push(currentLine);
|
|
324
345
|
resetParams();
|
|
325
346
|
// space needs to be appended before next word
|
|
@@ -329,7 +350,7 @@ export const wrapText = (text, font, maxWidth) => {
|
|
|
329
350
|
}
|
|
330
351
|
else if (!currentLine.endsWith("-")) {
|
|
331
352
|
currentLine += " ";
|
|
332
|
-
currentLineWidthTillNow +=
|
|
353
|
+
currentLineWidthTillNow += spaceAdvanceWidth;
|
|
333
354
|
}
|
|
334
355
|
index++;
|
|
335
356
|
}
|
|
@@ -337,7 +358,7 @@ export const wrapText = (text, font, maxWidth) => {
|
|
|
337
358
|
// Start appending words in a line till max width reached
|
|
338
359
|
while (currentLineWidthTillNow < maxWidth && index < words.length) {
|
|
339
360
|
const word = words[index];
|
|
340
|
-
currentLineWidthTillNow = getLineWidth(currentLine + word, font);
|
|
361
|
+
currentLineWidthTillNow = getLineWidth(currentLine + word, font, true);
|
|
341
362
|
if (currentLineWidthTillNow > maxWidth) {
|
|
342
363
|
push(currentLine);
|
|
343
364
|
resetParams();
|
|
@@ -352,7 +373,7 @@ export const wrapText = (text, font, maxWidth) => {
|
|
|
352
373
|
currentLine += " ";
|
|
353
374
|
}
|
|
354
375
|
// Push the word if appending space exceeds max width
|
|
355
|
-
if (currentLineWidthTillNow +
|
|
376
|
+
if (currentLineWidthTillNow + spaceAdvanceWidth >= maxWidth) {
|
|
356
377
|
if (shouldAppendSpace) {
|
|
357
378
|
lines.push(currentLine.slice(0, -1));
|
|
358
379
|
}
|
|
@@ -370,7 +391,7 @@ export const wrapText = (text, font, maxWidth) => {
|
|
|
370
391
|
currentLine = currentLine.slice(0, -1);
|
|
371
392
|
push(currentLine);
|
|
372
393
|
}
|
|
373
|
-
}
|
|
394
|
+
}
|
|
374
395
|
return lines.join("\n");
|
|
375
396
|
};
|
|
376
397
|
export const charWidth = (() => {
|
|
@@ -381,7 +402,7 @@ export const charWidth = (() => {
|
|
|
381
402
|
cachedCharWidth[font] = [];
|
|
382
403
|
}
|
|
383
404
|
if (!cachedCharWidth[font][ascii]) {
|
|
384
|
-
const width = getLineWidth(char, font);
|
|
405
|
+
const width = getLineWidth(char, font, true);
|
|
385
406
|
cachedCharWidth[font][ascii] = width;
|
|
386
407
|
}
|
|
387
408
|
return cachedCharWidth[font][ascii];
|
|
@@ -420,32 +441,9 @@ export const getMaxCharWidth = (font) => {
|
|
|
420
441
|
const cacheWithOutEmpty = cache.filter((val) => val !== undefined);
|
|
421
442
|
return Math.max(...cacheWithOutEmpty);
|
|
422
443
|
};
|
|
423
|
-
export const getApproxCharsToFitInWidth = (font, width) => {
|
|
424
|
-
// Generally lower case is used so converting to lower case
|
|
425
|
-
const dummyText = DUMMY_TEXT.toLocaleLowerCase();
|
|
426
|
-
const batchLength = 6;
|
|
427
|
-
let index = 0;
|
|
428
|
-
let widthTillNow = 0;
|
|
429
|
-
let str = "";
|
|
430
|
-
while (widthTillNow <= width) {
|
|
431
|
-
const batch = dummyText.substr(index, index + batchLength);
|
|
432
|
-
str += batch;
|
|
433
|
-
widthTillNow += getLineWidth(str, font);
|
|
434
|
-
if (index === dummyText.length - 1) {
|
|
435
|
-
index = 0;
|
|
436
|
-
}
|
|
437
|
-
index = index + batchLength;
|
|
438
|
-
}
|
|
439
|
-
while (widthTillNow > width) {
|
|
440
|
-
str = str.substr(0, str.length - 1);
|
|
441
|
-
widthTillNow = getLineWidth(str, font);
|
|
442
|
-
}
|
|
443
|
-
return str.length;
|
|
444
|
-
};
|
|
445
444
|
export const getBoundTextElementId = (container) => {
|
|
446
445
|
return container?.boundElements?.length
|
|
447
|
-
? container?.boundElements?.
|
|
448
|
-
null
|
|
446
|
+
? container?.boundElements?.find((ele) => ele.type === "text")?.id || null
|
|
449
447
|
: null;
|
|
450
448
|
};
|
|
451
449
|
export const getBoundTextElement = (element, elementsMap) => {
|
|
@@ -612,60 +610,6 @@ export const isMeasureTextSupported = () => {
|
|
|
612
610
|
}));
|
|
613
611
|
return width > 0;
|
|
614
612
|
};
|
|
615
|
-
/**
|
|
616
|
-
* Unitless line height
|
|
617
|
-
*
|
|
618
|
-
* In previous versions we used `normal` line height, which browsers interpret
|
|
619
|
-
* differently, and based on font-family and font-size.
|
|
620
|
-
*
|
|
621
|
-
* To make line heights consistent across browsers we hardcode the values for
|
|
622
|
-
* each of our fonts based on most common average line-heights.
|
|
623
|
-
* See https://github.com/excalidraw/excalidraw/pull/6360#issuecomment-1477635971
|
|
624
|
-
* where the values come from.
|
|
625
|
-
*/
|
|
626
|
-
const DEFAULT_LINE_HEIGHT = {
|
|
627
|
-
// ~1.25 is the average for Virgil in WebKit and Blink.
|
|
628
|
-
// Gecko (FF) uses ~1.28.
|
|
629
|
-
[FONT_FAMILY.Virgil]: 1.25,
|
|
630
|
-
// ~1.15 is the average for Helvetica in WebKit and Blink.
|
|
631
|
-
[FONT_FAMILY.Helvetica]: 1.15,
|
|
632
|
-
// ~1.2 is the average for Cascadia in WebKit and Blink, and kinda Gecko too
|
|
633
|
-
[FONT_FAMILY.Cascadia]: 1.2,
|
|
634
|
-
};
|
|
635
|
-
/**
|
|
636
|
-
* Hardcoded metrics for default fonts, read by https://opentype.js.org/font-inspector.html.
|
|
637
|
-
* For custom fonts, read these metrics from OS/2 table and extend this object.
|
|
638
|
-
*
|
|
639
|
-
* WARN: opentype does NOT open WOFF2 correctly, make sure to convert WOFF2 to TTF first.
|
|
640
|
-
*/
|
|
641
|
-
export const FONT_METRICS = {
|
|
642
|
-
[FONT_FAMILY.Virgil]: {
|
|
643
|
-
unitsPerEm: 1000,
|
|
644
|
-
ascender: 886,
|
|
645
|
-
descender: -374,
|
|
646
|
-
},
|
|
647
|
-
[FONT_FAMILY.Helvetica]: {
|
|
648
|
-
unitsPerEm: 2048,
|
|
649
|
-
ascender: 1577,
|
|
650
|
-
descender: -471,
|
|
651
|
-
},
|
|
652
|
-
[FONT_FAMILY.Cascadia]: {
|
|
653
|
-
unitsPerEm: 2048,
|
|
654
|
-
ascender: 1977,
|
|
655
|
-
descender: -480,
|
|
656
|
-
},
|
|
657
|
-
[FONT_FAMILY.Assistant]: {
|
|
658
|
-
unitsPerEm: 1000,
|
|
659
|
-
ascender: 1021,
|
|
660
|
-
descender: -287,
|
|
661
|
-
},
|
|
662
|
-
};
|
|
663
|
-
export const getDefaultLineHeight = (fontFamily) => {
|
|
664
|
-
if (fontFamily in DEFAULT_LINE_HEIGHT) {
|
|
665
|
-
return DEFAULT_LINE_HEIGHT[fontFamily];
|
|
666
|
-
}
|
|
667
|
-
return DEFAULT_LINE_HEIGHT[DEFAULT_FONT_FAMILY];
|
|
668
|
-
};
|
|
669
613
|
export const getMinTextElementWidth = (font, lineHeight) => {
|
|
670
614
|
return measureText("", font, lineHeight).width + BOUND_TEXT_PADDING * 2;
|
|
671
615
|
};
|
|
@@ -2,7 +2,7 @@ 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 } from "../constants";
|
|
5
|
+
import { CLASSES, isSafari } from "../constants";
|
|
6
6
|
import { bumpVersion, mutateElement } from "./mutateElement";
|
|
7
7
|
import { getBoundTextElementId, getContainerElement, getTextElementAngle, getTextWidth, normalizeText, redrawTextBoundingBox, wrapText, getBoundTextMaxHeight, getBoundTextMaxWidth, computeContainerDimensionForBoundText, computeBoundTextPosition, getBoundTextElement, } from "./textElement";
|
|
8
8
|
import { actionDecreaseFontSize, actionIncreaseFontSize, } from "../actions/actionProperties";
|
|
@@ -50,10 +50,12 @@ export const textWysiwyg = ({ id, onChange, onSubmit, getViewportCoords, element
|
|
|
50
50
|
let coordX = updatedTextElement.x;
|
|
51
51
|
let coordY = updatedTextElement.y;
|
|
52
52
|
const container = getContainerElement(updatedTextElement, app.scene.getNonDeletedElementsMap());
|
|
53
|
+
let width = updatedTextElement.width;
|
|
54
|
+
// set to element height by default since that's
|
|
55
|
+
// what is going to be used for unbounded text
|
|
56
|
+
let height = updatedTextElement.height;
|
|
53
57
|
let maxWidth = updatedTextElement.width;
|
|
54
58
|
let maxHeight = updatedTextElement.height;
|
|
55
|
-
let textElementWidth = updatedTextElement.width;
|
|
56
|
-
const textElementHeight = updatedTextElement.height;
|
|
57
59
|
if (container && updatedTextElement.containerId) {
|
|
58
60
|
if (isArrowElement(container)) {
|
|
59
61
|
const boundTextCoords = LinearElementEditor.getBoundTextElementPosition(container, updatedTextElement, elementsMap);
|
|
@@ -74,8 +76,8 @@ export const textWysiwyg = ({ id, onChange, onSubmit, getViewportCoords, element
|
|
|
74
76
|
maxWidth = getBoundTextMaxWidth(container, updatedTextElement);
|
|
75
77
|
maxHeight = getBoundTextMaxHeight(container, updatedTextElement);
|
|
76
78
|
// autogrow container height if text exceeds
|
|
77
|
-
if (!isArrowElement(container) &&
|
|
78
|
-
const targetContainerHeight = computeContainerDimensionForBoundText(
|
|
79
|
+
if (!isArrowElement(container) && height > maxHeight) {
|
|
80
|
+
const targetContainerHeight = computeContainerDimensionForBoundText(height, container.type);
|
|
79
81
|
mutateElement(container, { height: targetContainerHeight });
|
|
80
82
|
return;
|
|
81
83
|
}
|
|
@@ -84,8 +86,8 @@ export const textWysiwyg = ({ id, onChange, onSubmit, getViewportCoords, element
|
|
|
84
86
|
// is reached when text is removed
|
|
85
87
|
!isArrowElement(container) &&
|
|
86
88
|
container.height > originalContainerData.height &&
|
|
87
|
-
|
|
88
|
-
const targetContainerHeight = computeContainerDimensionForBoundText(
|
|
89
|
+
height < maxHeight) {
|
|
90
|
+
const targetContainerHeight = computeContainerDimensionForBoundText(height, container.type);
|
|
89
91
|
mutateElement(container, { height: targetContainerHeight });
|
|
90
92
|
}
|
|
91
93
|
else {
|
|
@@ -109,22 +111,30 @@ export const textWysiwyg = ({ id, onChange, onSubmit, getViewportCoords, element
|
|
|
109
111
|
}
|
|
110
112
|
if (!container) {
|
|
111
113
|
maxWidth = (appState.width - 8 - viewportX) / appState.zoom.value;
|
|
112
|
-
|
|
114
|
+
width = Math.min(width, maxWidth);
|
|
113
115
|
}
|
|
114
116
|
else {
|
|
115
|
-
|
|
117
|
+
width += 0.5;
|
|
116
118
|
}
|
|
119
|
+
// add 5% buffer otherwise it causes wysiwyg to jump
|
|
120
|
+
height *= 1.05;
|
|
121
|
+
const font = getFontString(updatedTextElement);
|
|
122
|
+
// adding left and right padding buffer, so that browser does not cut the glyphs (does not work in Safari)
|
|
123
|
+
const padding = !isSafari
|
|
124
|
+
? Math.ceil(updatedTextElement.fontSize / 2)
|
|
125
|
+
: 0;
|
|
117
126
|
// Make sure text editor height doesn't go beyond viewport
|
|
118
127
|
const editorMaxHeight = (appState.height - viewportY) / appState.zoom.value;
|
|
119
128
|
Object.assign(editable.style, {
|
|
120
|
-
font
|
|
129
|
+
font,
|
|
121
130
|
// must be defined *after* font ¯\_(ツ)_/¯
|
|
122
131
|
lineHeight: updatedTextElement.lineHeight,
|
|
123
|
-
width: `${
|
|
124
|
-
height: `${
|
|
125
|
-
left: `${viewportX}px`,
|
|
132
|
+
width: `${width}px`,
|
|
133
|
+
height: `${height}px`,
|
|
134
|
+
left: `${viewportX - padding}px`,
|
|
126
135
|
top: `${viewportY}px`,
|
|
127
|
-
transform: getTransform(
|
|
136
|
+
transform: getTransform(width, height, getTextElementAngle(updatedTextElement, container), appState, maxWidth, editorMaxHeight),
|
|
137
|
+
padding: `0 ${padding}px`,
|
|
128
138
|
textAlign,
|
|
129
139
|
verticalAlign,
|
|
130
140
|
color: updatedTextElement.strokeColor,
|
|
@@ -160,7 +170,6 @@ export const textWysiwyg = ({ id, onChange, onSubmit, getViewportCoords, element
|
|
|
160
170
|
minHeight: "1em",
|
|
161
171
|
backfaceVisibility: "hidden",
|
|
162
172
|
margin: 0,
|
|
163
|
-
padding: 0,
|
|
164
173
|
border: 0,
|
|
165
174
|
outline: 0,
|
|
166
175
|
resize: "none",
|
|
@@ -194,7 +203,7 @@ export const textWysiwyg = ({ id, onChange, onSubmit, getViewportCoords, element
|
|
|
194
203
|
if (container) {
|
|
195
204
|
const boundTextElement = getBoundTextElement(container, app.scene.getNonDeletedElementsMap());
|
|
196
205
|
const wrappedText = wrapText(`${editable.value}${data}`, font, getBoundTextMaxWidth(container, boundTextElement));
|
|
197
|
-
const width = getTextWidth(wrappedText, font);
|
|
206
|
+
const width = getTextWidth(wrappedText, font, true);
|
|
198
207
|
editable.style.width = `${width}px`;
|
|
199
208
|
}
|
|
200
209
|
};
|
|
@@ -320,8 +329,10 @@ export const textWysiwyg = ({ id, onChange, onSubmit, getViewportCoords, element
|
|
|
320
329
|
.reverse();
|
|
321
330
|
};
|
|
322
331
|
const stopEvent = (event) => {
|
|
323
|
-
event.
|
|
324
|
-
|
|
332
|
+
if (event.target instanceof HTMLCanvasElement) {
|
|
333
|
+
event.preventDefault();
|
|
334
|
+
event.stopPropagation();
|
|
335
|
+
}
|
|
325
336
|
};
|
|
326
337
|
// using a state variable instead of passing it to the handleSubmit callback
|
|
327
338
|
// so that we don't need to create separate a callback for event handlers
|
|
@@ -393,45 +404,26 @@ export const textWysiwyg = ({ id, onChange, onSubmit, getViewportCoords, element
|
|
|
393
404
|
// Also to handle cases such as picking a color which would trigger a blur
|
|
394
405
|
// in that same tick.
|
|
395
406
|
const target = event?.target;
|
|
396
|
-
const
|
|
397
|
-
target.classList.contains("
|
|
407
|
+
const isPropertiesTrigger = target instanceof HTMLElement &&
|
|
408
|
+
target.classList.contains("properties-trigger");
|
|
398
409
|
setTimeout(() => {
|
|
399
410
|
editable.onblur = handleSubmit;
|
|
400
|
-
if (isTargetPickerTrigger) {
|
|
401
|
-
const callback = (mutationList, observer) => {
|
|
402
|
-
const radixIsRemoved = mutationList.find((mutation) => mutation.removedNodes.length > 0 &&
|
|
403
|
-
mutation.removedNodes[0].dataset
|
|
404
|
-
?.radixPopperContentWrapper !== undefined);
|
|
405
|
-
if (radixIsRemoved) {
|
|
406
|
-
// should work without this in theory
|
|
407
|
-
// and i think it does actually but radix probably somewhere,
|
|
408
|
-
// somehow sets the focus elsewhere
|
|
409
|
-
setTimeout(() => {
|
|
410
|
-
editable.focus();
|
|
411
|
-
});
|
|
412
|
-
observer.disconnect();
|
|
413
|
-
}
|
|
414
|
-
};
|
|
415
|
-
const observer = new MutationObserver(callback);
|
|
416
|
-
observer.observe(document.querySelector(".excalidraw-container"), {
|
|
417
|
-
childList: true,
|
|
418
|
-
});
|
|
419
|
-
}
|
|
420
411
|
// case: clicking on the same property → no change → no update → no focus
|
|
421
|
-
if (!
|
|
412
|
+
if (!isPropertiesTrigger) {
|
|
422
413
|
editable.focus();
|
|
423
414
|
}
|
|
424
415
|
});
|
|
425
416
|
};
|
|
426
417
|
// prevent blur when changing properties from the menu
|
|
427
418
|
const onPointerDown = (event) => {
|
|
428
|
-
const
|
|
429
|
-
|
|
419
|
+
const target = event?.target;
|
|
420
|
+
const isPropertiesTrigger = target instanceof HTMLElement &&
|
|
421
|
+
target.classList.contains("properties-trigger");
|
|
430
422
|
if (((event.target instanceof HTMLElement ||
|
|
431
423
|
event.target instanceof SVGElement) &&
|
|
432
424
|
event.target.closest(`.${CLASSES.SHAPE_ACTIONS_MENU}`) &&
|
|
433
425
|
!isWritableElement(event.target)) ||
|
|
434
|
-
|
|
426
|
+
isPropertiesTrigger) {
|
|
435
427
|
editable.onblur = null;
|
|
436
428
|
window.addEventListener("pointerup", bindBlurEvent);
|
|
437
429
|
// handle edge-case where pointerup doesn't fire e.g. due to user
|
|
@@ -439,7 +431,7 @@ export const textWysiwyg = ({ id, onChange, onSubmit, getViewportCoords, element
|
|
|
439
431
|
window.addEventListener("blur", handleSubmit);
|
|
440
432
|
}
|
|
441
433
|
else if (event.target instanceof HTMLElement &&
|
|
442
|
-
|
|
434
|
+
event.target instanceof HTMLCanvasElement &&
|
|
443
435
|
// Vitest simply ignores stopPropagation, capture-mode, or rAF
|
|
444
436
|
// so without introducing crazier hacks, nothing we can do
|
|
445
437
|
!isTestEnv()) {
|
|
@@ -457,8 +449,8 @@ export const textWysiwyg = ({ id, onChange, onSubmit, getViewportCoords, element
|
|
|
457
449
|
// handle updates of textElement properties of editing element
|
|
458
450
|
const unbindUpdate = Scene.getScene(element).onUpdate(() => {
|
|
459
451
|
updateWysiwygStyle();
|
|
460
|
-
const
|
|
461
|
-
if (!
|
|
452
|
+
const isPopupOpened = !!document.activeElement?.closest(".properties-content");
|
|
453
|
+
if (!isPopupOpened) {
|
|
462
454
|
editable.focus();
|
|
463
455
|
}
|
|
464
456
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getElementAbsoluteCoords } from "./bounds";
|
|
2
2
|
import { rotate } from "../math";
|
|
3
|
-
import { isFrameLikeElement, isLinearElement } from "./typeChecks";
|
|
3
|
+
import { isElbowArrow, isFrameLikeElement, isLinearElement, } from "./typeChecks";
|
|
4
4
|
import { DEFAULT_TRANSFORM_HANDLE_SPACING, isAndroid, isIOS, } from "../constants";
|
|
5
5
|
const transformHandleSizes = {
|
|
6
6
|
mouse: 8,
|
|
@@ -116,7 +116,9 @@ export const getTransformHandles = (element, zoom, elementsMap, pointerType = "m
|
|
|
116
116
|
// so that when locked element is selected (especially when you toggle lock
|
|
117
117
|
// via keyboard) the locked element is visually distinct, indicating
|
|
118
118
|
// you can't move/resize
|
|
119
|
-
if (element.locked
|
|
119
|
+
if (element.locked ||
|
|
120
|
+
// Elbow arrows cannot be rotated
|
|
121
|
+
isElbowArrow(element)) {
|
|
120
122
|
return {};
|
|
121
123
|
}
|
|
122
124
|
if (element.type === "freedraw" || isLinearElement(element)) {
|
|
@@ -159,6 +161,9 @@ export const shouldShowBoundingBox = (elements, appState) => {
|
|
|
159
161
|
return true;
|
|
160
162
|
}
|
|
161
163
|
const element = elements[0];
|
|
164
|
+
if (isElbowArrow(element)) {
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
162
167
|
if (!isLinearElement(element)) {
|
|
163
168
|
return true;
|
|
164
169
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ElementOrToolType } from "../types";
|
|
2
2
|
import type { MarkNonNullable } from "../utility-types";
|
|
3
|
-
import type { ExcalidrawElement, ExcalidrawTextElement, ExcalidrawEmbeddableElement, ExcalidrawLinearElement, ExcalidrawBindableElement, ExcalidrawFreeDrawElement, InitializedExcalidrawImageElement, ExcalidrawImageElement, ExcalidrawTextElementWithContainer, ExcalidrawTextContainer, ExcalidrawFrameElement, RoundnessType, ExcalidrawFrameLikeElement, ExcalidrawElementType, ExcalidrawIframeElement, ExcalidrawIframeLikeElement, ExcalidrawMagicFrameElement, ExcalidrawArrowElement } from "./types";
|
|
3
|
+
import type { ExcalidrawElement, ExcalidrawTextElement, ExcalidrawEmbeddableElement, ExcalidrawLinearElement, ExcalidrawBindableElement, ExcalidrawFreeDrawElement, InitializedExcalidrawImageElement, ExcalidrawImageElement, ExcalidrawTextElementWithContainer, ExcalidrawTextContainer, ExcalidrawFrameElement, RoundnessType, ExcalidrawFrameLikeElement, ExcalidrawElementType, ExcalidrawIframeElement, ExcalidrawIframeLikeElement, ExcalidrawMagicFrameElement, ExcalidrawArrowElement, ExcalidrawElbowArrowElement, PointBinding, FixedPointBinding } from "./types";
|
|
4
4
|
export declare const isInitializedImageElement: (element: ExcalidrawElement | null) => element is InitializedExcalidrawImageElement;
|
|
5
5
|
export declare const isImageElement: (element: ExcalidrawElement | null) => element is ExcalidrawImageElement;
|
|
6
6
|
export declare const isEmbeddableElement: (element: ExcalidrawElement | null | undefined) => element is ExcalidrawEmbeddableElement;
|
|
@@ -14,10 +14,12 @@ export declare const isFreeDrawElement: (element?: ExcalidrawElement | null) =>
|
|
|
14
14
|
export declare const isFreeDrawElementType: (elementType: ExcalidrawElementType) => boolean;
|
|
15
15
|
export declare const isLinearElement: (element?: ExcalidrawElement | null) => element is ExcalidrawLinearElement;
|
|
16
16
|
export declare const isArrowElement: (element?: ExcalidrawElement | null) => element is ExcalidrawArrowElement;
|
|
17
|
+
export declare const isElbowArrow: (element?: ExcalidrawElement) => element is ExcalidrawElbowArrowElement;
|
|
17
18
|
export declare const isLinearElementType: (elementType: ElementOrToolType) => boolean;
|
|
18
19
|
export declare const isBindingElement: (element?: ExcalidrawElement | null, includeLocked?: boolean) => element is ExcalidrawLinearElement;
|
|
19
20
|
export declare const isBindingElementType: (elementType: ElementOrToolType) => boolean;
|
|
20
|
-
export declare const isBindableElement: (element: ExcalidrawElement | null, includeLocked?: boolean) => element is ExcalidrawBindableElement;
|
|
21
|
+
export declare const isBindableElement: (element: ExcalidrawElement | null | undefined, includeLocked?: boolean) => element is ExcalidrawBindableElement;
|
|
22
|
+
export declare const isRectanguloidElement: (element?: ExcalidrawElement | null) => element is ExcalidrawBindableElement;
|
|
21
23
|
export declare const isTextBindableContainer: (element: ExcalidrawElement | null, includeLocked?: boolean) => element is ExcalidrawTextContainer;
|
|
22
24
|
export declare const isExcalidrawElement: (element: any) => element is ExcalidrawElement;
|
|
23
25
|
export declare const hasBoundTextElement: (element: ExcalidrawElement | null) => element is MarkNonNullable<ExcalidrawBindableElement, "boundElements">;
|
|
@@ -30,3 +32,4 @@ export declare const getDefaultRoundnessTypeForElement: (element: ExcalidrawElem
|
|
|
30
32
|
} | {
|
|
31
33
|
type: 3;
|
|
32
34
|
} | null;
|
|
35
|
+
export declare const isFixedPointBinding: (binding: PointBinding) => binding is FixedPointBinding;
|
|
@@ -40,6 +40,9 @@ export const isLinearElement = (element) => {
|
|
|
40
40
|
export const isArrowElement = (element) => {
|
|
41
41
|
return element != null && element.type === "arrow";
|
|
42
42
|
};
|
|
43
|
+
export const isElbowArrow = (element) => {
|
|
44
|
+
return isArrowElement(element) && element.elbowed;
|
|
45
|
+
};
|
|
43
46
|
export const isLinearElementType = (elementType) => {
|
|
44
47
|
return (elementType === "arrow" || elementType === "line" // || elementType === "freedraw"
|
|
45
48
|
);
|
|
@@ -65,6 +68,17 @@ export const isBindableElement = (element, includeLocked = true) => {
|
|
|
65
68
|
element.type === "magicframe" ||
|
|
66
69
|
(element.type === "text" && !element.containerId)));
|
|
67
70
|
};
|
|
71
|
+
export const isRectanguloidElement = (element) => {
|
|
72
|
+
return (element != null &&
|
|
73
|
+
(element.type === "rectangle" ||
|
|
74
|
+
element.type === "diamond" ||
|
|
75
|
+
element.type === "image" ||
|
|
76
|
+
element.type === "iframe" ||
|
|
77
|
+
element.type === "embeddable" ||
|
|
78
|
+
element.type === "frame" ||
|
|
79
|
+
element.type === "magicframe" ||
|
|
80
|
+
(element.type === "text" && !element.containerId)));
|
|
81
|
+
};
|
|
68
82
|
export const isTextBindableContainer = (element, includeLocked = true) => {
|
|
69
83
|
return (element != null &&
|
|
70
84
|
(!element.locked || includeLocked === true) &&
|
|
@@ -142,3 +156,6 @@ export const getDefaultRoundnessTypeForElement = (element) => {
|
|
|
142
156
|
}
|
|
143
157
|
return null;
|
|
144
158
|
};
|
|
159
|
+
export const isFixedPointBinding = (binding) => {
|
|
160
|
+
return binding.fixedPoint != null;
|
|
161
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Point } from "../types";
|
|
2
2
|
import type { FONT_FAMILY, ROUNDNESS, TEXT_ALIGN, THEME, VERTICAL_ALIGN } from "../constants";
|
|
3
|
-
import type { MakeBrand, MarkNonNullable, ValueOf } from "../utility-types";
|
|
3
|
+
import type { MakeBrand, MarkNonNullable, Merge, ValueOf } from "../utility-types";
|
|
4
4
|
import type { MagicCacheData } from "../data/magic";
|
|
5
5
|
export type ChartType = "bar" | "line";
|
|
6
6
|
export type FillStyle = "hachure" | "cross-hatch" | "solid" | "zigzag";
|
|
@@ -174,11 +174,16 @@ export type ExcalidrawTextContainer = ExcalidrawRectangleElement | ExcalidrawDia
|
|
|
174
174
|
export type ExcalidrawTextElementWithContainer = {
|
|
175
175
|
containerId: ExcalidrawTextContainer["id"];
|
|
176
176
|
} & ExcalidrawTextElement;
|
|
177
|
+
export type FixedPoint = [number, number];
|
|
177
178
|
export type PointBinding = {
|
|
178
179
|
elementId: ExcalidrawBindableElement["id"];
|
|
179
180
|
focus: number;
|
|
180
181
|
gap: number;
|
|
182
|
+
fixedPoint: FixedPoint | null;
|
|
181
183
|
};
|
|
184
|
+
export type FixedPointBinding = Merge<PointBinding, {
|
|
185
|
+
fixedPoint: FixedPoint;
|
|
186
|
+
}>;
|
|
182
187
|
export type Arrowhead = "arrow" | "bar" | "dot" | "circle" | "circle_outline" | "triangle" | "triangle_outline" | "diamond" | "diamond_outline";
|
|
183
188
|
export type ExcalidrawLinearElement = _ExcalidrawElementBase & Readonly<{
|
|
184
189
|
type: "line" | "arrow";
|
|
@@ -191,6 +196,12 @@ export type ExcalidrawLinearElement = _ExcalidrawElementBase & Readonly<{
|
|
|
191
196
|
}>;
|
|
192
197
|
export type ExcalidrawArrowElement = ExcalidrawLinearElement & Readonly<{
|
|
193
198
|
type: "arrow";
|
|
199
|
+
elbowed: boolean;
|
|
200
|
+
}>;
|
|
201
|
+
export type ExcalidrawElbowArrowElement = Merge<ExcalidrawArrowElement, {
|
|
202
|
+
elbowed: true;
|
|
203
|
+
startBinding: FixedPointBinding | null;
|
|
204
|
+
endBinding: FixedPointBinding | null;
|
|
194
205
|
}>;
|
|
195
206
|
export type ExcalidrawFreeDrawElement = _ExcalidrawElementBase & Readonly<{
|
|
196
207
|
type: "freedraw";
|