@excalidraw/excalidraw 0.17.1-d9bbf1e → 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-XOM7LNOU.js → chunk-IT7T3AIK.js} +49 -8
- package/dist/browser/dev/excalidraw-assets-dev/chunk-IT7T3AIK.js.map +7 -0
- package/dist/browser/dev/excalidraw-assets-dev/{chunk-BLEB3M62.js → chunk-RNHSD5AR.js} +7668 -2142
- package/dist/browser/dev/excalidraw-assets-dev/chunk-RNHSD5AR.js.map +7 -0
- package/dist/browser/dev/excalidraw-assets-dev/{dist-ITJNUBZF.js → dist-DNSPZDOZ.js} +66 -32
- package/dist/browser/dev/excalidraw-assets-dev/dist-DNSPZDOZ.js.map +7 -0
- package/dist/browser/dev/excalidraw-assets-dev/{en-TR4QLF5E.js → en-XV7OZCPP.js} +8 -2
- package/dist/browser/dev/excalidraw-assets-dev/{image-ZGDDRBEN.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 +610 -180
- package/dist/browser/dev/index.css.map +3 -3
- package/dist/browser/dev/index.js +13306 -8006
- 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-5SYIAZGL.js → chunk-PDYFZJMS.js} +5 -5
- 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 +70 -51
- 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-XW4JO6VX.json → en-YNVBSAIL.json} +42 -7
- package/dist/dev/index.css +610 -180
- package/dist/dev/index.css.map +3 -3
- package/dist/dev/index.js +22165 -16833
- package/dist/dev/index.js.map +4 -4
- package/dist/excalidraw/actions/actionAddToLibrary.d.ts +24 -9
- package/dist/excalidraw/actions/actionAlign.d.ts +8 -8
- package/dist/excalidraw/actions/actionBoundText.d.ts +20 -10
- package/dist/excalidraw/actions/actionBoundText.js +3 -1
- package/dist/excalidraw/actions/actionCanvas.d.ts +100 -40
- package/dist/excalidraw/actions/actionCanvas.js +1 -1
- package/dist/excalidraw/actions/actionClipboard.d.ts +62 -26
- package/dist/excalidraw/actions/actionDeleteSelected.d.ts +28 -12
- package/dist/excalidraw/actions/actionDeleteSelected.js +24 -5
- package/dist/excalidraw/actions/actionDistribute.d.ts +4 -4
- package/dist/excalidraw/actions/actionDuplicateSelection.d.ts +3 -3
- package/dist/excalidraw/actions/actionDuplicateSelection.js +1 -2
- package/dist/excalidraw/actions/actionElementLock.d.ts +17 -7
- package/dist/excalidraw/actions/actionExport.d.ts +75 -30
- package/dist/excalidraw/actions/actionFinalize.d.ts +17 -7
- package/dist/excalidraw/actions/actionFinalize.js +2 -2
- package/dist/excalidraw/actions/actionFlip.d.ts +4 -4
- package/dist/excalidraw/actions/actionFlip.js +2 -2
- package/dist/excalidraw/actions/actionFrame.d.ts +338 -10
- package/dist/excalidraw/actions/actionGroup.d.ts +324 -4
- package/dist/excalidraw/actions/actionHistory.d.ts +3 -3
- package/dist/excalidraw/actions/actionHistory.js +8 -8
- package/dist/excalidraw/actions/actionLinearEditor.d.ts +12 -5
- package/dist/excalidraw/actions/actionLinearEditor.js +21 -5
- package/dist/excalidraw/actions/actionLink.d.ts +8 -3
- package/dist/excalidraw/actions/actionMenu.d.ts +24 -9
- package/dist/excalidraw/actions/actionNavigate.d.ts +17 -7
- package/dist/excalidraw/actions/actionProperties.d.ts +476 -82
- package/dist/excalidraw/actions/actionProperties.js +384 -59
- package/dist/excalidraw/actions/actionSelectAll.d.ts +9 -4
- package/dist/excalidraw/actions/actionStyles.d.ts +12 -4
- package/dist/excalidraw/actions/actionStyles.js +3 -2
- package/dist/excalidraw/actions/actionTextAutoResize.d.ts +17 -0
- package/dist/excalidraw/actions/actionTextAutoResize.js +38 -0
- package/dist/excalidraw/actions/actionToggleGridMode.d.ts +9 -4
- package/dist/excalidraw/actions/actionToggleObjectsSnapMode.d.ts +8 -3
- package/dist/excalidraw/actions/actionToggleStats.d.ts +9 -3
- package/dist/excalidraw/actions/actionToggleStats.js +4 -3
- package/dist/excalidraw/actions/actionToggleViewMode.d.ts +8 -3
- package/dist/excalidraw/actions/actionToggleZenMode.d.ts +8 -3
- package/dist/excalidraw/actions/actionZindex.d.ts +8 -4
- package/dist/excalidraw/actions/actionZindex.js +4 -0
- package/dist/excalidraw/actions/manager.d.ts +3 -3
- package/dist/excalidraw/actions/register.d.ts +1 -1
- package/dist/excalidraw/actions/shortcuts.d.ts +2 -2
- package/dist/excalidraw/actions/types.d.ts +6 -6
- package/dist/excalidraw/align.d.ts +1 -1
- package/dist/excalidraw/analytics.js +9 -7
- package/dist/excalidraw/animated-trail.d.ts +2 -2
- package/dist/excalidraw/appState.d.ts +6 -2
- package/dist/excalidraw/appState.js +14 -3
- package/dist/excalidraw/binaryheap.d.ts +12 -0
- package/dist/excalidraw/binaryheap.js +93 -0
- package/dist/excalidraw/change.d.ts +6 -5
- package/dist/excalidraw/change.js +20 -11
- package/dist/excalidraw/charts.d.ts +1 -1
- package/dist/excalidraw/charts.js +0 -10
- package/dist/excalidraw/clients.d.ts +2 -2
- package/dist/excalidraw/clients.js +1 -1
- package/dist/excalidraw/clipboard.d.ts +3 -3
- package/dist/excalidraw/colors.d.ts +1 -1
- package/dist/excalidraw/components/Actions.d.ts +3 -3
- package/dist/excalidraw/components/Actions.js +14 -9
- package/dist/excalidraw/components/App.d.ts +14 -17
- package/dist/excalidraw/components/App.js +356 -217
- 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/CheckboxItem.js +1 -1
- package/dist/excalidraw/components/ColorPicker/ColorInput.d.ts +1 -1
- package/dist/excalidraw/components/ColorPicker/ColorInput.js +1 -1
- package/dist/excalidraw/components/ColorPicker/ColorPicker.d.ts +4 -4
- package/dist/excalidraw/components/ColorPicker/ColorPicker.js +48 -80
- package/dist/excalidraw/components/ColorPicker/Picker.d.ts +3 -3
- package/dist/excalidraw/components/ColorPicker/Picker.js +1 -1
- package/dist/excalidraw/components/ColorPicker/PickerColorList.d.ts +1 -1
- package/dist/excalidraw/components/ColorPicker/PickerHeading.d.ts +1 -1
- package/dist/excalidraw/components/ColorPicker/ShadeList.d.ts +1 -1
- package/dist/excalidraw/components/ColorPicker/TopPicks.d.ts +1 -1
- package/dist/excalidraw/components/ColorPicker/colorPickerUtils.d.ts +2 -2
- package/dist/excalidraw/components/ColorPicker/colorPickerUtils.js +1 -1
- package/dist/excalidraw/components/ColorPicker/keyboardNavHandlers.d.ts +2 -2
- package/dist/excalidraw/components/ColorPicker/keyboardNavHandlers.js +1 -1
- package/dist/excalidraw/components/CommandPalette/CommandPalette.d.ts +1 -1
- package/dist/excalidraw/components/CommandPalette/CommandPalette.js +5 -5
- package/dist/excalidraw/components/CommandPalette/defaultCommandPaletteItems.d.ts +1 -1
- package/dist/excalidraw/components/CommandPalette/types.d.ts +3 -3
- package/dist/excalidraw/components/ConfirmDialog.d.ts +1 -1
- package/dist/excalidraw/components/ContextMenu.d.ts +2 -2
- package/dist/excalidraw/components/ContextMenu.js +2 -2
- package/dist/excalidraw/components/DarkModeToggle.d.ts +1 -1
- package/dist/excalidraw/components/DefaultSidebar.d.ts +2 -2
- package/dist/excalidraw/components/Dialog.js +1 -1
- package/dist/excalidraw/components/DialogActionButton.d.ts +1 -1
- package/dist/excalidraw/components/EyeDropper.d.ts +2 -2
- package/dist/excalidraw/components/FollowMode/FollowMode.d.ts +1 -1
- package/dist/excalidraw/components/FollowMode/FollowMode.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 +2 -2
- package/dist/excalidraw/components/HintViewer.d.ts +1 -1
- package/dist/excalidraw/components/HintViewer.js +6 -3
- package/dist/excalidraw/components/IconPicker.js +2 -2
- package/dist/excalidraw/components/ImageExportDialog.d.ts +1 -1
- package/dist/excalidraw/components/InitializeApp.d.ts +2 -2
- package/dist/excalidraw/components/JSONExportDialog.d.ts +3 -3
- package/dist/excalidraw/components/LayerUI.d.ts +4 -4
- package/dist/excalidraw/components/LayerUI.js +10 -7
- package/dist/excalidraw/components/LibraryMenu.d.ts +2 -2
- package/dist/excalidraw/components/LibraryMenuBrowseButton.d.ts +1 -1
- package/dist/excalidraw/components/LibraryMenuControlButtons.d.ts +1 -1
- package/dist/excalidraw/components/LibraryMenuHeaderContent.d.ts +2 -2
- package/dist/excalidraw/components/LibraryMenuItems.d.ts +1 -1
- package/dist/excalidraw/components/LibraryMenuSection.d.ts +5 -4
- package/dist/excalidraw/components/LibraryUnit.d.ts +2 -2
- package/dist/excalidraw/components/LoadingMessage.d.ts +1 -1
- package/dist/excalidraw/components/MagicSettings.js +2 -2
- package/dist/excalidraw/components/MobileMenu.d.ts +3 -3
- package/dist/excalidraw/components/MobileMenu.js +2 -6
- package/dist/excalidraw/components/Modal.d.ts +1 -1
- package/dist/excalidraw/components/OverwriteConfirm/OverwriteConfirmState.d.ts +1 -1
- package/dist/excalidraw/components/PasteChartDialog.d.ts +1 -1
- package/dist/excalidraw/components/PasteChartDialog.js +1 -1
- package/dist/excalidraw/components/PropertiesPopover.d.ts +15 -0
- package/dist/excalidraw/components/PropertiesPopover.js +31 -0
- package/dist/excalidraw/components/PublishLibrary.d.ts +1 -1
- package/dist/excalidraw/components/QuickSearch.d.ts +9 -0
- package/dist/excalidraw/components/QuickSearch.js +8 -0
- package/dist/excalidraw/components/SVGLayer.d.ts +1 -1
- package/dist/excalidraw/components/ScrollableList.d.ts +9 -0
- package/dist/excalidraw/components/ScrollableList.js +8 -0
- package/dist/excalidraw/components/Sidebar/Sidebar.js +1 -1
- package/dist/excalidraw/components/Sidebar/SidebarTab.d.ts +1 -1
- package/dist/excalidraw/components/Sidebar/SidebarTabTrigger.d.ts +1 -1
- package/dist/excalidraw/components/Sidebar/SidebarTrigger.d.ts +1 -1
- package/dist/excalidraw/components/Sidebar/common.d.ts +1 -1
- package/dist/excalidraw/components/Stats/Angle.d.ts +12 -0
- package/dist/excalidraw/components/Stats/Angle.js +53 -0
- package/dist/excalidraw/components/Stats/Collapsible.d.ts +9 -0
- package/dist/excalidraw/components/Stats/Collapsible.js +12 -0
- package/dist/excalidraw/components/Stats/Dimension.d.ts +12 -0
- package/dist/excalidraw/components/Stats/Dimension.js +68 -0
- package/dist/excalidraw/components/Stats/DragInput.d.ts +32 -0
- package/dist/excalidraw/components/Stats/DragInput.js +174 -0
- package/dist/excalidraw/components/Stats/FontSize.d.ts +12 -0
- package/dist/excalidraw/components/Stats/FontSize.js +50 -0
- package/dist/excalidraw/components/Stats/MultiAngle.d.ts +12 -0
- package/dist/excalidraw/components/Stats/MultiAngle.js +66 -0
- package/dist/excalidraw/components/Stats/MultiDimension.d.ts +15 -0
- package/dist/excalidraw/components/Stats/MultiDimension.js +199 -0
- package/dist/excalidraw/components/Stats/MultiFontSize.d.ts +13 -0
- package/dist/excalidraw/components/Stats/MultiFontSize.js +72 -0
- package/dist/excalidraw/components/Stats/MultiPosition.d.ts +15 -0
- package/dist/excalidraw/components/Stats/MultiPosition.js +101 -0
- package/dist/excalidraw/components/Stats/Position.d.ts +13 -0
- package/dist/excalidraw/components/Stats/Position.js +40 -0
- package/dist/excalidraw/components/Stats/index.d.ts +16 -0
- package/dist/excalidraw/components/Stats/index.js +79 -0
- package/dist/excalidraw/components/Stats/utils.d.ts +26 -0
- package/dist/excalidraw/components/Stats/utils.js +162 -0
- package/dist/excalidraw/components/TTDDialog/MermaidToExcalidraw.d.ts +1 -1
- package/dist/excalidraw/components/TTDDialog/TTDDialog.js +2 -2
- package/dist/excalidraw/components/TTDDialog/TTDDialogInput.d.ts +1 -1
- package/dist/excalidraw/components/TTDDialog/TTDDialogPanel.d.ts +1 -1
- package/dist/excalidraw/components/TTDDialog/TTDDialogPanels.d.ts +1 -1
- package/dist/excalidraw/components/TTDDialog/TTDDialogTabs.d.ts +1 -1
- package/dist/excalidraw/components/TTDDialog/TTDDialogTrigger.d.ts +1 -1
- package/dist/excalidraw/components/TTDDialog/common.d.ts +5 -5
- package/dist/excalidraw/components/TTDDialog/common.js +3 -7
- package/dist/excalidraw/components/TextField.d.ts +1 -1
- package/dist/excalidraw/components/Toast.d.ts +1 -1
- package/dist/excalidraw/components/ToolButton.d.ts +3 -2
- package/dist/excalidraw/components/Trans.d.ts +1 -1
- package/dist/excalidraw/components/UserList.d.ts +1 -1
- package/dist/excalidraw/components/UserList.js +22 -22
- package/dist/excalidraw/components/canvases/InteractiveCanvas.d.ts +3 -2
- package/dist/excalidraw/components/canvases/InteractiveCanvas.js +4 -2
- package/dist/excalidraw/components/canvases/StaticCanvas.d.ts +2 -2
- package/dist/excalidraw/components/canvases/StaticCanvas.js +3 -2
- 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/footer/Footer.d.ts +2 -2
- package/dist/excalidraw/components/hyperlink/Hyperlink.d.ts +2 -2
- package/dist/excalidraw/components/hyperlink/helpers.d.ts +3 -3
- package/dist/excalidraw/components/icons.d.ts +10 -2
- package/dist/excalidraw/components/icons.js +29 -6
- 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 +24 -3
- package/dist/excalidraw/constants.js +28 -4
- package/dist/excalidraw/context/ui-appState.d.ts +1 -1
- package/dist/excalidraw/cursor.d.ts +1 -1
- package/dist/excalidraw/data/EditorLocalStorage.d.ts +2 -2
- package/dist/excalidraw/data/blob.d.ts +5 -5
- package/dist/excalidraw/data/filesystem.d.ts +2 -1
- package/dist/excalidraw/data/index.d.ts +4 -4
- package/dist/excalidraw/data/json.d.ts +3 -3
- package/dist/excalidraw/data/library.d.ts +3 -3
- package/dist/excalidraw/data/magic.d.ts +3 -3
- package/dist/excalidraw/data/reconcile.d.ts +3 -3
- package/dist/excalidraw/data/reconcile.js +18 -1
- package/dist/excalidraw/data/resave.d.ts +2 -2
- package/dist/excalidraw/data/restore.d.ts +3 -3
- package/dist/excalidraw/data/restore.js +58 -9
- package/dist/excalidraw/data/transform.d.ts +3 -3
- package/dist/excalidraw/data/transform.js +8 -5
- package/dist/excalidraw/data/types.d.ts +3 -3
- package/dist/excalidraw/element/ElementCanvasButtons.d.ts +1 -1
- package/dist/excalidraw/element/binding.d.ts +29 -10
- package/dist/excalidraw/element/binding.js +303 -71
- package/dist/excalidraw/element/bounds.d.ts +3 -3
- package/dist/excalidraw/element/collision.d.ts +4 -4
- package/dist/excalidraw/element/collision.js +5 -2
- package/dist/excalidraw/element/containerCache.d.ts +1 -1
- package/dist/excalidraw/element/dragElements.d.ts +6 -6
- package/dist/excalidraw/element/dragElements.js +39 -5
- package/dist/excalidraw/element/embeddable.d.ts +11 -6
- package/dist/excalidraw/element/heading.d.ts +11 -0
- package/dist/excalidraw/element/heading.js +81 -0
- package/dist/excalidraw/element/image.d.ts +2 -2
- package/dist/excalidraw/element/index.d.ts +2 -2
- package/dist/excalidraw/element/index.js +1 -1
- package/dist/excalidraw/element/linearElementEditor.d.ts +27 -16
- package/dist/excalidraw/element/linearElementEditor.js +133 -56
- package/dist/excalidraw/element/mutateElement.d.ts +3 -3
- package/dist/excalidraw/element/mutateElement.js +5 -3
- package/dist/excalidraw/element/newElement.d.ts +12 -10
- package/dist/excalidraw/element/newElement.js +31 -16
- package/dist/excalidraw/element/resizeElements.d.ts +15 -6
- package/dist/excalidraw/element/resizeElements.js +122 -46
- package/dist/excalidraw/element/resizeTest.d.ts +4 -4
- package/dist/excalidraw/element/resizeTest.js +2 -4
- package/dist/excalidraw/element/routing.d.ts +13 -0
- package/dist/excalidraw/element/routing.js +641 -0
- package/dist/excalidraw/element/showSelectedShapeActions.d.ts +2 -2
- package/dist/excalidraw/element/sizeHelpers.d.ts +2 -2
- package/dist/excalidraw/element/sortElements.d.ts +1 -1
- package/dist/excalidraw/element/textElement.d.ts +6 -28
- package/dist/excalidraw/element/textElement.js +64 -112
- package/dist/excalidraw/element/textWysiwyg.d.ts +12 -6
- package/dist/excalidraw/element/textWysiwyg.js +75 -62
- package/dist/excalidraw/element/transformHandles.d.ts +3 -3
- package/dist/excalidraw/element/transformHandles.js +7 -12
- package/dist/excalidraw/element/typeChecks.d.ts +7 -4
- package/dist/excalidraw/element/typeChecks.js +17 -0
- package/dist/excalidraw/element/types.d.ts +22 -4
- package/dist/excalidraw/emitter.d.ts +1 -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 +12 -5
- package/dist/excalidraw/fractionalIndex.js +40 -10
- package/dist/excalidraw/frame.d.ts +4 -4
- package/dist/excalidraw/frame.js +3 -3
- package/dist/excalidraw/gatransforms.d.ts +1 -1
- package/dist/excalidraw/gesture.d.ts +1 -1
- package/dist/excalidraw/groups.d.ts +4 -4
- package/dist/excalidraw/history.d.ts +8 -7
- package/dist/excalidraw/history.js +8 -8
- package/dist/excalidraw/hooks/useEmitter.d.ts +1 -1
- package/dist/excalidraw/hooks/useLibraryItemSvg.d.ts +1 -1
- package/dist/excalidraw/i18n.d.ts +1 -1
- package/dist/excalidraw/index.d.ts +2 -2
- package/dist/excalidraw/index.js +3 -3
- package/dist/excalidraw/jotai.d.ts +1 -1
- package/dist/excalidraw/laser-trails.d.ts +3 -2
- package/dist/excalidraw/locales/en.json +42 -7
- package/dist/excalidraw/math.d.ts +47 -2
- package/dist/excalidraw/math.js +116 -0
- package/dist/excalidraw/mermaid.d.ts +2 -0
- package/dist/excalidraw/mermaid.js +29 -0
- package/dist/excalidraw/points.d.ts +1 -1
- package/dist/excalidraw/queue.d.ts +1 -1
- package/dist/excalidraw/renderer/helpers.d.ts +2 -2
- package/dist/excalidraw/renderer/interactiveScene.d.ts +2 -2
- package/dist/excalidraw/renderer/interactiveScene.js +64 -22
- package/dist/excalidraw/renderer/renderElement.d.ts +6 -4
- package/dist/excalidraw/renderer/renderElement.js +78 -58
- package/dist/excalidraw/renderer/renderSnaps.d.ts +1 -1
- package/dist/excalidraw/renderer/staticScene.d.ts +1 -1
- package/dist/excalidraw/renderer/staticSvgScene.d.ts +4 -4
- package/dist/excalidraw/renderer/staticSvgScene.js +2 -1
- package/dist/excalidraw/scene/Renderer.d.ts +4 -4
- package/dist/excalidraw/scene/Renderer.js +2 -3
- package/dist/excalidraw/scene/Scene.d.ts +16 -7
- package/dist/excalidraw/scene/Scene.js +26 -11
- package/dist/excalidraw/scene/Shape.d.ts +1 -1
- package/dist/excalidraw/scene/Shape.js +56 -5
- package/dist/excalidraw/scene/ShapeCache.d.ts +4 -4
- package/dist/excalidraw/scene/comparisons.d.ts +3 -2
- package/dist/excalidraw/scene/comparisons.js +1 -1
- package/dist/excalidraw/scene/export.d.ts +4 -3
- package/dist/excalidraw/scene/export.js +34 -36
- package/dist/excalidraw/scene/scroll.d.ts +2 -2
- package/dist/excalidraw/scene/scrollbars.d.ts +3 -3
- package/dist/excalidraw/scene/selection.d.ts +2 -2
- package/dist/excalidraw/scene/types.d.ts +6 -8
- package/dist/excalidraw/scene/zoom.d.ts +1 -1
- package/dist/excalidraw/shapes.d.ts +8 -0
- package/dist/excalidraw/shapes.js +57 -0
- package/dist/excalidraw/snapping.d.ts +4 -4
- package/dist/excalidraw/snapping.js +2 -1
- package/dist/excalidraw/store.d.ts +34 -4
- package/dist/excalidraw/store.js +27 -0
- package/dist/excalidraw/types.d.ts +32 -21
- package/dist/excalidraw/utils.d.ts +15 -5
- package/dist/excalidraw/utils.js +22 -0
- package/dist/excalidraw/zindex.d.ts +2 -2
- 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-XW4JO6VX.json → en-YNVBSAIL.json} +42 -7
- package/dist/prod/index.css +1 -1
- package/dist/prod/index.js +49 -53
- package/dist/utils/bbox.d.ts +2 -2
- package/dist/utils/collision.d.ts +1 -1
- package/dist/utils/export.d.ts +4 -3
- package/dist/utils/export.js +2 -1
- package/dist/utils/geometry/geometry.d.ts +3 -2
- package/dist/utils/geometry/geometry.js +5 -1
- package/dist/utils/geometry/shape.d.ts +1 -1
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/withinBounds.d.ts +1 -1
- package/history.ts +13 -6
- 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-BLEB3M62.js.map +0 -7
- package/dist/browser/dev/excalidraw-assets-dev/chunk-XOM7LNOU.js.map +0 -7
- package/dist/browser/dev/excalidraw-assets-dev/dist-ITJNUBZF.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-UWBW5SR2.js +0 -55
- package/dist/browser/prod/excalidraw-assets/dist-54276HPL.js +0 -6
- package/dist/browser/prod/excalidraw-assets/en-7GPZE2Y2.js +0 -1
- package/dist/browser/prod/excalidraw-assets/image-35KQQ5EN.js +0 -1
- package/dist/dev/Cascadia-CYPE3OJC.woff2 +0 -0
- package/dist/dev/Virgil-UZN6MUT6.woff2 +0 -0
- package/dist/excalidraw/components/Stats.d.ts +0 -11
- package/dist/excalidraw/components/Stats.js +0 -13
- package/dist/excalidraw/scene/Fonts.d.ts +0 -21
- package/dist/excalidraw/scene/Fonts.js +0 -72
- 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-TR4QLF5E.js.map → en-XV7OZCPP.js.map} +0 -0
- /package/dist/browser/dev/excalidraw-assets-dev/{image-ZGDDRBEN.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
|
@@ -10,17 +10,18 @@ import { ActionManager } from "../actions/manager";
|
|
|
10
10
|
import { actions } from "../actions/register";
|
|
11
11
|
import { trackEvent } from "../analytics";
|
|
12
12
|
import { getDefaultAppState, isEraserActive, isHandToolActive, } from "../appState";
|
|
13
|
-
import { copyTextToSystemClipboard, parseClipboard
|
|
14
|
-
import {
|
|
13
|
+
import { copyTextToSystemClipboard, parseClipboard } from "../clipboard";
|
|
14
|
+
import { ARROW_TYPE } from "../constants";
|
|
15
|
+
import { APP_NAME, CURSOR_TYPE, DEFAULT_MAX_IMAGE_WIDTH_OR_HEIGHT, DEFAULT_VERTICAL_ALIGN, DRAGGING_THRESHOLD, ELEMENT_SHIFT_TRANSLATE_AMOUNT, ELEMENT_TRANSLATE_AMOUNT, ENV, EVENT, FRAME_STYLE, GRID_SIZE, IMAGE_MIME_TYPES, IMAGE_RENDER_TIMEOUT, isBrave, LINE_CONFIRM_THRESHOLD, MAX_ALLOWED_FILE_BYTES, MIME_TYPES, MQ_MAX_HEIGHT_LANDSCAPE, MQ_MAX_WIDTH_LANDSCAPE, MQ_MAX_WIDTH_PORTRAIT, MQ_RIGHT_SIDEBAR_MIN_WIDTH, POINTER_BUTTON, ROUNDNESS, SCROLL_TIMEOUT, TAP_TWICE_TIMEOUT, TEXT_TO_CENTER_SNAP_THRESHOLD, THEME, THEME_FILTER, TOUCH_CTX_MENU_TIMEOUT, VERTICAL_ALIGN, YOUTUBE_STATES, ZOOM_STEP, POINTER_EVENTS, TOOL_TYPE, EDITOR_LS_KEYS, isIOS, supportsResizeObserver, DEFAULT_COLLISION_THRESHOLD, DEFAULT_TEXT_ALIGN, } from "../constants";
|
|
15
16
|
import { exportCanvas, loadFromBlob } from "../data";
|
|
16
17
|
import Library, { distributeLibraryItemsOnSquareGrid } from "../data/library";
|
|
17
18
|
import { restore, restoreElements } from "../data/restore";
|
|
18
|
-
import { dragNewElement, dragSelectedElements, duplicateElement, getCommonBounds, getCursorForResizingElement, getDragOffsetXY, getElementWithTransformHandleType, getNormalizedDimensions, getResizeArrowDirection, getResizeOffsetXY, getLockedLinearCursorAlignSize, getTransformHandleTypeFromCoords, isInvisiblySmallElement, isNonDeletedElement, isTextElement, newElement, newLinearElement, newTextElement, newImageElement, transformElements,
|
|
19
|
+
import { dragNewElement, dragSelectedElements, duplicateElement, getCommonBounds, getCursorForResizingElement, getDragOffsetXY, getElementWithTransformHandleType, getNormalizedDimensions, getResizeArrowDirection, getResizeOffsetXY, getLockedLinearCursorAlignSize, getTransformHandleTypeFromCoords, isInvisiblySmallElement, isNonDeletedElement, isTextElement, newElement, newLinearElement, newTextElement, newImageElement, transformElements, refreshTextDimensions, redrawTextBoundingBox, getElementAbsoluteCoords, } from "../element";
|
|
19
20
|
import { bindOrUnbindLinearElement, bindOrUnbindLinearElements, fixBindingsAfterDeletion, fixBindingsAfterDuplication, getHoveredElementForBinding, isBindingEnabled, isLinearElementSimpleAndAlreadyBound, maybeBindLinearElement, shouldEnableBindingForPointerEvent, updateBoundElements, getSuggestedBindingsForArrows, } from "../element/binding";
|
|
20
21
|
import { LinearElementEditor } from "../element/linearElementEditor";
|
|
21
22
|
import { mutateElement, newElementWith } from "../element/mutateElement";
|
|
22
|
-
import { deepCopyElement, duplicateElements, newFrameElement, newFreeDrawElement, newEmbeddableElement, newMagicFrameElement, newIframeElement, } from "../element/newElement";
|
|
23
|
-
import { hasBoundTextElement, isArrowElement, isBindingElement, isBindingElementType, isBoundToContainer, isFrameLikeElement, isImageElement, isEmbeddableElement, isInitializedImageElement, isLinearElement, isLinearElementType, isUsingAdaptiveRadius,
|
|
23
|
+
import { deepCopyElement, duplicateElements, newFrameElement, newFreeDrawElement, newEmbeddableElement, newMagicFrameElement, newIframeElement, newArrowElement, } from "../element/newElement";
|
|
24
|
+
import { hasBoundTextElement, isArrowElement, isBindingElement, isBindingElementType, isBoundToContainer, isFrameLikeElement, isImageElement, isEmbeddableElement, isInitializedImageElement, isLinearElement, isLinearElementType, isUsingAdaptiveRadius, isIframeElement, isIframeLikeElement, isMagicFrameElement, isTextBindableContainer, isElbowArrow, } from "../element/typeChecks";
|
|
24
25
|
import { getCenter, getDistance } from "../gesture";
|
|
25
26
|
import { editGroupForSelectedElement, getElementsInGroup, getSelectedGroupIdForElement, getSelectedGroupIds, isElementInGroup, isSelectedViaGroup, selectGroupsForSelectedElements, } from "../groups";
|
|
26
27
|
import { History } from "../history";
|
|
@@ -31,12 +32,12 @@ import { distance2d, getCornerRadius, getGridPoint, isPathALoop, } from "../math
|
|
|
31
32
|
import { calculateScrollCenter, getElementsWithinSelection, getNormalizedZoom, getSelectedElements, hasBackground, isSomeElementSelected, } from "../scene";
|
|
32
33
|
import Scene from "../scene/Scene";
|
|
33
34
|
import { getStateForZoom } from "../scene/zoom";
|
|
34
|
-
import { findShapeByKey } from "../shapes";
|
|
35
|
-
import {
|
|
35
|
+
import { findShapeByKey, getBoundTextShape, getElementShape } from "../shapes";
|
|
36
|
+
import { getSelectionBoxShape } from "../../utils/geometry/shape";
|
|
36
37
|
import { isPointInShape } from "../../utils/collision";
|
|
37
38
|
import { debounce, distance, getFontString, getNearestScrollableContainer, isInputLike, isToolIcon, isWritableElement, sceneCoordsToViewportCoords, tupleToCoors, viewportCoordsToSceneCoords, wrapEvent, updateObject, updateActiveTool, getShortcutKey, isTransparent, easeToValuesRAF, muteFSAbortError, isTestEnv, easeOut, updateStable, addEventListener, normalizeEOL, getDateTime, isShallowEqual, arrayToMap, } from "../utils";
|
|
38
39
|
import { createSrcDoc, embeddableURLValidator, maybeParseEmbedSrc, getEmbedLink, } from "../element/embeddable";
|
|
39
|
-
import { ContextMenu, CONTEXT_MENU_SEPARATOR
|
|
40
|
+
import { ContextMenu, CONTEXT_MENU_SEPARATOR } from "./ContextMenu";
|
|
40
41
|
import LayerUI from "./LayerUI";
|
|
41
42
|
import { Toast } from "./Toast";
|
|
42
43
|
import { actionToggleViewMode } from "../actions/actionToggleViewMode";
|
|
@@ -44,12 +45,12 @@ import { dataURLToFile, generateIdFromFile, getDataURL, getFileFromEvent, ImageU
|
|
|
44
45
|
import { getInitializedImageElements, loadHTMLImageElement, normalizeSVG, updateImageCache as _updateImageCache, } from "../element/image";
|
|
45
46
|
import throttle from "lodash.throttle";
|
|
46
47
|
import { fileOpen } from "../data/filesystem";
|
|
47
|
-
import { bindTextToShapeAfterDuplication, getApproxMinLineHeight, getApproxMinLineWidth, getBoundTextElement, getContainerCenter, getContainerElement,
|
|
48
|
+
import { bindTextToShapeAfterDuplication, getApproxMinLineHeight, getApproxMinLineWidth, getBoundTextElement, getContainerCenter, getContainerElement, getLineHeightInPx, getMinTextElementWidth, isMeasureTextSupported, isValidTextContainer, measureText, wrapText, } from "../element/textElement";
|
|
48
49
|
import { showHyperlinkTooltip, hideHyperlinkToolip, Hyperlink, } from "../components/hyperlink/Hyperlink";
|
|
49
50
|
import { isLocalLink, normalizeLink, toValidURL } from "../data/url";
|
|
50
51
|
import { shouldShowBoundingBox } from "../element/transformHandles";
|
|
51
52
|
import { actionUnlockAllElements } from "../actions/actionElementLock";
|
|
52
|
-
import { Fonts } from "../
|
|
53
|
+
import { Fonts, getLineHeight } from "../fonts";
|
|
53
54
|
import { getFrameChildren, isCursorInFrame, bindElementsToFramesAfterDuplication, addElementsToFrame, replaceAllElementsInFrame, removeElementsFromFrame, getElementsInResizingFrame, getElementsInNewFrame, getContainingFrame, elementOverlapsWithFrame, updateFrameMembershipOfSelectedElements, isElementInFrame, getFrameLikeTitle, getElementsOverlappingFrame, filterElementsEligibleAsFrameChildren, } from "../frame";
|
|
54
55
|
import { excludeElementsInFramesFromSelection, makeNextSelectedElementIds, } from "../scene/selection";
|
|
55
56
|
import { actionPaste } from "../actions/actionClipboard";
|
|
@@ -62,7 +63,7 @@ import { getSnapLinesAtPointer, snapDraggedElements, isActiveToolNonLinearSnappa
|
|
|
62
63
|
import { actionWrapTextInContainer } from "../actions/actionBoundText";
|
|
63
64
|
import BraveMeasureTextError from "./BraveMeasureTextError";
|
|
64
65
|
import { activeEyeDropperAtom } from "./EyeDropper";
|
|
65
|
-
import { convertToExcalidrawElements
|
|
66
|
+
import { convertToExcalidrawElements } from "../data/transform";
|
|
66
67
|
import { isSidebarDockedAtom } from "./Sidebar/Sidebar";
|
|
67
68
|
import { StaticCanvas, InteractiveCanvas } from "./canvases";
|
|
68
69
|
import { Renderer } from "../scene/Renderer";
|
|
@@ -84,12 +85,16 @@ import { AnimatedTrail } from "../animated-trail";
|
|
|
84
85
|
import { LaserTrails } from "../laser-trails";
|
|
85
86
|
import { withBatchedUpdates, withBatchedUpdatesThrottled } from "../reactUtils";
|
|
86
87
|
import { getRenderOpacity } from "../renderer/renderElement";
|
|
87
|
-
import { hitElementBoundText, hitElementBoundingBoxOnly, hitElementItself,
|
|
88
|
+
import { hitElementBoundText, hitElementBoundingBoxOnly, hitElementItself, } from "../element/collision";
|
|
88
89
|
import { textWysiwyg } from "../element/textWysiwyg";
|
|
89
90
|
import { isOverScrollBars } from "../scene/scrollbars";
|
|
90
91
|
import { syncInvalidIndices, syncMovedIndices } from "../fractionalIndex";
|
|
91
92
|
import { isPointHittingLink, isPointHittingLinkIcon, } from "./hyperlink/helpers";
|
|
92
93
|
import { getShortcutFromShortcutName } from "../actions/shortcuts";
|
|
94
|
+
import { actionTextAutoResize } from "../actions/actionTextAutoResize";
|
|
95
|
+
import { getVisibleSceneBounds } from "../element/bounds";
|
|
96
|
+
import { isMaybeMermaidDefinition } from "../mermaid";
|
|
97
|
+
import { mutateElbowArrow } from "../element/routing";
|
|
93
98
|
const AppContext = React.createContext(null);
|
|
94
99
|
const AppPropsContext = React.createContext(null);
|
|
95
100
|
const deviceContextInitialValue = {
|
|
@@ -162,8 +167,8 @@ class App extends React.Component {
|
|
|
162
167
|
device = deviceContextInitialValue;
|
|
163
168
|
excalidrawContainerRef = React.createRef();
|
|
164
169
|
scene;
|
|
165
|
-
renderer;
|
|
166
170
|
fonts;
|
|
171
|
+
renderer;
|
|
167
172
|
resizeObserver;
|
|
168
173
|
nearestScrollableContainer;
|
|
169
174
|
library;
|
|
@@ -286,10 +291,7 @@ class App extends React.Component {
|
|
|
286
291
|
container: this.excalidrawContainerRef.current,
|
|
287
292
|
id: this.id,
|
|
288
293
|
};
|
|
289
|
-
this.fonts = new Fonts({
|
|
290
|
-
scene: this.scene,
|
|
291
|
-
onSceneUpdated: this.onSceneUpdated,
|
|
292
|
-
});
|
|
294
|
+
this.fonts = new Fonts({ scene: this.scene });
|
|
293
295
|
this.history = new History();
|
|
294
296
|
this.actionManager.registerAll(actions);
|
|
295
297
|
this.actionManager.registerAction(createUndoAction(this.history, this.store));
|
|
@@ -444,7 +446,7 @@ class App extends React.Component {
|
|
|
444
446
|
return false;
|
|
445
447
|
});
|
|
446
448
|
if (updated) {
|
|
447
|
-
this.scene.
|
|
449
|
+
this.scene.triggerUpdate();
|
|
448
450
|
}
|
|
449
451
|
// GC
|
|
450
452
|
this.iFrameRefs.forEach((ref, id) => {
|
|
@@ -700,15 +702,7 @@ class App extends React.Component {
|
|
|
700
702
|
return null;
|
|
701
703
|
}
|
|
702
704
|
const isDarkTheme = this.state.theme === THEME.DARK;
|
|
703
|
-
let frameIndex = 0;
|
|
704
|
-
let magicFrameIndex = 0;
|
|
705
705
|
return this.scene.getNonDeletedFramesLikes().map((f) => {
|
|
706
|
-
if (isFrameElement(f)) {
|
|
707
|
-
frameIndex++;
|
|
708
|
-
}
|
|
709
|
-
else {
|
|
710
|
-
magicFrameIndex++;
|
|
711
|
-
}
|
|
712
706
|
if (!isElementInViewport(f, this.canvas.width / window.devicePixelRatio, this.canvas.height / window.devicePixelRatio, {
|
|
713
707
|
offsetLeft: this.state.offsetLeft,
|
|
714
708
|
offsetTop: this.state.offsetTop,
|
|
@@ -726,7 +720,7 @@ class App extends React.Component {
|
|
|
726
720
|
this.setState({ editingFrame: null });
|
|
727
721
|
};
|
|
728
722
|
let frameNameJSX;
|
|
729
|
-
const frameName = getFrameLikeTitle(f
|
|
723
|
+
const frameName = getFrameLikeTitle(f);
|
|
730
724
|
if (f.id === this.state.editingFrame) {
|
|
731
725
|
const frameNameInEdit = frameName;
|
|
732
726
|
frameNameJSX = (_jsx("input", { autoFocus: true, value: frameNameInEdit, onChange: (e) => {
|
|
@@ -803,9 +797,9 @@ class App extends React.Component {
|
|
|
803
797
|
render() {
|
|
804
798
|
const selectedElements = this.scene.getSelectedElements(this.state);
|
|
805
799
|
const { renderTopRightUI, renderCustomStats } = this.props;
|
|
806
|
-
const
|
|
800
|
+
const sceneNonce = this.scene.getSceneNonce();
|
|
807
801
|
const { elementsMap, visibleElements } = this.renderer.getRenderableElements({
|
|
808
|
-
|
|
802
|
+
sceneNonce,
|
|
809
803
|
zoom: this.state.zoom,
|
|
810
804
|
offsetLeft: this.state.offsetLeft,
|
|
811
805
|
offsetTop: this.state.offsetTop,
|
|
@@ -874,14 +868,14 @@ class App extends React.Component {
|
|
|
874
868
|
this.focusContainer();
|
|
875
869
|
callback?.();
|
|
876
870
|
});
|
|
877
|
-
} })), _jsx(StaticCanvas, { canvas: this.canvas, rc: this.rc, elementsMap: elementsMap, allElementsMap: allElementsMap, visibleElements: visibleElements,
|
|
871
|
+
} })), _jsx(StaticCanvas, { canvas: this.canvas, rc: this.rc, elementsMap: elementsMap, allElementsMap: allElementsMap, visibleElements: visibleElements, sceneNonce: sceneNonce, selectionNonce: this.state.selectionElement?.versionNonce, scale: window.devicePixelRatio, appState: this.state, renderConfig: {
|
|
878
872
|
imageCache: this.imageCache,
|
|
879
873
|
isExporting: false,
|
|
880
874
|
renderGrid: true,
|
|
881
875
|
canvasBackgroundColor: this.state.viewBackgroundColor,
|
|
882
876
|
embedsValidationStatus: this.embedsValidationStatus,
|
|
883
877
|
elementsPendingErasure: this.elementsPendingErasure,
|
|
884
|
-
} }), _jsx(InteractiveCanvas, { containerRef: this.excalidrawContainerRef, canvas: this.interactiveCanvas, elementsMap: elementsMap, visibleElements: visibleElements, selectedElements: selectedElements,
|
|
878
|
+
} }), _jsx(InteractiveCanvas, { containerRef: this.excalidrawContainerRef, canvas: this.interactiveCanvas, elementsMap: elementsMap, visibleElements: visibleElements, allElementsMap: allElementsMap, selectedElements: selectedElements, sceneNonce: sceneNonce, selectionNonce: this.state.selectionElement?.versionNonce, scale: window.devicePixelRatio, appState: this.state, device: this.device, renderInteractiveSceneCallback: this.renderInteractiveSceneCallback, handleCanvasRef: this.handleInteractiveCanvasRef, onContextMenu: this.handleCanvasContextMenu, onPointerMove: this.handleCanvasPointerMove, onPointerUp: this.handleCanvasPointerUp, onPointerCancel: this.removePointer, onTouchMove: this.handleTouchMove, onPointerDown: this.handleCanvasPointerDown, onDoubleClick: this.handleCanvasDoubleClick }), this.state.userToFollow && (_jsx(FollowMode, { width: this.state.width, height: this.state.height, userToFollow: this.state.userToFollow, onDisconnect: this.maybeUnfollowRemoteUser })), this.renderFrameNames()] }), this.renderEmbeddables()] }) }) }) }) }) }) }) }));
|
|
885
879
|
}
|
|
886
880
|
focusContainer = () => {
|
|
887
881
|
this.excalidrawContainerRef.current?.focus();
|
|
@@ -931,7 +925,7 @@ class App extends React.Component {
|
|
|
931
925
|
mutateElement(frameElement, { customData: { generationData: data } }, false);
|
|
932
926
|
}
|
|
933
927
|
this.magicGenerations.set(frameElement.id, data);
|
|
934
|
-
this.
|
|
928
|
+
this.triggerRender();
|
|
935
929
|
};
|
|
936
930
|
getTextFromElements(elements) {
|
|
937
931
|
const text = elements
|
|
@@ -1180,10 +1174,24 @@ class App extends React.Component {
|
|
|
1180
1174
|
keepOpenOnAlt: false,
|
|
1181
1175
|
});
|
|
1182
1176
|
};
|
|
1177
|
+
dismissLinearEditor = () => {
|
|
1178
|
+
setTimeout(() => {
|
|
1179
|
+
this.setState({
|
|
1180
|
+
editingLinearElement: null,
|
|
1181
|
+
});
|
|
1182
|
+
});
|
|
1183
|
+
};
|
|
1183
1184
|
syncActionResult = withBatchedUpdates((actionResult) => {
|
|
1184
1185
|
if (this.unmounted || actionResult === false) {
|
|
1185
1186
|
return;
|
|
1186
1187
|
}
|
|
1188
|
+
if (actionResult.storeAction === StoreAction.UPDATE) {
|
|
1189
|
+
this.store.shouldUpdateSnapshot();
|
|
1190
|
+
}
|
|
1191
|
+
else if (actionResult.storeAction === StoreAction.CAPTURE) {
|
|
1192
|
+
this.store.shouldCaptureIncrement();
|
|
1193
|
+
}
|
|
1194
|
+
let didUpdate = false;
|
|
1187
1195
|
let editingElement = null;
|
|
1188
1196
|
if (actionResult.elements) {
|
|
1189
1197
|
actionResult.elements.forEach((element) => {
|
|
@@ -1193,13 +1201,8 @@ class App extends React.Component {
|
|
|
1193
1201
|
editingElement = element;
|
|
1194
1202
|
}
|
|
1195
1203
|
});
|
|
1196
|
-
if (actionResult.storeAction === StoreAction.UPDATE) {
|
|
1197
|
-
this.store.shouldUpdateSnapshot();
|
|
1198
|
-
}
|
|
1199
|
-
else if (actionResult.storeAction === StoreAction.CAPTURE) {
|
|
1200
|
-
this.store.shouldCaptureIncrement();
|
|
1201
|
-
}
|
|
1202
1204
|
this.scene.replaceAllElements(actionResult.elements);
|
|
1205
|
+
didUpdate = true;
|
|
1203
1206
|
}
|
|
1204
1207
|
if (actionResult.files) {
|
|
1205
1208
|
this.files = actionResult.replaceFiles
|
|
@@ -1208,12 +1211,6 @@ class App extends React.Component {
|
|
|
1208
1211
|
this.addNewImagesToImageCache();
|
|
1209
1212
|
}
|
|
1210
1213
|
if (actionResult.appState || editingElement || this.state.contextMenu) {
|
|
1211
|
-
if (actionResult.storeAction === StoreAction.UPDATE) {
|
|
1212
|
-
this.store.shouldUpdateSnapshot();
|
|
1213
|
-
}
|
|
1214
|
-
else if (actionResult.storeAction === StoreAction.CAPTURE) {
|
|
1215
|
-
this.store.shouldCaptureIncrement();
|
|
1216
|
-
}
|
|
1217
1214
|
let viewModeEnabled = actionResult?.appState?.viewModeEnabled || false;
|
|
1218
1215
|
let zenModeEnabled = actionResult?.appState?.zenModeEnabled || false;
|
|
1219
1216
|
let gridSize = actionResult?.appState?.gridSize || null;
|
|
@@ -1252,6 +1249,10 @@ class App extends React.Component {
|
|
|
1252
1249
|
errorMessage,
|
|
1253
1250
|
});
|
|
1254
1251
|
});
|
|
1252
|
+
didUpdate = true;
|
|
1253
|
+
}
|
|
1254
|
+
if (!didUpdate && actionResult.storeAction !== StoreAction.NONE) {
|
|
1255
|
+
this.scene.triggerUpdate();
|
|
1255
1256
|
}
|
|
1256
1257
|
});
|
|
1257
1258
|
// Lifecycle
|
|
@@ -1304,7 +1305,12 @@ class App extends React.Component {
|
|
|
1304
1305
|
}
|
|
1305
1306
|
let initialData = null;
|
|
1306
1307
|
try {
|
|
1307
|
-
|
|
1308
|
+
if (typeof this.props.initialData === "function") {
|
|
1309
|
+
initialData = (await this.props.initialData()) || null;
|
|
1310
|
+
}
|
|
1311
|
+
else {
|
|
1312
|
+
initialData = (await this.props.initialData) || null;
|
|
1313
|
+
}
|
|
1308
1314
|
if (initialData?.libraryItems) {
|
|
1309
1315
|
this.library
|
|
1310
1316
|
.updateLibrary({
|
|
@@ -1352,17 +1358,17 @@ class App extends React.Component {
|
|
|
1352
1358
|
}),
|
|
1353
1359
|
};
|
|
1354
1360
|
}
|
|
1355
|
-
// FontFaceSet loadingdone event we listen on may not always fire
|
|
1356
|
-
// (looking at you Safari), so on init we manually load fonts for current
|
|
1357
|
-
// text elements on canvas, and rerender them once done. This also
|
|
1358
|
-
// seems faster even in browsers that do fire the loadingdone event.
|
|
1359
|
-
this.fonts.loadFontsForElements(scene.elements);
|
|
1360
1361
|
this.resetStore();
|
|
1361
1362
|
this.resetHistory();
|
|
1362
1363
|
this.syncActionResult({
|
|
1363
1364
|
...scene,
|
|
1364
1365
|
storeAction: StoreAction.UPDATE,
|
|
1365
1366
|
});
|
|
1367
|
+
// FontFaceSet loadingdone event we listen on may not always
|
|
1368
|
+
// fire (looking at you Safari), so on init we manually load all
|
|
1369
|
+
// fonts and rerender scene text elements once done. This also
|
|
1370
|
+
// seems faster even in browsers that do fire the loadingdone event.
|
|
1371
|
+
this.fonts.loadSceneFonts();
|
|
1366
1372
|
};
|
|
1367
1373
|
isMobileBreakpoint = (width, height) => {
|
|
1368
1374
|
return (width < MQ_MAX_WIDTH_PORTRAIT ||
|
|
@@ -1436,12 +1442,16 @@ class App extends React.Component {
|
|
|
1436
1442
|
configurable: true,
|
|
1437
1443
|
value: this.store,
|
|
1438
1444
|
},
|
|
1445
|
+
fonts: {
|
|
1446
|
+
configurable: true,
|
|
1447
|
+
value: this.fonts,
|
|
1448
|
+
},
|
|
1439
1449
|
});
|
|
1440
1450
|
}
|
|
1441
1451
|
this.store.onStoreIncrementEmitter.on((increment) => {
|
|
1442
1452
|
this.history.record(increment.elementsChange, increment.appStateChange);
|
|
1443
1453
|
});
|
|
1444
|
-
this.scene.
|
|
1454
|
+
this.scene.onUpdate(this.triggerRender);
|
|
1445
1455
|
this.addEventListeners();
|
|
1446
1456
|
if (this.props.autoFocus && this.excalidrawContainerRef.current) {
|
|
1447
1457
|
this.focusContainer();
|
|
@@ -1477,15 +1487,17 @@ class App extends React.Component {
|
|
|
1477
1487
|
}
|
|
1478
1488
|
}
|
|
1479
1489
|
componentWillUnmount() {
|
|
1490
|
+
window.launchQueue?.setConsumer(() => { });
|
|
1480
1491
|
this.renderer.destroy();
|
|
1492
|
+
this.scene.destroy();
|
|
1481
1493
|
this.scene = new Scene();
|
|
1494
|
+
this.fonts = new Fonts({ scene: this.scene });
|
|
1482
1495
|
this.renderer = new Renderer(this.scene);
|
|
1483
1496
|
this.files = {};
|
|
1484
1497
|
this.imageCache.clear();
|
|
1485
1498
|
this.resizeObserver?.disconnect();
|
|
1486
1499
|
this.unmounted = true;
|
|
1487
1500
|
this.removeEventListeners();
|
|
1488
|
-
this.scene.destroy();
|
|
1489
1501
|
this.library.destroy();
|
|
1490
1502
|
this.laserTrails.stop();
|
|
1491
1503
|
this.eraserTrail.stop();
|
|
@@ -1534,15 +1546,18 @@ class App extends React.Component {
|
|
|
1534
1546
|
this.onRemoveEventListenersEmitter.once(addEventListener(document, EVENT.KEYDOWN, this.onKeyDown, false));
|
|
1535
1547
|
}
|
|
1536
1548
|
this.onRemoveEventListenersEmitter.once(addEventListener(this.excalidrawContainerRef.current, EVENT.WHEEL, this.onWheel, { passive: false }), addEventListener(window, EVENT.MESSAGE, this.onWindowMessage, false), addEventListener(document, EVENT.POINTER_UP, this.removePointer), // #3553
|
|
1537
|
-
addEventListener(document, EVENT.COPY, this.onCopy), addEventListener(document, EVENT.KEYUP, this.onKeyUp, { passive: true }), addEventListener(document, EVENT.
|
|
1549
|
+
addEventListener(document, EVENT.COPY, this.onCopy), addEventListener(document, EVENT.KEYUP, this.onKeyUp, { passive: true }), addEventListener(document, EVENT.POINTER_MOVE, this.updateCurrentCursorPosition),
|
|
1538
1550
|
// rerender text elements on font load to fix #637 && #1553
|
|
1539
1551
|
addEventListener(document.fonts, "loadingdone", (event) => {
|
|
1540
1552
|
const loadedFontFaces = event.fontfaces;
|
|
1541
|
-
this.fonts.
|
|
1553
|
+
this.fonts.onLoaded(loadedFontFaces);
|
|
1542
1554
|
}),
|
|
1543
1555
|
// Safari-only desktop pinch zoom
|
|
1544
1556
|
addEventListener(document, EVENT.GESTURE_START, this.onGestureStart, false), addEventListener(document, EVENT.GESTURE_CHANGE, this.onGestureChange, false), addEventListener(document, EVENT.GESTURE_END, this.onGestureEnd, false), addEventListener(window, EVENT.FOCUS, () => {
|
|
1545
1557
|
this.maybeCleanupAfterMissingPointerUp(null);
|
|
1558
|
+
// browsers (chrome?) tend to free up memory a lot, which results
|
|
1559
|
+
// in canvas context being cleared. Thus re-render on focus.
|
|
1560
|
+
this.triggerRender(true);
|
|
1546
1561
|
}));
|
|
1547
1562
|
if (this.state.viewModeEnabled) {
|
|
1548
1563
|
return;
|
|
@@ -1660,7 +1675,7 @@ class App extends React.Component {
|
|
|
1660
1675
|
multiElement != null &&
|
|
1661
1676
|
isBindingEnabled(this.state) &&
|
|
1662
1677
|
isBindingElement(multiElement, false)) {
|
|
1663
|
-
maybeBindLinearElement(multiElement, this.state, tupleToCoors(LinearElementEditor.getPointAtIndexGlobalCoordinates(multiElement, -1, nonDeletedElementsMap)), this);
|
|
1678
|
+
maybeBindLinearElement(multiElement, this.state, tupleToCoors(LinearElementEditor.getPointAtIndexGlobalCoordinates(multiElement, -1, nonDeletedElementsMap)), this.scene.getNonDeletedElementsMap(), this.scene.getNonDeletedElements());
|
|
1664
1679
|
}
|
|
1665
1680
|
this.store.commit(elementsMap, this.state);
|
|
1666
1681
|
// Do not notify consumers if we're still loading the scene. Among other
|
|
@@ -1849,6 +1864,24 @@ class App extends React.Component {
|
|
|
1849
1864
|
});
|
|
1850
1865
|
}
|
|
1851
1866
|
else if (data.text) {
|
|
1867
|
+
if (data.text && isMaybeMermaidDefinition(data.text)) {
|
|
1868
|
+
const api = await import("@excalidraw/mermaid-to-excalidraw");
|
|
1869
|
+
try {
|
|
1870
|
+
const { elements: skeletonElements, files } = await api.parseMermaidToExcalidraw(data.text);
|
|
1871
|
+
const elements = convertToExcalidrawElements(skeletonElements, {
|
|
1872
|
+
regenerateIds: true,
|
|
1873
|
+
});
|
|
1874
|
+
this.addElementsFromPasteOrLibrary({
|
|
1875
|
+
elements,
|
|
1876
|
+
files,
|
|
1877
|
+
position: "cursor",
|
|
1878
|
+
});
|
|
1879
|
+
return;
|
|
1880
|
+
}
|
|
1881
|
+
catch (err) {
|
|
1882
|
+
console.warn(`parsing pasted text as mermaid definition failed: ${err.message}`);
|
|
1883
|
+
}
|
|
1884
|
+
}
|
|
1852
1885
|
const nonEmptyLines = normalizeEOL(data.text)
|
|
1853
1886
|
.split(/\n+/)
|
|
1854
1887
|
.map((s) => s.trim())
|
|
@@ -2053,27 +2086,46 @@ class App extends React.Component {
|
|
|
2053
2086
|
text,
|
|
2054
2087
|
fontSize: this.state.currentItemFontSize,
|
|
2055
2088
|
fontFamily: this.state.currentItemFontFamily,
|
|
2056
|
-
textAlign:
|
|
2089
|
+
textAlign: DEFAULT_TEXT_ALIGN,
|
|
2057
2090
|
verticalAlign: DEFAULT_VERTICAL_ALIGN,
|
|
2058
2091
|
locked: false,
|
|
2059
2092
|
};
|
|
2093
|
+
const fontString = getFontString({
|
|
2094
|
+
fontSize: textElementProps.fontSize,
|
|
2095
|
+
fontFamily: textElementProps.fontFamily,
|
|
2096
|
+
});
|
|
2097
|
+
const lineHeight = getLineHeight(textElementProps.fontFamily);
|
|
2098
|
+
const [x1, , x2] = getVisibleSceneBounds(this.state);
|
|
2099
|
+
// long texts should not go beyond 800 pixels in width nor should it go below 200 px
|
|
2100
|
+
const maxTextWidth = Math.max(Math.min((x2 - x1) * 0.5, 800), 200);
|
|
2060
2101
|
const LINE_GAP = 10;
|
|
2061
2102
|
let currentY = y;
|
|
2062
2103
|
const lines = isPlainPaste ? [text] : text.split("\n");
|
|
2063
2104
|
const textElements = lines.reduce((acc, line, idx) => {
|
|
2064
|
-
const
|
|
2065
|
-
|
|
2066
|
-
if (text.length) {
|
|
2105
|
+
const originalText = line.trim();
|
|
2106
|
+
if (originalText.length) {
|
|
2067
2107
|
const topLayerFrame = this.getTopLayerFrameAtSceneCoords({
|
|
2068
2108
|
x,
|
|
2069
2109
|
y: currentY,
|
|
2070
2110
|
});
|
|
2111
|
+
let metrics = measureText(originalText, fontString, lineHeight);
|
|
2112
|
+
const isTextUnwrapped = metrics.width > maxTextWidth;
|
|
2113
|
+
const text = isTextUnwrapped
|
|
2114
|
+
? wrapText(originalText, fontString, maxTextWidth)
|
|
2115
|
+
: originalText;
|
|
2116
|
+
metrics = isTextUnwrapped
|
|
2117
|
+
? measureText(text, fontString, lineHeight)
|
|
2118
|
+
: metrics;
|
|
2119
|
+
const startX = x - metrics.width / 2;
|
|
2120
|
+
const startY = currentY - metrics.height / 2;
|
|
2071
2121
|
const element = newTextElement({
|
|
2072
2122
|
...textElementProps,
|
|
2073
|
-
x,
|
|
2074
|
-
y:
|
|
2123
|
+
x: startX,
|
|
2124
|
+
y: startY,
|
|
2075
2125
|
text,
|
|
2126
|
+
originalText,
|
|
2076
2127
|
lineHeight,
|
|
2128
|
+
autoResize: !isTextUnwrapped,
|
|
2077
2129
|
frameId: topLayerFrame ? topLayerFrame.id : null,
|
|
2078
2130
|
});
|
|
2079
2131
|
acc.push(element);
|
|
@@ -2292,7 +2344,7 @@ class App extends React.Component {
|
|
|
2292
2344
|
ShapeCache.delete(element);
|
|
2293
2345
|
}
|
|
2294
2346
|
});
|
|
2295
|
-
this.scene.
|
|
2347
|
+
this.scene.triggerUpdate();
|
|
2296
2348
|
this.addNewImagesToImageCache();
|
|
2297
2349
|
});
|
|
2298
2350
|
updateScene = withBatchedUpdates((sceneData) => {
|
|
@@ -2326,8 +2378,15 @@ class App extends React.Component {
|
|
|
2326
2378
|
this.setState({ collaborators: sceneData.collaborators });
|
|
2327
2379
|
}
|
|
2328
2380
|
});
|
|
2329
|
-
|
|
2330
|
-
|
|
2381
|
+
triggerRender = (
|
|
2382
|
+
/** force always re-renders canvas even if no change */
|
|
2383
|
+
force) => {
|
|
2384
|
+
if (force === true) {
|
|
2385
|
+
this.scene.triggerUpdate();
|
|
2386
|
+
}
|
|
2387
|
+
else {
|
|
2388
|
+
this.setState({});
|
|
2389
|
+
}
|
|
2331
2390
|
};
|
|
2332
2391
|
/**
|
|
2333
2392
|
* @returns whether the menu was toggled on or off
|
|
@@ -2459,13 +2518,23 @@ class App extends React.Component {
|
|
|
2459
2518
|
this.setState({ isBindingEnabled: false });
|
|
2460
2519
|
}
|
|
2461
2520
|
if (isArrowKey(event.key)) {
|
|
2462
|
-
const
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2521
|
+
const selectedElements = this.scene.getSelectedElements({
|
|
2522
|
+
selectedElementIds: this.state.selectedElementIds,
|
|
2523
|
+
includeBoundTextElement: true,
|
|
2524
|
+
includeElementsInFrames: true,
|
|
2525
|
+
});
|
|
2526
|
+
const elbowArrow = selectedElements.find(isElbowArrow);
|
|
2527
|
+
const step = elbowArrow
|
|
2528
|
+
? elbowArrow.startBinding || elbowArrow.endBinding
|
|
2529
|
+
? 0
|
|
2530
|
+
: ELEMENT_TRANSLATE_AMOUNT
|
|
2531
|
+
: (this.state.gridSize &&
|
|
2532
|
+
(event.shiftKey
|
|
2533
|
+
? ELEMENT_TRANSLATE_AMOUNT
|
|
2534
|
+
: this.state.gridSize)) ||
|
|
2535
|
+
(event.shiftKey
|
|
2536
|
+
? ELEMENT_SHIFT_TRANSLATE_AMOUNT
|
|
2537
|
+
: ELEMENT_TRANSLATE_AMOUNT);
|
|
2469
2538
|
let offsetX = 0;
|
|
2470
2539
|
let offsetY = 0;
|
|
2471
2540
|
if (event.key === KEYS.ARROW_LEFT) {
|
|
@@ -2480,22 +2549,17 @@ class App extends React.Component {
|
|
|
2480
2549
|
else if (event.key === KEYS.ARROW_DOWN) {
|
|
2481
2550
|
offsetY = step;
|
|
2482
2551
|
}
|
|
2483
|
-
const selectedElements = this.scene.getSelectedElements({
|
|
2484
|
-
selectedElementIds: this.state.selectedElementIds,
|
|
2485
|
-
includeBoundTextElement: true,
|
|
2486
|
-
includeElementsInFrames: true,
|
|
2487
|
-
});
|
|
2488
2552
|
selectedElements.forEach((element) => {
|
|
2489
2553
|
mutateElement(element, {
|
|
2490
2554
|
x: element.x + offsetX,
|
|
2491
2555
|
y: element.y + offsetY,
|
|
2492
2556
|
});
|
|
2493
|
-
updateBoundElements(element, this.scene.getNonDeletedElementsMap(), {
|
|
2557
|
+
updateBoundElements(element, this.scene.getNonDeletedElementsMap(), this.scene, {
|
|
2494
2558
|
simultaneouslyUpdated: selectedElements,
|
|
2495
2559
|
});
|
|
2496
2560
|
});
|
|
2497
2561
|
this.setState({
|
|
2498
|
-
suggestedBindings: getSuggestedBindingsForArrows(selectedElements, this),
|
|
2562
|
+
suggestedBindings: getSuggestedBindingsForArrows(selectedElements.filter((element) => element.id !== elbowArrow?.id || step !== 0), this.scene.getNonDeletedElementsMap()),
|
|
2499
2563
|
});
|
|
2500
2564
|
event.preventDefault();
|
|
2501
2565
|
}
|
|
@@ -2509,9 +2573,11 @@ class App extends React.Component {
|
|
|
2509
2573
|
this.state.editingLinearElement.elementId !==
|
|
2510
2574
|
selectedElements[0].id) {
|
|
2511
2575
|
this.store.shouldCaptureIncrement();
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2576
|
+
if (!isElbowArrow(selectedElement)) {
|
|
2577
|
+
this.setState({
|
|
2578
|
+
editingLinearElement: new LinearElementEditor(selectedElement),
|
|
2579
|
+
});
|
|
2580
|
+
}
|
|
2515
2581
|
}
|
|
2516
2582
|
}
|
|
2517
2583
|
}
|
|
@@ -2548,6 +2614,15 @@ class App extends React.Component {
|
|
|
2548
2614
|
if (this.state.activeTool.type !== shape) {
|
|
2549
2615
|
trackEvent("toolbar", shape, `keyboard (${this.device.editor.isMobile ? "mobile" : "desktop"})`);
|
|
2550
2616
|
}
|
|
2617
|
+
if (shape === "arrow" && this.state.activeTool.type === "arrow") {
|
|
2618
|
+
this.setState((prevState) => ({
|
|
2619
|
+
currentItemArrowType: prevState.currentItemArrowType === ARROW_TYPE.sharp
|
|
2620
|
+
? ARROW_TYPE.round
|
|
2621
|
+
: prevState.currentItemArrowType === ARROW_TYPE.round
|
|
2622
|
+
? ARROW_TYPE.elbow
|
|
2623
|
+
: ARROW_TYPE.sharp,
|
|
2624
|
+
}));
|
|
2625
|
+
}
|
|
2551
2626
|
this.setActiveTool({ type: shape });
|
|
2552
2627
|
event.stopPropagation();
|
|
2553
2628
|
}
|
|
@@ -2580,6 +2655,21 @@ class App extends React.Component {
|
|
|
2580
2655
|
event.stopPropagation();
|
|
2581
2656
|
}
|
|
2582
2657
|
}
|
|
2658
|
+
if (!event[KEYS.CTRL_OR_CMD] &&
|
|
2659
|
+
event.shiftKey &&
|
|
2660
|
+
event.key.toLowerCase() === KEYS.F) {
|
|
2661
|
+
const selectedElements = this.scene.getSelectedElements(this.state);
|
|
2662
|
+
if (this.state.activeTool.type === "selection" &&
|
|
2663
|
+
!selectedElements.length) {
|
|
2664
|
+
return;
|
|
2665
|
+
}
|
|
2666
|
+
if (this.state.activeTool.type === "text" ||
|
|
2667
|
+
selectedElements.find((element) => isTextElement(element) ||
|
|
2668
|
+
getBoundTextElement(element, this.scene.getNonDeletedElementsMap()))) {
|
|
2669
|
+
event.preventDefault();
|
|
2670
|
+
this.setState({ openPopup: "fontFamily" });
|
|
2671
|
+
}
|
|
2672
|
+
}
|
|
2583
2673
|
if (event.key === KEYS.K && !event.altKey && !event[KEYS.CTRL_OR_CMD]) {
|
|
2584
2674
|
if (this.state.activeTool.type === "laser") {
|
|
2585
2675
|
this.setActiveTool({ type: "selection" });
|
|
@@ -2634,7 +2724,7 @@ class App extends React.Component {
|
|
|
2634
2724
|
this.setState({ isBindingEnabled: true });
|
|
2635
2725
|
}
|
|
2636
2726
|
if (isArrowKey(event.key)) {
|
|
2637
|
-
bindOrUnbindLinearElements(this.scene.getSelectedElements(this.state).filter(isLinearElement), this, isBindingEnabled(this.state), this.state.selectedLinearElement?.selectedPointsIndices ?? []);
|
|
2727
|
+
bindOrUnbindLinearElements(this.scene.getSelectedElements(this.state).filter(isLinearElement), this.scene.getNonDeletedElementsMap(), this.scene.getNonDeletedElements(), this.scene, isBindingEnabled(this.state), this.state.selectedLinearElement?.selectedPointsIndices ?? []);
|
|
2638
2728
|
this.setState({ suggestedBindings: [] });
|
|
2639
2729
|
}
|
|
2640
2730
|
});
|
|
@@ -2772,15 +2862,16 @@ class App extends React.Component {
|
|
|
2772
2862
|
});
|
|
2773
2863
|
handleTextWysiwyg(element, { isExistingElement = false, }) {
|
|
2774
2864
|
const elementsMap = this.scene.getElementsMapIncludingDeleted();
|
|
2775
|
-
const updateElement = (
|
|
2865
|
+
const updateElement = (nextOriginalText, isDeleted) => {
|
|
2776
2866
|
this.scene.replaceAllElements([
|
|
2777
2867
|
// Not sure why we include deleted elements as well hence using deleted elements map
|
|
2778
2868
|
...this.scene.getElementsIncludingDeleted().map((_element) => {
|
|
2779
2869
|
if (_element.id === element.id && isTextElement(_element)) {
|
|
2780
|
-
return
|
|
2781
|
-
|
|
2782
|
-
isDeleted,
|
|
2783
|
-
|
|
2870
|
+
return newElementWith(_element, {
|
|
2871
|
+
originalText: nextOriginalText,
|
|
2872
|
+
isDeleted: isDeleted ?? _element.isDeleted,
|
|
2873
|
+
// returns (wrapped) text and new dimensions
|
|
2874
|
+
...refreshTextDimensions(_element, getContainerElement(_element, elementsMap), elementsMap, nextOriginalText),
|
|
2784
2875
|
});
|
|
2785
2876
|
}
|
|
2786
2877
|
return _element;
|
|
@@ -2800,15 +2891,15 @@ class App extends React.Component {
|
|
|
2800
2891
|
viewportY - this.state.offsetTop,
|
|
2801
2892
|
];
|
|
2802
2893
|
},
|
|
2803
|
-
onChange: withBatchedUpdates((
|
|
2804
|
-
updateElement(
|
|
2894
|
+
onChange: withBatchedUpdates((nextOriginalText) => {
|
|
2895
|
+
updateElement(nextOriginalText, false);
|
|
2805
2896
|
if (isNonDeletedElement(element)) {
|
|
2806
|
-
updateBoundElements(element, elementsMap);
|
|
2897
|
+
updateBoundElements(element, elementsMap, this.scene);
|
|
2807
2898
|
}
|
|
2808
2899
|
}),
|
|
2809
|
-
onSubmit: withBatchedUpdates(({
|
|
2810
|
-
const isDeleted = !
|
|
2811
|
-
updateElement(
|
|
2900
|
+
onSubmit: withBatchedUpdates(({ viaKeyboard, nextOriginalText }) => {
|
|
2901
|
+
const isDeleted = !nextOriginalText.trim();
|
|
2902
|
+
updateElement(nextOriginalText, isDeleted);
|
|
2812
2903
|
// select the created text element only if submitting via keyboard
|
|
2813
2904
|
// (when submitting via click it should act as signal to deselect)
|
|
2814
2905
|
if (!isDeleted && viaKeyboard) {
|
|
@@ -2842,12 +2933,17 @@ class App extends React.Component {
|
|
|
2842
2933
|
element,
|
|
2843
2934
|
excalidrawContainer: this.excalidrawContainerRef.current,
|
|
2844
2935
|
app: this,
|
|
2936
|
+
// when text is selected, it's hard (at least on iOS) to re-position the
|
|
2937
|
+
// caret (i.e. deselect). There's not much use for always selecting
|
|
2938
|
+
// the text on edit anyway (and users can select-all from contextmenu
|
|
2939
|
+
// if needed)
|
|
2940
|
+
autoSelect: !this.device.isTouchScreen,
|
|
2845
2941
|
});
|
|
2846
2942
|
// deselect all other elements when inserting text
|
|
2847
2943
|
this.deselectElements();
|
|
2848
2944
|
// do an initial update to re-initialize element position since we were
|
|
2849
2945
|
// modifying element's x/y for sake of editor (case: syncing to remote)
|
|
2850
|
-
updateElement(element.
|
|
2946
|
+
updateElement(element.originalText, false);
|
|
2851
2947
|
}
|
|
2852
2948
|
deselectElements() {
|
|
2853
2949
|
this.setState({
|
|
@@ -2866,57 +2962,6 @@ class App extends React.Component {
|
|
|
2866
2962
|
}
|
|
2867
2963
|
return null;
|
|
2868
2964
|
}
|
|
2869
|
-
/**
|
|
2870
|
-
* get the pure geometric shape of an excalidraw element
|
|
2871
|
-
* which is then used for hit detection
|
|
2872
|
-
*/
|
|
2873
|
-
getElementShape(element) {
|
|
2874
|
-
switch (element.type) {
|
|
2875
|
-
case "rectangle":
|
|
2876
|
-
case "diamond":
|
|
2877
|
-
case "frame":
|
|
2878
|
-
case "magicframe":
|
|
2879
|
-
case "embeddable":
|
|
2880
|
-
case "image":
|
|
2881
|
-
case "iframe":
|
|
2882
|
-
case "text":
|
|
2883
|
-
case "selection":
|
|
2884
|
-
return getPolygonShape(element);
|
|
2885
|
-
case "arrow":
|
|
2886
|
-
case "line": {
|
|
2887
|
-
const roughShape = ShapeCache.get(element)?.[0] ??
|
|
2888
|
-
ShapeCache.generateElementShape(element, null)[0];
|
|
2889
|
-
const [, , , , cx, cy] = getElementAbsoluteCoords(element, this.scene.getNonDeletedElementsMap());
|
|
2890
|
-
return shouldTestInside(element)
|
|
2891
|
-
? getClosedCurveShape(element, roughShape, [element.x, element.y], element.angle, [cx, cy])
|
|
2892
|
-
: getCurveShape(roughShape, [element.x, element.y], element.angle, [
|
|
2893
|
-
cx,
|
|
2894
|
-
cy,
|
|
2895
|
-
]);
|
|
2896
|
-
}
|
|
2897
|
-
case "ellipse":
|
|
2898
|
-
return getEllipseShape(element);
|
|
2899
|
-
case "freedraw": {
|
|
2900
|
-
const [, , , , cx, cy] = getElementAbsoluteCoords(element, this.scene.getNonDeletedElementsMap());
|
|
2901
|
-
return getFreedrawShape(element, [cx, cy], shouldTestInside(element));
|
|
2902
|
-
}
|
|
2903
|
-
}
|
|
2904
|
-
}
|
|
2905
|
-
getBoundTextShape(element) {
|
|
2906
|
-
const boundTextElement = getBoundTextElement(element, this.scene.getNonDeletedElementsMap());
|
|
2907
|
-
if (boundTextElement) {
|
|
2908
|
-
if (element.type === "arrow") {
|
|
2909
|
-
return this.getElementShape({
|
|
2910
|
-
...boundTextElement,
|
|
2911
|
-
// arrow's bound text accurate position is not stored in the element's property
|
|
2912
|
-
// but rather calculated and returned from the following static method
|
|
2913
|
-
...LinearElementEditor.getBoundTextElementPosition(element, boundTextElement, this.scene.getNonDeletedElementsMap()),
|
|
2914
|
-
});
|
|
2915
|
-
}
|
|
2916
|
-
return this.getElementShape(boundTextElement);
|
|
2917
|
-
}
|
|
2918
|
-
return null;
|
|
2919
|
-
}
|
|
2920
2965
|
getElementAtPosition(x, y, opts) {
|
|
2921
2966
|
const allHitElements = this.getElementsAtPosition(x, y, opts?.includeBoundTextElement, opts?.includeLockedElements);
|
|
2922
2967
|
if (allHitElements.length > 1) {
|
|
@@ -2934,7 +2979,7 @@ class App extends React.Component {
|
|
|
2934
2979
|
x,
|
|
2935
2980
|
y,
|
|
2936
2981
|
element: elementWithHighestZIndex,
|
|
2937
|
-
shape: this.
|
|
2982
|
+
shape: getElementShape(elementWithHighestZIndex, this.scene.getNonDeletedElementsMap()),
|
|
2938
2983
|
// when overlapping, we would like to be more precise
|
|
2939
2984
|
// this also avoids the need to update past tests
|
|
2940
2985
|
threshold: this.getElementHitThreshold() / 2,
|
|
@@ -2996,7 +3041,7 @@ class App extends React.Component {
|
|
|
2996
3041
|
return isPointInShape([x, y], selectionShape);
|
|
2997
3042
|
}
|
|
2998
3043
|
// take bound text element into consideration for hit collision as well
|
|
2999
|
-
const hitBoundTextOfElement = hitElementBoundText(x, y, this.
|
|
3044
|
+
const hitBoundTextOfElement = hitElementBoundText(x, y, getBoundTextShape(element, this.scene.getNonDeletedElementsMap()));
|
|
3000
3045
|
if (hitBoundTextOfElement) {
|
|
3001
3046
|
return true;
|
|
3002
3047
|
}
|
|
@@ -3004,7 +3049,7 @@ class App extends React.Component {
|
|
|
3004
3049
|
x,
|
|
3005
3050
|
y,
|
|
3006
3051
|
element,
|
|
3007
|
-
shape: this.
|
|
3052
|
+
shape: getElementShape(element, this.scene.getNonDeletedElementsMap()),
|
|
3008
3053
|
threshold: this.getElementHitThreshold(),
|
|
3009
3054
|
frameNameBound: isFrameLikeElement(element)
|
|
3010
3055
|
? this.frameNameBoundsCache.get(element)
|
|
@@ -3031,7 +3076,7 @@ class App extends React.Component {
|
|
|
3031
3076
|
x,
|
|
3032
3077
|
y,
|
|
3033
3078
|
element: elements[index],
|
|
3034
|
-
shape:
|
|
3079
|
+
shape: getElementShape(elements[index], this.scene.getNonDeletedElementsMap()),
|
|
3035
3080
|
threshold: this.getElementHitThreshold(),
|
|
3036
3081
|
})) {
|
|
3037
3082
|
hitElement = elements[index];
|
|
@@ -3044,7 +3089,7 @@ class App extends React.Component {
|
|
|
3044
3089
|
}
|
|
3045
3090
|
return isTextBindableContainer(hitElement, false) ? hitElement : null;
|
|
3046
3091
|
}
|
|
3047
|
-
startTextEditing = ({ sceneX, sceneY, insertAtParentCenter = true, container, }) => {
|
|
3092
|
+
startTextEditing = ({ sceneX, sceneY, insertAtParentCenter = true, container, autoEdit = true, }) => {
|
|
3048
3093
|
let shouldBindToContainer = false;
|
|
3049
3094
|
let parentCenterPosition = insertAtParentCenter &&
|
|
3050
3095
|
this.getTextWysiwygSnappedToCenterPosition(sceneX, sceneY, this.state, container);
|
|
@@ -3071,7 +3116,7 @@ class App extends React.Component {
|
|
|
3071
3116
|
existingTextElement = this.getTextElementAtPosition(sceneX, sceneY);
|
|
3072
3117
|
}
|
|
3073
3118
|
const fontFamily = existingTextElement?.fontFamily || this.state.currentItemFontFamily;
|
|
3074
|
-
const lineHeight = existingTextElement?.lineHeight ||
|
|
3119
|
+
const lineHeight = existingTextElement?.lineHeight || getLineHeight(fontFamily);
|
|
3075
3120
|
const fontSize = this.state.currentItemFontSize;
|
|
3076
3121
|
if (!existingTextElement &&
|
|
3077
3122
|
shouldBindToContainer &&
|
|
@@ -3145,12 +3190,17 @@ class App extends React.Component {
|
|
|
3145
3190
|
this.scene.insertElement(element);
|
|
3146
3191
|
}
|
|
3147
3192
|
}
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3193
|
+
if (autoEdit || existingTextElement || container) {
|
|
3194
|
+
this.handleTextWysiwyg(element, {
|
|
3195
|
+
isExistingElement: !!existingTextElement,
|
|
3196
|
+
});
|
|
3197
|
+
}
|
|
3198
|
+
else {
|
|
3199
|
+
this.setState({
|
|
3200
|
+
draggingElement: element,
|
|
3201
|
+
multiElement: null,
|
|
3202
|
+
});
|
|
3203
|
+
}
|
|
3154
3204
|
};
|
|
3155
3205
|
handleCanvasDoubleClick = (event) => {
|
|
3156
3206
|
// case: double-clicking with arrow/line tool selected would both create
|
|
@@ -3166,7 +3216,9 @@ class App extends React.Component {
|
|
|
3166
3216
|
if (selectedElements.length === 1 && isLinearElement(selectedElements[0])) {
|
|
3167
3217
|
if (event[KEYS.CTRL_OR_CMD] &&
|
|
3168
3218
|
(!this.state.editingLinearElement ||
|
|
3169
|
-
this.state.editingLinearElement.elementId !==
|
|
3219
|
+
this.state.editingLinearElement.elementId !==
|
|
3220
|
+
selectedElements[0].id) &&
|
|
3221
|
+
!isElbowArrow(selectedElements[0])) {
|
|
3170
3222
|
this.store.shouldCaptureIncrement();
|
|
3171
3223
|
this.setState({
|
|
3172
3224
|
editingLinearElement: new LinearElementEditor(selectedElements[0]),
|
|
@@ -3210,7 +3262,7 @@ class App extends React.Component {
|
|
|
3210
3262
|
x: sceneX,
|
|
3211
3263
|
y: sceneY,
|
|
3212
3264
|
element: container,
|
|
3213
|
-
shape: this.
|
|
3265
|
+
shape: getElementShape(container, this.scene.getNonDeletedElementsMap()),
|
|
3214
3266
|
threshold: this.getElementHitThreshold(),
|
|
3215
3267
|
})) {
|
|
3216
3268
|
const midPoint = getContainerCenter(container, this.state, this.scene.getNonDeletedElementsMap());
|
|
@@ -3317,8 +3369,11 @@ class App extends React.Component {
|
|
|
3317
3369
|
}, state);
|
|
3318
3370
|
this.translateCanvas({
|
|
3319
3371
|
zoom: zoomState.zoom,
|
|
3320
|
-
|
|
3321
|
-
|
|
3372
|
+
// 2x multiplier is just a magic number that makes this work correctly
|
|
3373
|
+
// on touchscreen devices (note: if we get report that panning is slower/faster
|
|
3374
|
+
// than actual movement, consider swapping with devicePixelRatio)
|
|
3375
|
+
scrollX: zoomState.scrollX + 2 * (deltaX / nextZoom),
|
|
3376
|
+
scrollY: zoomState.scrollY + 2 * (deltaY / nextZoom),
|
|
3322
3377
|
shouldCacheIgnoreZoom: true,
|
|
3323
3378
|
});
|
|
3324
3379
|
});
|
|
@@ -3381,7 +3436,7 @@ class App extends React.Component {
|
|
|
3381
3436
|
}
|
|
3382
3437
|
if (this.state.editingLinearElement &&
|
|
3383
3438
|
!this.state.editingLinearElement.isDragging) {
|
|
3384
|
-
const editingLinearElement = LinearElementEditor.handlePointerMove(event, scenePointerX, scenePointerY, this.state, this.scene
|
|
3439
|
+
const editingLinearElement = LinearElementEditor.handlePointerMove(event, scenePointerX, scenePointerY, this.state, this.scene);
|
|
3385
3440
|
if (editingLinearElement &&
|
|
3386
3441
|
editingLinearElement !== this.state.editingLinearElement) {
|
|
3387
3442
|
// Since we are reading from previous state which is not possible with
|
|
@@ -3443,7 +3498,9 @@ class App extends React.Component {
|
|
|
3443
3498
|
});
|
|
3444
3499
|
}
|
|
3445
3500
|
else {
|
|
3446
|
-
const [gridX, gridY] = getGridPoint(scenePointerX, scenePointerY, event[KEYS.CTRL_OR_CMD]
|
|
3501
|
+
const [gridX, gridY] = getGridPoint(scenePointerX, scenePointerY, event[KEYS.CTRL_OR_CMD] || isElbowArrow(multiElement)
|
|
3502
|
+
? null
|
|
3503
|
+
: this.state.gridSize);
|
|
3447
3504
|
const [lastCommittedX, lastCommittedY] = multiElement?.lastCommittedPoint ?? [0, 0];
|
|
3448
3505
|
let dxFromLastCommitted = gridX - rx - lastCommittedX;
|
|
3449
3506
|
let dyFromLastCommitted = gridY - ry - lastCommittedY;
|
|
@@ -3458,16 +3515,29 @@ class App extends React.Component {
|
|
|
3458
3515
|
if (isPathALoop(points, this.state.zoom.value)) {
|
|
3459
3516
|
setCursor(this.interactiveCanvas, CURSOR_TYPE.POINTER);
|
|
3460
3517
|
}
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
points: [
|
|
3518
|
+
if (isElbowArrow(multiElement)) {
|
|
3519
|
+
mutateElbowArrow(multiElement, this.scene, [
|
|
3464
3520
|
...points.slice(0, -1),
|
|
3465
3521
|
[
|
|
3466
3522
|
lastCommittedX + dxFromLastCommitted,
|
|
3467
3523
|
lastCommittedY + dyFromLastCommitted,
|
|
3468
3524
|
],
|
|
3469
|
-
],
|
|
3470
|
-
|
|
3525
|
+
], undefined, undefined, {
|
|
3526
|
+
isDragging: true,
|
|
3527
|
+
});
|
|
3528
|
+
}
|
|
3529
|
+
else {
|
|
3530
|
+
// update last uncommitted point
|
|
3531
|
+
mutateElement(multiElement, {
|
|
3532
|
+
points: [
|
|
3533
|
+
...points.slice(0, -1),
|
|
3534
|
+
[
|
|
3535
|
+
lastCommittedX + dxFromLastCommitted,
|
|
3536
|
+
lastCommittedY + dyFromLastCommitted,
|
|
3537
|
+
],
|
|
3538
|
+
],
|
|
3539
|
+
});
|
|
3540
|
+
}
|
|
3471
3541
|
}
|
|
3472
3542
|
return;
|
|
3473
3543
|
}
|
|
@@ -3488,8 +3558,9 @@ class App extends React.Component {
|
|
|
3488
3558
|
if (this.state.selectedLinearElement) {
|
|
3489
3559
|
this.handleHoverSelectedLinearElement(this.state.selectedLinearElement, scenePointerX, scenePointerY);
|
|
3490
3560
|
}
|
|
3491
|
-
if (!this.state.selectedLinearElement ||
|
|
3492
|
-
this.state.selectedLinearElement.hoverPointIndex === -1)
|
|
3561
|
+
if ((!this.state.selectedLinearElement ||
|
|
3562
|
+
this.state.selectedLinearElement.hoverPointIndex === -1) &&
|
|
3563
|
+
!(selectedElements.length === 1 && isElbowArrow(selectedElements[0]))) {
|
|
3493
3564
|
const elementWithTransformHandleType = getElementWithTransformHandleType(elements, this.state, scenePointerX, scenePointerY, this.state.zoom, event.pointerType, this.scene.getNonDeletedElementsMap(), this.device);
|
|
3494
3565
|
if (elementWithTransformHandleType &&
|
|
3495
3566
|
elementWithTransformHandleType.transformHandleType) {
|
|
@@ -3639,7 +3710,7 @@ class App extends React.Component {
|
|
|
3639
3710
|
}
|
|
3640
3711
|
}
|
|
3641
3712
|
this.elementsPendingErasure = new Set(this.elementsPendingErasure);
|
|
3642
|
-
this.
|
|
3713
|
+
this.triggerRender();
|
|
3643
3714
|
}
|
|
3644
3715
|
};
|
|
3645
3716
|
// set touch moving for mobile context menu
|
|
@@ -3659,7 +3730,7 @@ class App extends React.Component {
|
|
|
3659
3730
|
x: scenePointerX,
|
|
3660
3731
|
y: scenePointerY,
|
|
3661
3732
|
element,
|
|
3662
|
-
shape: this.
|
|
3733
|
+
shape: getElementShape(element, this.scene.getNonDeletedElementsMap()),
|
|
3663
3734
|
})) {
|
|
3664
3735
|
hoverPointIndex = LinearElementEditor.getPointIndexUnderCursor(element, elementsMap, this.state.zoom, scenePointerX, scenePointerY);
|
|
3665
3736
|
segmentMidPointHoveredCoords =
|
|
@@ -3672,7 +3743,10 @@ class App extends React.Component {
|
|
|
3672
3743
|
}
|
|
3673
3744
|
}
|
|
3674
3745
|
else if (this.hitElement(scenePointerX, scenePointerY, element)) {
|
|
3675
|
-
|
|
3746
|
+
if (!isElbowArrow(element) ||
|
|
3747
|
+
!(element.startBinding || element.endBinding)) {
|
|
3748
|
+
setCursor(this.interactiveCanvas, CURSOR_TYPE.MOVE);
|
|
3749
|
+
}
|
|
3676
3750
|
}
|
|
3677
3751
|
if (this.state.selectedLinearElement.hoverPointIndex !== hoverPointIndex) {
|
|
3678
3752
|
this.setState({
|
|
@@ -3850,7 +3924,6 @@ class App extends React.Component {
|
|
|
3850
3924
|
}
|
|
3851
3925
|
if (this.state.activeTool.type === "text") {
|
|
3852
3926
|
this.handleTextOnPointerDown(event, pointerDownState);
|
|
3853
|
-
return;
|
|
3854
3927
|
}
|
|
3855
3928
|
else if (this.state.activeTool.type === "arrow" ||
|
|
3856
3929
|
this.state.activeTool.type === "line") {
|
|
@@ -4086,10 +4159,13 @@ class App extends React.Component {
|
|
|
4086
4159
|
const origin = viewportCoordsToSceneCoords(event, this.state);
|
|
4087
4160
|
const selectedElements = this.scene.getSelectedElements(this.state);
|
|
4088
4161
|
const [minX, minY, maxX, maxY] = getCommonBounds(selectedElements);
|
|
4162
|
+
const isElbowArrowOnly = selectedElements.findIndex(isElbowArrow) === 0;
|
|
4089
4163
|
return {
|
|
4090
4164
|
origin,
|
|
4091
4165
|
withCmdOrCtrl: event[KEYS.CTRL_OR_CMD],
|
|
4092
|
-
originInGrid: tupleToCoors(getGridPoint(origin.x, origin.y, event[KEYS.CTRL_OR_CMD]
|
|
4166
|
+
originInGrid: tupleToCoors(getGridPoint(origin.x, origin.y, event[KEYS.CTRL_OR_CMD] || isElbowArrowOnly
|
|
4167
|
+
? null
|
|
4168
|
+
: this.state.gridSize)),
|
|
4093
4169
|
scrollbars: isOverScrollBars(currentScrollBars, event.clientX - this.state.offsetLeft, event.clientY - this.state.offsetTop),
|
|
4094
4170
|
// we need to duplicate because we'll be updating this state
|
|
4095
4171
|
lastCoords: { ...origin },
|
|
@@ -4206,7 +4282,7 @@ class App extends React.Component {
|
|
|
4206
4282
|
else {
|
|
4207
4283
|
if (this.state.selectedLinearElement) {
|
|
4208
4284
|
const linearElementEditor = this.state.editingLinearElement || this.state.selectedLinearElement;
|
|
4209
|
-
const ret = LinearElementEditor.handlePointerDown(event, this.state, this.store, pointerDownState.origin, linearElementEditor, this);
|
|
4285
|
+
const ret = LinearElementEditor.handlePointerDown(event, this.state, this.store, pointerDownState.origin, linearElementEditor, this.scene);
|
|
4210
4286
|
if (ret.hitElement) {
|
|
4211
4287
|
pointerDownState.hit.element = ret.hitElement;
|
|
4212
4288
|
}
|
|
@@ -4398,6 +4474,7 @@ class App extends React.Component {
|
|
|
4398
4474
|
sceneY,
|
|
4399
4475
|
insertAtParentCenter: !event.altKey,
|
|
4400
4476
|
container,
|
|
4477
|
+
autoEdit: false,
|
|
4401
4478
|
});
|
|
4402
4479
|
resetCursor(this.interactiveCanvas);
|
|
4403
4480
|
if (!this.state.activeTool.locked) {
|
|
@@ -4445,7 +4522,7 @@ class App extends React.Component {
|
|
|
4445
4522
|
points: [[0, 0]],
|
|
4446
4523
|
pressures,
|
|
4447
4524
|
});
|
|
4448
|
-
const boundElement = getHoveredElementForBinding(pointerDownState.origin, this);
|
|
4525
|
+
const boundElement = getHoveredElementForBinding(pointerDownState.origin, this.scene.getNonDeletedElements(), this.scene.getNonDeletedElementsMap());
|
|
4449
4526
|
this.scene.insertElement(element);
|
|
4450
4527
|
this.setState({
|
|
4451
4528
|
draggingElement: element,
|
|
@@ -4551,6 +4628,15 @@ class App extends React.Component {
|
|
|
4551
4628
|
this.actionManager.executeAction(actionFinalize);
|
|
4552
4629
|
return;
|
|
4553
4630
|
}
|
|
4631
|
+
// Elbow arrows cannot be created by putting down points
|
|
4632
|
+
// only the start and end points can be defined
|
|
4633
|
+
if (isElbowArrow(multiElement) && multiElement.points.length > 1) {
|
|
4634
|
+
mutateElement(multiElement, {
|
|
4635
|
+
lastCommittedPoint: multiElement.points[multiElement.points.length - 1],
|
|
4636
|
+
});
|
|
4637
|
+
this.actionManager.executeAction(actionFinalize);
|
|
4638
|
+
return;
|
|
4639
|
+
}
|
|
4554
4640
|
const { x: rx, y: ry, lastCommittedPoint } = multiElement;
|
|
4555
4641
|
// clicking inside commit zone → finalize arrow
|
|
4556
4642
|
if (multiElement.points.length > 1 &&
|
|
@@ -4586,25 +4672,46 @@ class App extends React.Component {
|
|
|
4586
4672
|
const [startArrowhead, endArrowhead] = elementType === "arrow"
|
|
4587
4673
|
? [currentItemStartArrowhead, currentItemEndArrowhead]
|
|
4588
4674
|
: [null, null];
|
|
4589
|
-
const element =
|
|
4590
|
-
|
|
4591
|
-
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
|
|
4595
|
-
|
|
4596
|
-
|
|
4597
|
-
|
|
4598
|
-
|
|
4599
|
-
|
|
4600
|
-
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
|
|
4604
|
-
|
|
4605
|
-
|
|
4606
|
-
|
|
4607
|
-
|
|
4675
|
+
const element = elementType === "arrow"
|
|
4676
|
+
? newArrowElement({
|
|
4677
|
+
type: elementType,
|
|
4678
|
+
x: gridX,
|
|
4679
|
+
y: gridY,
|
|
4680
|
+
strokeColor: this.state.currentItemStrokeColor,
|
|
4681
|
+
backgroundColor: this.state.currentItemBackgroundColor,
|
|
4682
|
+
fillStyle: this.state.currentItemFillStyle,
|
|
4683
|
+
strokeWidth: this.state.currentItemStrokeWidth,
|
|
4684
|
+
strokeStyle: this.state.currentItemStrokeStyle,
|
|
4685
|
+
roughness: this.state.currentItemRoughness,
|
|
4686
|
+
opacity: this.state.currentItemOpacity,
|
|
4687
|
+
roundness: this.state.currentItemArrowType === ARROW_TYPE.round
|
|
4688
|
+
? { type: ROUNDNESS.PROPORTIONAL_RADIUS }
|
|
4689
|
+
: // note, roundness doesn't have any effect for elbow arrows,
|
|
4690
|
+
// but it's best to set it to null as well
|
|
4691
|
+
null,
|
|
4692
|
+
startArrowhead,
|
|
4693
|
+
endArrowhead,
|
|
4694
|
+
locked: false,
|
|
4695
|
+
frameId: topLayerFrame ? topLayerFrame.id : null,
|
|
4696
|
+
elbowed: this.state.currentItemArrowType === ARROW_TYPE.elbow,
|
|
4697
|
+
})
|
|
4698
|
+
: newLinearElement({
|
|
4699
|
+
type: elementType,
|
|
4700
|
+
x: gridX,
|
|
4701
|
+
y: gridY,
|
|
4702
|
+
strokeColor: this.state.currentItemStrokeColor,
|
|
4703
|
+
backgroundColor: this.state.currentItemBackgroundColor,
|
|
4704
|
+
fillStyle: this.state.currentItemFillStyle,
|
|
4705
|
+
strokeWidth: this.state.currentItemStrokeWidth,
|
|
4706
|
+
strokeStyle: this.state.currentItemStrokeStyle,
|
|
4707
|
+
roughness: this.state.currentItemRoughness,
|
|
4708
|
+
opacity: this.state.currentItemOpacity,
|
|
4709
|
+
roundness: this.state.currentItemRoundness === "round"
|
|
4710
|
+
? { type: ROUNDNESS.PROPORTIONAL_RADIUS }
|
|
4711
|
+
: null,
|
|
4712
|
+
locked: false,
|
|
4713
|
+
frameId: topLayerFrame ? topLayerFrame.id : null,
|
|
4714
|
+
});
|
|
4608
4715
|
this.setState((prevState) => {
|
|
4609
4716
|
const nextSelectedElementIds = {
|
|
4610
4717
|
...prevState.selectedElementIds,
|
|
@@ -4617,7 +4724,7 @@ class App extends React.Component {
|
|
|
4617
4724
|
mutateElement(element, {
|
|
4618
4725
|
points: [...element.points, [0, 0]],
|
|
4619
4726
|
});
|
|
4620
|
-
const boundElement = getHoveredElementForBinding(pointerDownState.origin, this);
|
|
4727
|
+
const boundElement = getHoveredElementForBinding(pointerDownState.origin, this.scene.getNonDeletedElements(), this.scene.getNonDeletedElementsMap(), isElbowArrow(element));
|
|
4621
4728
|
this.scene.insertElement(element);
|
|
4622
4729
|
this.setState({
|
|
4623
4730
|
draggingElement: element,
|
|
@@ -4827,7 +4934,7 @@ class App extends React.Component {
|
|
|
4827
4934
|
}
|
|
4828
4935
|
const didDrag = LinearElementEditor.handlePointDragging(event, this.state, pointerCoords.x, pointerCoords.y, (element, pointsSceneCoords) => {
|
|
4829
4936
|
this.maybeSuggestBindingsForLinearElementAtCoords(element, pointsSceneCoords);
|
|
4830
|
-
}, linearElementEditor, this.scene
|
|
4937
|
+
}, linearElementEditor, this.scene);
|
|
4831
4938
|
if (didDrag) {
|
|
4832
4939
|
pointerDownState.lastCoords.x = pointerCoords.x;
|
|
4833
4940
|
pointerDownState.lastCoords.y = pointerCoords.y;
|
|
@@ -4913,10 +5020,14 @@ class App extends React.Component {
|
|
|
4913
5020
|
// when we're editing the name of a frame, we want the user to be
|
|
4914
5021
|
// able to select and interact with the text input
|
|
4915
5022
|
!this.state.editingFrame &&
|
|
4916
|
-
dragSelectedElements(pointerDownState, selectedElements, dragOffset, this.
|
|
4917
|
-
|
|
4918
|
-
|
|
4919
|
-
|
|
5023
|
+
dragSelectedElements(pointerDownState, selectedElements, dragOffset, this.scene, snapOffset, event[KEYS.CTRL_OR_CMD] ? null : this.state.gridSize);
|
|
5024
|
+
if (selectedElements.length !== 1 ||
|
|
5025
|
+
!isElbowArrow(selectedElements[0])) {
|
|
5026
|
+
this.setState({
|
|
5027
|
+
suggestedBindings: getSuggestedBindingsForArrows(selectedElements, this.scene.getNonDeletedElementsMap()),
|
|
5028
|
+
});
|
|
5029
|
+
}
|
|
5030
|
+
//}
|
|
4920
5031
|
// We duplicate the selected element if alt is pressed on pointer move
|
|
4921
5032
|
if (event.altKey && !pointerDownState.hit.hasBeenDuplicated) {
|
|
4922
5033
|
// Move the currently selected elements to the top of the z index stack, and
|
|
@@ -5009,6 +5120,11 @@ class App extends React.Component {
|
|
|
5009
5120
|
points: [...points, [dx, dy]],
|
|
5010
5121
|
});
|
|
5011
5122
|
}
|
|
5123
|
+
else if (points.length > 1 && isElbowArrow(draggingElement)) {
|
|
5124
|
+
mutateElbowArrow(draggingElement, this.scene, [...points.slice(0, -1), [dx, dy]], [0, 0], undefined, {
|
|
5125
|
+
isDragging: true,
|
|
5126
|
+
});
|
|
5127
|
+
}
|
|
5012
5128
|
else if (points.length === 2) {
|
|
5013
5129
|
mutateElement(draggingElement, {
|
|
5014
5130
|
points: [...points.slice(0, -1), [dx, dy]],
|
|
@@ -5152,7 +5268,7 @@ class App extends React.Component {
|
|
|
5152
5268
|
this.actionManager.executeAction(actionFinalize);
|
|
5153
5269
|
}
|
|
5154
5270
|
else {
|
|
5155
|
-
const editingLinearElement = LinearElementEditor.handlePointerUp(childEvent, this.state.editingLinearElement, this.state, this);
|
|
5271
|
+
const editingLinearElement = LinearElementEditor.handlePointerUp(childEvent, this.state.editingLinearElement, this.state, this.scene);
|
|
5156
5272
|
if (editingLinearElement !== this.state.editingLinearElement) {
|
|
5157
5273
|
this.setState({
|
|
5158
5274
|
editingLinearElement,
|
|
@@ -5171,11 +5287,11 @@ class App extends React.Component {
|
|
|
5171
5287
|
}
|
|
5172
5288
|
}
|
|
5173
5289
|
else {
|
|
5174
|
-
const linearElementEditor = LinearElementEditor.handlePointerUp(childEvent, this.state.selectedLinearElement, this.state, this);
|
|
5290
|
+
const linearElementEditor = LinearElementEditor.handlePointerUp(childEvent, this.state.selectedLinearElement, this.state, this.scene);
|
|
5175
5291
|
const { startBindingElement, endBindingElement } = linearElementEditor;
|
|
5176
5292
|
const element = this.scene.getElement(linearElementEditor.elementId);
|
|
5177
5293
|
if (isBindingElement(element)) {
|
|
5178
|
-
bindOrUnbindLinearElement(element, startBindingElement, endBindingElement, elementsMap);
|
|
5294
|
+
bindOrUnbindLinearElement(element, startBindingElement, endBindingElement, elementsMap, this.scene);
|
|
5179
5295
|
}
|
|
5180
5296
|
if (linearElementEditor !== this.state.selectedLinearElement) {
|
|
5181
5297
|
this.setState({
|
|
@@ -5263,7 +5379,7 @@ class App extends React.Component {
|
|
|
5263
5379
|
else if (pointerDownState.drag.hasOccurred && !multiElement) {
|
|
5264
5380
|
if (isBindingEnabled(this.state) &&
|
|
5265
5381
|
isBindingElement(draggingElement, false)) {
|
|
5266
|
-
maybeBindLinearElement(draggingElement, this.state, pointerCoords, this);
|
|
5382
|
+
maybeBindLinearElement(draggingElement, this.state, pointerCoords, this.scene.getNonDeletedElementsMap(), this.scene.getNonDeletedElements());
|
|
5267
5383
|
}
|
|
5268
5384
|
this.setState({ suggestedBindings: [], startBoundElement: null });
|
|
5269
5385
|
if (!activeTool.locked) {
|
|
@@ -5288,6 +5404,21 @@ class App extends React.Component {
|
|
|
5288
5404
|
}
|
|
5289
5405
|
return;
|
|
5290
5406
|
}
|
|
5407
|
+
if (isTextElement(draggingElement)) {
|
|
5408
|
+
const minWidth = getMinTextElementWidth(getFontString({
|
|
5409
|
+
fontSize: draggingElement.fontSize,
|
|
5410
|
+
fontFamily: draggingElement.fontFamily,
|
|
5411
|
+
}), draggingElement.lineHeight);
|
|
5412
|
+
if (draggingElement.width < minWidth) {
|
|
5413
|
+
mutateElement(draggingElement, {
|
|
5414
|
+
autoResize: true,
|
|
5415
|
+
});
|
|
5416
|
+
}
|
|
5417
|
+
this.resetCursor();
|
|
5418
|
+
this.handleTextWysiwyg(draggingElement, {
|
|
5419
|
+
isExistingElement: true,
|
|
5420
|
+
});
|
|
5421
|
+
}
|
|
5291
5422
|
if (activeTool.type !== "selection" &&
|
|
5292
5423
|
draggingElement &&
|
|
5293
5424
|
isInvisiblySmallElement(draggingElement)) {
|
|
@@ -5323,7 +5454,7 @@ class App extends React.Component {
|
|
|
5323
5454
|
groupIds: [],
|
|
5324
5455
|
});
|
|
5325
5456
|
removeElementsFromFrame([linearElement], this.scene.getNonDeletedElementsMap());
|
|
5326
|
-
this.scene.
|
|
5457
|
+
this.scene.triggerUpdate();
|
|
5327
5458
|
}
|
|
5328
5459
|
}
|
|
5329
5460
|
}
|
|
@@ -5556,7 +5687,7 @@ class App extends React.Component {
|
|
|
5556
5687
|
x: pointerDownState.origin.x,
|
|
5557
5688
|
y: pointerDownState.origin.y,
|
|
5558
5689
|
element: hitElement,
|
|
5559
|
-
shape: this.
|
|
5690
|
+
shape: getElementShape(hitElement, this.scene.getNonDeletedElementsMap()),
|
|
5560
5691
|
threshold: this.getElementHitThreshold(),
|
|
5561
5692
|
frameNameBound: isFrameLikeElement(hitElement)
|
|
5562
5693
|
? this.frameNameBoundsCache.get(hitElement)
|
|
@@ -5605,7 +5736,7 @@ class App extends React.Component {
|
|
|
5605
5736
|
const linearElements = this.scene
|
|
5606
5737
|
.getSelectedElements(this.state)
|
|
5607
5738
|
.filter(isLinearElement);
|
|
5608
|
-
bindOrUnbindLinearElements(linearElements, this, isBindingEnabled(this.state), this.state.selectedLinearElement?.selectedPointsIndices ?? []);
|
|
5739
|
+
bindOrUnbindLinearElements(linearElements, this.scene.getNonDeletedElementsMap(), this.scene.getNonDeletedElements(), this.scene, isBindingEnabled(this.state), this.state.selectedLinearElement?.selectedPointsIndices ?? []);
|
|
5609
5740
|
}
|
|
5610
5741
|
if (activeTool.type === "laser") {
|
|
5611
5742
|
this.laserTrails.endPath();
|
|
@@ -5640,7 +5771,7 @@ class App extends React.Component {
|
|
|
5640
5771
|
}
|
|
5641
5772
|
restoreReadyToEraseElements = () => {
|
|
5642
5773
|
this.elementsPendingErasure = new Set();
|
|
5643
|
-
this.
|
|
5774
|
+
this.triggerRender();
|
|
5644
5775
|
};
|
|
5645
5776
|
eraseElements = () => {
|
|
5646
5777
|
let didChange = false;
|
|
@@ -5932,7 +6063,7 @@ class App extends React.Component {
|
|
|
5932
6063
|
if (uncachedImageElements.length) {
|
|
5933
6064
|
const { updatedFiles } = await this.updateImageCache(uncachedImageElements, files);
|
|
5934
6065
|
if (updatedFiles.size) {
|
|
5935
|
-
this.scene.
|
|
6066
|
+
this.scene.triggerUpdate();
|
|
5936
6067
|
}
|
|
5937
6068
|
}
|
|
5938
6069
|
};
|
|
@@ -5948,7 +6079,7 @@ class App extends React.Component {
|
|
|
5948
6079
|
}
|
|
5949
6080
|
};
|
|
5950
6081
|
maybeSuggestBindingAtCursor = (pointerCoords) => {
|
|
5951
|
-
const hoveredBindableElement = getHoveredElementForBinding(pointerCoords, this);
|
|
6082
|
+
const hoveredBindableElement = getHoveredElementForBinding(pointerCoords, this.scene.getNonDeletedElements(), this.scene.getNonDeletedElementsMap());
|
|
5952
6083
|
this.setState({
|
|
5953
6084
|
suggestedBindings: hoveredBindableElement != null ? [hoveredBindableElement] : [],
|
|
5954
6085
|
});
|
|
@@ -5963,7 +6094,7 @@ class App extends React.Component {
|
|
|
5963
6094
|
return;
|
|
5964
6095
|
}
|
|
5965
6096
|
const suggestedBindings = pointerCoords.reduce((acc, coords) => {
|
|
5966
|
-
const hoveredBindableElement = getHoveredElementForBinding(coords, this);
|
|
6097
|
+
const hoveredBindableElement = getHoveredElementForBinding(coords, this.scene.getNonDeletedElements(), this.scene.getNonDeletedElementsMap(), isArrowElement(linearElement) && isElbowArrow(linearElement));
|
|
5967
6098
|
if (hoveredBindableElement != null &&
|
|
5968
6099
|
!isLinearElementSimpleAndAlreadyBound(linearElement, oppositeBindingBoundElement?.id, hoveredBindableElement)) {
|
|
5969
6100
|
acc.push(hoveredBindableElement);
|
|
@@ -6211,7 +6342,7 @@ class App extends React.Component {
|
|
|
6211
6342
|
}
|
|
6212
6343
|
if (draggingElement.type === "selection" &&
|
|
6213
6344
|
this.state.activeTool.type !== "eraser") {
|
|
6214
|
-
dragNewElement(draggingElement, this.state.activeTool.type, pointerDownState.origin.x, pointerDownState.origin.y, pointerCoords.x, pointerCoords.y, distance(pointerDownState.origin.x, pointerCoords.x), distance(pointerDownState.origin.y, pointerCoords.y), shouldMaintainAspectRatio(event), shouldResizeFromCenter(event));
|
|
6345
|
+
dragNewElement(draggingElement, this.state.activeTool.type, pointerDownState.origin.x, pointerDownState.origin.y, pointerCoords.x, pointerCoords.y, distance(pointerDownState.origin.x, pointerCoords.x), distance(pointerDownState.origin.y, pointerCoords.y), shouldMaintainAspectRatio(event), shouldResizeFromCenter(event), this.state.zoom.value);
|
|
6215
6346
|
}
|
|
6216
6347
|
else {
|
|
6217
6348
|
let [gridX, gridY] = getGridPoint(pointerCoords.x, pointerCoords.y, event[KEYS.CTRL_OR_CMD] ? null : this.state.gridSize);
|
|
@@ -6237,7 +6368,7 @@ class App extends React.Component {
|
|
|
6237
6368
|
});
|
|
6238
6369
|
dragNewElement(draggingElement, this.state.activeTool.type, pointerDownState.originInGrid.x, pointerDownState.originInGrid.y, gridX, gridY, distance(pointerDownState.originInGrid.x, gridX), distance(pointerDownState.originInGrid.y, gridY), isImageElement(draggingElement)
|
|
6239
6370
|
? !shouldMaintainAspectRatio(event)
|
|
6240
|
-
: shouldMaintainAspectRatio(event), shouldResizeFromCenter(event), aspectRatio, this.state.originSnapOffset);
|
|
6371
|
+
: shouldMaintainAspectRatio(event), shouldResizeFromCenter(event), this.state.zoom.value, aspectRatio, this.state.originSnapOffset);
|
|
6241
6372
|
// highlight elements that are to be added to frames on frames creation
|
|
6242
6373
|
if (this.state.activeTool.type === TOOL_TYPE.frame ||
|
|
6243
6374
|
this.state.activeTool.type === TOOL_TYPE.magicframe) {
|
|
@@ -6293,8 +6424,8 @@ class App extends React.Component {
|
|
|
6293
6424
|
}
|
|
6294
6425
|
if (transformElements(pointerDownState.originalElements, transformHandleType, selectedElements, this.scene.getElementsMapIncludingDeleted(), shouldRotateWithDiscreteAngle(event), shouldResizeFromCenter(event), selectedElements.some((element) => isImageElement(element))
|
|
6295
6426
|
? !shouldMaintainAspectRatio(event)
|
|
6296
|
-
: shouldMaintainAspectRatio(event), resizeX, resizeY, pointerDownState.resize.center.x, pointerDownState.resize.center.y)) {
|
|
6297
|
-
const suggestedBindings = getSuggestedBindingsForArrows(selectedElements, this);
|
|
6427
|
+
: shouldMaintainAspectRatio(event), resizeX, resizeY, pointerDownState.resize.center.x, pointerDownState.resize.center.y, this.scene)) {
|
|
6428
|
+
const suggestedBindings = getSuggestedBindingsForArrows(selectedElements, this.scene.getNonDeletedElementsMap());
|
|
6298
6429
|
const elementsToHighlight = new Set();
|
|
6299
6430
|
selectedFrames.forEach((frame) => {
|
|
6300
6431
|
getElementsInResizingFrame(this.scene.getNonDeletedElements(), frame, this.state, this.scene.getNonDeletedElementsMap()).forEach((element) => elementsToHighlight.add(element));
|
|
@@ -6346,6 +6477,7 @@ class App extends React.Component {
|
|
|
6346
6477
|
return [actionCopy, ...options];
|
|
6347
6478
|
}
|
|
6348
6479
|
return [
|
|
6480
|
+
CONTEXT_MENU_SEPARATOR,
|
|
6349
6481
|
actionCut,
|
|
6350
6482
|
actionCopy,
|
|
6351
6483
|
actionPaste,
|
|
@@ -6358,6 +6490,7 @@ class App extends React.Component {
|
|
|
6358
6490
|
actionPasteStyles,
|
|
6359
6491
|
CONTEXT_MENU_SEPARATOR,
|
|
6360
6492
|
actionGroup,
|
|
6493
|
+
actionTextAutoResize,
|
|
6361
6494
|
actionUnbindText,
|
|
6362
6495
|
actionBindText,
|
|
6363
6496
|
actionWrapTextInContainer,
|
|
@@ -6529,6 +6662,12 @@ export const createTestHook = () => {
|
|
|
6529
6662
|
return this.app?.scene.replaceAllElements(syncInvalidIndices(elements));
|
|
6530
6663
|
},
|
|
6531
6664
|
},
|
|
6665
|
+
scene: {
|
|
6666
|
+
configurable: true,
|
|
6667
|
+
get() {
|
|
6668
|
+
return this.app?.scene;
|
|
6669
|
+
},
|
|
6670
|
+
},
|
|
6532
6671
|
});
|
|
6533
6672
|
}
|
|
6534
6673
|
};
|