@excalidraw/excalidraw 0.17.1-1d71f84 → 0.17.1-22b3927
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 +14 -2
- package/dist/browser/dev/excalidraw-assets-dev/{blockDiagram-91b80b7a-ACFH36JV.js → blockDiagram-91b80b7a-H47FTXHA.js} +5 -5
- package/dist/browser/dev/excalidraw-assets-dev/{c4Diagram-b2a90758-QZ27YR47.js → c4Diagram-b2a90758-NNJK6GKC.js} +3 -3
- package/dist/browser/dev/excalidraw-assets-dev/{chunk-HO2HMSK7.js → chunk-4KQVEBHW.js} +3 -3
- package/dist/browser/dev/excalidraw-assets-dev/{chunk-USGV265L.js → chunk-53YI56GV.js} +4 -4
- package/dist/browser/dev/excalidraw-assets-dev/{chunk-EDFX3S7X.js → chunk-A2WCJI4I.js} +3 -3
- package/dist/browser/dev/excalidraw-assets-dev/{chunk-IX4V72YG.js → chunk-EFLPX7NE.js} +6 -6
- package/dist/browser/dev/excalidraw-assets-dev/{chunk-MXVETLVM.js → chunk-JYIQCNWV.js} +2 -2
- package/dist/browser/dev/excalidraw-assets-dev/{chunk-YZIOORVX.js → chunk-LVIQQW6F.js} +2 -2
- package/dist/browser/dev/excalidraw-assets-dev/{chunk-6U7GQNJT.js → chunk-PXLO3FOU.js} +2 -2
- package/dist/browser/dev/excalidraw-assets-dev/{chunk-AK7SWNLN.js → chunk-Q6A4M3MN.js} +9 -5
- package/dist/browser/dev/excalidraw-assets-dev/chunk-Q6A4M3MN.js.map +7 -0
- package/dist/browser/dev/excalidraw-assets-dev/{chunk-7DACDEY3.js → chunk-TO2AW5PW.js} +2 -2
- package/dist/browser/dev/excalidraw-assets-dev/{chunk-RWZVJAQU.js → chunk-VC7RRIDZ.js} +4657 -2673
- package/dist/browser/dev/excalidraw-assets-dev/chunk-VC7RRIDZ.js.map +7 -0
- package/dist/browser/dev/excalidraw-assets-dev/{chunk-NJ77ZFNJ.js → chunk-VURILHLY.js} +2 -2
- package/dist/browser/dev/excalidraw-assets-dev/{chunk-2T2GU7NF.js → chunk-ZAYGSUHF.js} +2 -2
- package/dist/browser/dev/excalidraw-assets-dev/{chunk-Z3PH3V2B.js → chunk-ZQR5ML6Y.js} +26 -26
- package/dist/browser/dev/excalidraw-assets-dev/chunk-ZQR5ML6Y.js.map +7 -0
- package/dist/browser/dev/excalidraw-assets-dev/{classDiagram-30eddba6-QSLMH4JW.js → classDiagram-30eddba6-CUYIJICN.js} +5 -5
- package/dist/browser/dev/excalidraw-assets-dev/{classDiagram-v2-f2df5561-DY4DYQ5P.js → classDiagram-v2-f2df5561-K6WW6K73.js} +8 -8
- package/dist/browser/dev/excalidraw-assets-dev/{dist-Z46EOVOL.js → dist-6QVAH5JA.js} +37 -15
- package/dist/browser/dev/excalidraw-assets-dev/dist-6QVAH5JA.js.map +7 -0
- package/dist/browser/dev/excalidraw-assets-dev/{en-5TCZHGGJ.js → en-Y27YPU72.js} +2 -2
- package/dist/browser/dev/excalidraw-assets-dev/{erDiagram-47591fe2-SOOJRTCB.js → erDiagram-47591fe2-XGAD7EEP.js} +4 -4
- package/dist/browser/dev/excalidraw-assets-dev/{flowDiagram-5540d9b9-AHGL4KPK.js → flowDiagram-5540d9b9-B6EOVNNO.js} +9 -9
- package/dist/browser/dev/excalidraw-assets-dev/{flowDiagram-v2-3b53844e-56LDZZWY.js → flowDiagram-v2-3b53844e-NUG24FJH.js} +9 -9
- package/dist/browser/dev/excalidraw-assets-dev/{flowchart-elk-definition-5fe447d6-27LUKRI6.js → flowchart-elk-definition-5fe447d6-25Y7PCBL.js} +5 -5
- package/dist/browser/dev/excalidraw-assets-dev/{ganttDiagram-9a3bba1f-EHGYGNG6.js → ganttDiagram-9a3bba1f-GNL6ZDTC.js} +2 -2
- package/dist/browser/dev/excalidraw-assets-dev/{gitGraphDiagram-96e6b4ee-AJQNBDW5.js → gitGraphDiagram-96e6b4ee-HNW52NVO.js} +2 -2
- package/dist/browser/dev/excalidraw-assets-dev/{image-EDKQZH7Z.js → image-J7S3ALXP.js} +2 -2
- package/dist/browser/dev/excalidraw-assets-dev/{image-OFRRV5MB.css → image-O66MQ7WQ.css} +1 -1
- package/dist/browser/dev/excalidraw-assets-dev/image-O66MQ7WQ.css.map +7 -0
- package/dist/browser/dev/excalidraw-assets-dev/{infoDiagram-bcd20f53-SWLLQVES.js → infoDiagram-bcd20f53-FWEUVFLT.js} +2 -2
- package/dist/browser/dev/excalidraw-assets-dev/{journeyDiagram-4fe6b3dc-7UAVCWOZ.js → journeyDiagram-4fe6b3dc-RZIUI7UG.js} +3 -3
- package/dist/browser/dev/excalidraw-assets-dev/{mindmap-definition-f354de21-SROW5KGM.js → mindmap-definition-f354de21-GBVN45GU.js} +3 -3
- package/dist/browser/dev/excalidraw-assets-dev/{pieDiagram-79897490-QKCI6NCB.js → pieDiagram-79897490-ECENNII6.js} +2 -2
- package/dist/browser/dev/excalidraw-assets-dev/{quadrantDiagram-62f64e94-LNYJZFC5.js → quadrantDiagram-62f64e94-ZMEOFVNL.js} +2 -2
- package/dist/browser/dev/excalidraw-assets-dev/{requirementDiagram-05bf5f74-ZZD7ZHFA.js → requirementDiagram-05bf5f74-FHZSFHCR.js} +4 -4
- package/dist/browser/dev/excalidraw-assets-dev/{sankeyDiagram-97764748-L75ZZ4UM.js → sankeyDiagram-97764748-VDKIKTA6.js} +2 -2
- package/dist/browser/dev/excalidraw-assets-dev/{sequenceDiagram-acc0e65c-6PCU7TDK.js → sequenceDiagram-acc0e65c-6JUSPVKX.js} +3 -3
- package/dist/browser/dev/excalidraw-assets-dev/{stateDiagram-0ff1cf1a-WM76WOPR.js → stateDiagram-0ff1cf1a-L3AKWENF.js} +5 -5
- package/dist/browser/dev/excalidraw-assets-dev/{stateDiagram-v2-9a9d610d-N4HZW3O2.js → stateDiagram-v2-9a9d610d-NU3GGMCH.js} +8 -8
- package/dist/browser/dev/excalidraw-assets-dev/{timeline-definition-fea2a41d-ZHGCAXGP.js → timeline-definition-fea2a41d-JGP7XCHW.js} +2 -2
- package/dist/browser/dev/excalidraw-assets-dev/{xychartDiagram-ab372869-2DLOVRAZ.js → xychartDiagram-ab372869-HLFHHF2I.js} +3 -3
- package/dist/browser/dev/index.css +72 -28
- package/dist/browser/dev/index.css.map +3 -3
- package/dist/browser/dev/index.js +2387 -1934
- package/dist/browser/dev/index.js.map +4 -4
- package/dist/browser/prod/excalidraw-assets/{blockDiagram-91b80b7a-ONPS22AM.js → blockDiagram-91b80b7a-FVCRVGN5.js} +1 -1
- package/dist/browser/prod/excalidraw-assets/{c4Diagram-b2a90758-XMIQY7ZT.js → c4Diagram-b2a90758-56CXO7GA.js} +1 -1
- package/dist/browser/prod/excalidraw-assets/{chunk-GCHQBOKV.js → chunk-635MQ3CK.js} +1 -1
- package/dist/browser/prod/excalidraw-assets/{chunk-P5M3G2RP.js → chunk-AIKXYJX3.js} +1 -1
- package/dist/browser/prod/excalidraw-assets/{chunk-E2YLWFZX.js → chunk-CR7VMNWC.js} +1 -1
- package/dist/browser/prod/excalidraw-assets/chunk-CWO763YJ.js +55 -0
- package/dist/browser/prod/excalidraw-assets/{chunk-WEYK4A2L.js → chunk-FFF2CSVG.js} +1 -1
- package/dist/browser/prod/excalidraw-assets/{chunk-R3HAIP6R.js → chunk-G4WDCSPE.js} +1 -1
- package/dist/browser/prod/excalidraw-assets/{chunk-HFOXJM22.js → chunk-HKZSHFLX.js} +1 -1
- package/dist/browser/prod/excalidraw-assets/{chunk-XIMFFJTE.js → chunk-IKCDYWMW.js} +1 -1
- package/dist/browser/prod/excalidraw-assets/{chunk-CTYINSWT.js → chunk-IZMZ6RPD.js} +2 -2
- package/dist/browser/prod/excalidraw-assets/{chunk-AHLLBBVJ.js → chunk-L5DS24G6.js} +1 -1
- package/dist/browser/prod/excalidraw-assets/{chunk-CQJF3C6G.js → chunk-MUNOKHUD.js} +1 -1
- package/dist/browser/prod/excalidraw-assets/{chunk-NI6SYCUG.js → chunk-QOQYOOQ4.js} +1 -1
- package/dist/browser/prod/excalidraw-assets/{chunk-I2PZFXTK.js → chunk-ZTIWFPBM.js} +21 -21
- package/dist/browser/prod/excalidraw-assets/{classDiagram-30eddba6-IEJXXCVX.js → classDiagram-30eddba6-BCUTAUMD.js} +1 -1
- package/dist/browser/prod/excalidraw-assets/{classDiagram-v2-f2df5561-7LZDSWOS.js → classDiagram-v2-f2df5561-6SOXSGQ2.js} +1 -1
- package/dist/browser/prod/excalidraw-assets/dist-567JAXHK.js +7 -0
- package/dist/browser/prod/excalidraw-assets/{en-LROPV2RN.js → en-GSUSWMSH.js} +1 -1
- package/dist/browser/prod/excalidraw-assets/{erDiagram-47591fe2-E5V666CF.js → erDiagram-47591fe2-RE6HB7RM.js} +1 -1
- package/dist/browser/prod/excalidraw-assets/{flowDiagram-5540d9b9-GMBRCYVF.js → flowDiagram-5540d9b9-ZNJZBERW.js} +1 -1
- package/dist/browser/prod/excalidraw-assets/{flowDiagram-v2-3b53844e-Z4HUWP6B.js → flowDiagram-v2-3b53844e-LY44JLQJ.js} +1 -1
- package/dist/browser/prod/excalidraw-assets/{flowchart-elk-definition-5fe447d6-5ZCYTX5N.js → flowchart-elk-definition-5fe447d6-TMTJ6Z7O.js} +1 -1
- package/dist/browser/prod/excalidraw-assets/{ganttDiagram-9a3bba1f-WM32OMT5.js → ganttDiagram-9a3bba1f-5O6EA6LX.js} +1 -1
- package/dist/browser/prod/excalidraw-assets/{gitGraphDiagram-96e6b4ee-CAKZ2U6E.js → gitGraphDiagram-96e6b4ee-UHYNM5DI.js} +1 -1
- package/dist/browser/prod/excalidraw-assets/image-SZBFRCU2.js +1 -0
- package/dist/browser/prod/excalidraw-assets/{infoDiagram-bcd20f53-MUIKXGC4.js → infoDiagram-bcd20f53-BP77NQEH.js} +1 -1
- package/dist/browser/prod/excalidraw-assets/{journeyDiagram-4fe6b3dc-NYRV4HK2.js → journeyDiagram-4fe6b3dc-XMGKCMES.js} +1 -1
- package/dist/browser/prod/excalidraw-assets/{mindmap-definition-f354de21-MY55DRSM.js → mindmap-definition-f354de21-ZQRRBRWF.js} +1 -1
- package/dist/browser/prod/excalidraw-assets/{pieDiagram-79897490-47L6J6L2.js → pieDiagram-79897490-IGXEC2KX.js} +1 -1
- package/dist/browser/prod/excalidraw-assets/{quadrantDiagram-62f64e94-DF5C2GDT.js → quadrantDiagram-62f64e94-WTHHDYJL.js} +1 -1
- package/dist/browser/prod/excalidraw-assets/{requirementDiagram-05bf5f74-C4IMUBDN.js → requirementDiagram-05bf5f74-MV4OFRVW.js} +1 -1
- package/dist/browser/prod/excalidraw-assets/{sankeyDiagram-97764748-YHW7EUST.js → sankeyDiagram-97764748-ZGYUHEJT.js} +1 -1
- package/dist/browser/prod/excalidraw-assets/{sequenceDiagram-acc0e65c-H3XEHT32.js → sequenceDiagram-acc0e65c-IBSENK6W.js} +1 -1
- package/dist/browser/prod/excalidraw-assets/{stateDiagram-0ff1cf1a-Z5WB6Q3P.js → stateDiagram-0ff1cf1a-DB73XNZH.js} +1 -1
- package/dist/browser/prod/excalidraw-assets/{stateDiagram-v2-9a9d610d-T7OZETQC.js → stateDiagram-v2-9a9d610d-2OOBUPNR.js} +1 -1
- package/dist/browser/prod/excalidraw-assets/{timeline-definition-fea2a41d-VVC22BWF.js → timeline-definition-fea2a41d-P3NQQVDU.js} +1 -1
- package/dist/browser/prod/excalidraw-assets/{xychartDiagram-ab372869-JAXODQF7.js → xychartDiagram-ab372869-HI3XLK3Y.js} +1 -1
- package/dist/browser/prod/index.css +1 -1
- package/dist/browser/prod/index.js +24 -24
- package/dist/dev/{en-II4GK66F.json → en-OIPCBIOA.json} +8 -4
- package/dist/dev/index.css +72 -28
- package/dist/dev/index.css.map +3 -3
- package/dist/dev/index.js +5866 -3499
- package/dist/dev/index.js.map +4 -4
- package/dist/excalidraw/actions/actionAddToLibrary.d.ts +4 -4
- package/dist/excalidraw/actions/actionAddToLibrary.js +4 -3
- package/dist/excalidraw/actions/actionAlign.d.ts +22 -22
- package/dist/excalidraw/actions/actionAlign.js +7 -6
- package/dist/excalidraw/actions/actionBoundText.d.ts +10 -10
- package/dist/excalidraw/actions/actionBoundText.js +11 -5
- package/dist/excalidraw/actions/actionCanvas.d.ts +52 -52
- package/dist/excalidraw/actions/actionCanvas.js +19 -14
- package/dist/excalidraw/actions/actionClipboard.d.ts +24 -24
- package/dist/excalidraw/actions/actionClipboard.js +14 -13
- package/dist/excalidraw/actions/actionDeleteSelected.d.ts +10 -10
- package/dist/excalidraw/actions/actionDeleteSelected.js +6 -3
- package/dist/excalidraw/actions/actionDistribute.d.ts +10 -10
- package/dist/excalidraw/actions/actionDistribute.js +3 -2
- package/dist/excalidraw/actions/actionDuplicateSelection.d.ts +7 -8
- package/dist/excalidraw/actions/actionDuplicateSelection.js +7 -3
- package/dist/excalidraw/actions/actionElementLock.d.ts +9 -9
- package/dist/excalidraw/actions/actionElementLock.js +3 -2
- package/dist/excalidraw/actions/actionExport.d.ts +33 -33
- package/dist/excalidraw/actions/actionExport.js +15 -11
- package/dist/excalidraw/actions/actionFinalize.d.ts +9 -9
- package/dist/excalidraw/actions/actionFinalize.js +9 -5
- package/dist/excalidraw/actions/actionFlip.d.ts +10 -10
- package/dist/excalidraw/actions/actionFlip.js +12 -12
- package/dist/excalidraw/actions/actionFrame.d.ts +171 -18
- package/dist/excalidraw/actions/actionFrame.js +7 -6
- package/dist/excalidraw/actions/actionGroup.d.ts +16 -16
- package/dist/excalidraw/actions/actionGroup.js +9 -11
- package/dist/excalidraw/actions/actionHistory.d.ts +4 -3
- package/dist/excalidraw/actions/actionHistory.js +27 -28
- package/dist/excalidraw/actions/actionLinearEditor.d.ts +6 -4
- package/dist/excalidraw/actions/actionLinearEditor.js +21 -5
- package/dist/excalidraw/actions/actionLink.d.ts +5 -5
- package/dist/excalidraw/actions/actionLink.js +2 -1
- package/dist/excalidraw/actions/actionMenu.d.ts +8 -8
- package/dist/excalidraw/actions/actionMenu.js +4 -3
- package/dist/excalidraw/actions/actionNavigate.d.ts +4 -4
- package/dist/excalidraw/actions/actionNavigate.js +3 -2
- package/dist/excalidraw/actions/actionProperties.d.ts +34 -34
- package/dist/excalidraw/actions/actionProperties.js +19 -14
- package/dist/excalidraw/actions/actionSelectAll.d.ts +5 -5
- package/dist/excalidraw/actions/actionSelectAll.js +2 -1
- package/dist/excalidraw/actions/actionStyles.d.ts +11 -11
- package/dist/excalidraw/actions/actionStyles.js +4 -3
- package/dist/excalidraw/actions/actionTextAutoResize.d.ts +17 -0
- package/dist/excalidraw/actions/actionTextAutoResize.js +38 -0
- package/dist/excalidraw/actions/actionToggleGridMode.d.ts +7 -5
- package/dist/excalidraw/actions/actionToggleGridMode.js +6 -2
- package/dist/excalidraw/actions/actionToggleObjectsSnapMode.d.ts +4 -4
- package/dist/excalidraw/actions/actionToggleObjectsSnapMode.js +2 -1
- package/dist/excalidraw/actions/actionToggleStats.d.ts +4 -4
- package/dist/excalidraw/actions/actionToggleStats.js +2 -1
- package/dist/excalidraw/actions/actionToggleViewMode.d.ts +4 -4
- package/dist/excalidraw/actions/actionToggleViewMode.js +2 -1
- package/dist/excalidraw/actions/actionToggleZenMode.d.ts +4 -4
- package/dist/excalidraw/actions/actionToggleZenMode.js +2 -1
- package/dist/excalidraw/actions/actionZindex.d.ts +23 -19
- package/dist/excalidraw/actions/actionZindex.js +9 -4
- package/dist/excalidraw/actions/manager.d.ts +5 -5
- package/dist/excalidraw/actions/register.d.ts +1 -1
- package/dist/excalidraw/actions/shortcuts.d.ts +2 -2
- package/dist/excalidraw/actions/shortcuts.js +1 -1
- package/dist/excalidraw/actions/types.d.ts +8 -8
- package/dist/excalidraw/align.d.ts +1 -1
- package/dist/excalidraw/analytics.js +1 -1
- package/dist/excalidraw/animated-trail.d.ts +2 -2
- package/dist/excalidraw/appState.d.ts +5 -5
- package/dist/excalidraw/change.d.ts +191 -0
- package/dist/excalidraw/change.js +901 -0
- package/dist/excalidraw/charts.d.ts +1 -1
- 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 +9 -6
- package/dist/excalidraw/components/App.d.ts +28 -14
- package/dist/excalidraw/components/App.js +491 -204
- package/dist/excalidraw/components/ButtonIconSelect.js +1 -1
- 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 +1 -1
- package/dist/excalidraw/components/ColorPicker/Picker.d.ts +3 -3
- 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 +30 -15
- 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/DarkModeToggle.js +3 -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/HelpDialog.js +8 -6
- package/dist/excalidraw/components/HintViewer.d.ts +1 -1
- 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 +2 -2
- 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 +1 -1
- 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/PublishLibrary.d.ts +1 -1
- package/dist/excalidraw/components/RadioGroup.d.ts +2 -1
- package/dist/excalidraw/components/RadioGroup.js +1 -1
- package/dist/excalidraw/components/SVGLayer.d.ts +1 -1
- package/dist/excalidraw/components/Sidebar/Sidebar.d.ts +2 -2
- 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/Stack.d.ts +2 -2
- package/dist/excalidraw/components/Stats.d.ts +2 -2
- package/dist/excalidraw/components/TTDDialog/MermaidToExcalidraw.d.ts +1 -1
- package/dist/excalidraw/components/TTDDialog/MermaidToExcalidraw.js +6 -2
- 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 +4 -4
- 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 +4 -2
- package/dist/excalidraw/components/ToolButton.js +1 -1
- package/dist/excalidraw/components/Trans.d.ts +1 -1
- package/dist/excalidraw/components/UserList.d.ts +1 -1
- package/dist/excalidraw/components/canvases/InteractiveCanvas.d.ts +5 -3
- package/dist/excalidraw/components/canvases/InteractiveCanvas.js +5 -2
- package/dist/excalidraw/components/canvases/StaticCanvas.d.ts +2 -2
- package/dist/excalidraw/components/canvases/StaticCanvas.js +2 -2
- package/dist/excalidraw/components/dropdownMenu/DropdownMenuItem.js +2 -2
- package/dist/excalidraw/components/dropdownMenu/DropdownMenuItemContentRadio.d.ts +18 -0
- package/dist/excalidraw/components/dropdownMenu/DropdownMenuItemContentRadio.js +9 -0
- 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/Hyperlink.js +3 -3
- package/dist/excalidraw/components/hyperlink/helpers.d.ts +3 -3
- package/dist/excalidraw/components/hyperlink/helpers.js +2 -3
- package/dist/excalidraw/components/icons.d.ts +6 -1
- package/dist/excalidraw/components/icons.js +23 -5
- package/dist/excalidraw/components/main-menu/DefaultItems.d.ts +12 -2
- package/dist/excalidraw/components/main-menu/DefaultItems.js +38 -7
- package/dist/excalidraw/constants.d.ts +6 -5
- package/dist/excalidraw/constants.js +11 -3
- 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/magic.js +2 -1
- package/dist/excalidraw/data/reconcile.d.ts +6 -0
- package/dist/excalidraw/data/reconcile.js +49 -0
- package/dist/excalidraw/data/resave.d.ts +2 -2
- package/dist/excalidraw/data/restore.d.ts +5 -5
- package/dist/excalidraw/data/restore.js +9 -7
- package/dist/excalidraw/data/transform.d.ts +4 -4
- package/dist/excalidraw/data/transform.js +12 -3
- package/dist/excalidraw/data/types.d.ts +3 -3
- package/dist/excalidraw/data/url.d.ts +1 -0
- package/dist/excalidraw/data/url.js +4 -1
- package/dist/excalidraw/element/ElementCanvasButtons.d.ts +1 -1
- package/dist/excalidraw/element/binding.d.ts +50 -9
- package/dist/excalidraw/element/binding.js +712 -155
- package/dist/excalidraw/element/bounds.d.ts +3 -4
- package/dist/excalidraw/element/bounds.js +0 -3
- package/dist/excalidraw/element/collision.d.ts +14 -19
- package/dist/excalidraw/element/collision.js +36 -713
- package/dist/excalidraw/element/containerCache.d.ts +1 -1
- package/dist/excalidraw/element/dragElements.d.ts +4 -4
- package/dist/excalidraw/element/dragElements.js +27 -3
- package/dist/excalidraw/element/embeddable.d.ts +9 -6
- package/dist/excalidraw/element/embeddable.js +98 -62
- package/dist/excalidraw/element/image.d.ts +2 -2
- package/dist/excalidraw/element/index.d.ts +2 -3
- package/dist/excalidraw/element/index.js +1 -2
- package/dist/excalidraw/element/linearElementEditor.d.ts +12 -12
- package/dist/excalidraw/element/linearElementEditor.js +7 -5
- package/dist/excalidraw/element/mutateElement.d.ts +4 -5
- package/dist/excalidraw/element/mutateElement.js +5 -3
- package/dist/excalidraw/element/newElement.d.ts +6 -9
- package/dist/excalidraw/element/newElement.js +18 -15
- package/dist/excalidraw/element/resizeElements.d.ts +4 -4
- package/dist/excalidraw/element/resizeElements.js +172 -96
- package/dist/excalidraw/element/resizeTest.d.ts +7 -7
- package/dist/excalidraw/element/resizeTest.js +53 -8
- package/dist/excalidraw/element/showSelectedShapeActions.d.ts +2 -2
- package/dist/excalidraw/element/sizeHelpers.d.ts +2 -2
- package/dist/excalidraw/element/sizeHelpers.js +3 -0
- package/dist/excalidraw/element/sortElements.d.ts +1 -1
- package/dist/excalidraw/element/textElement.d.ts +6 -6
- package/dist/excalidraw/element/textElement.js +16 -37
- package/dist/excalidraw/element/textWysiwyg.d.ts +12 -6
- package/dist/excalidraw/element/textWysiwyg.js +38 -17
- package/dist/excalidraw/element/transformHandles.d.ts +24 -6
- package/dist/excalidraw/element/transformHandles.js +22 -11
- package/dist/excalidraw/element/typeChecks.d.ts +4 -4
- package/dist/excalidraw/element/types.d.ts +33 -10
- package/dist/excalidraw/emitter.d.ts +1 -1
- package/dist/excalidraw/errors.d.ts +3 -0
- package/dist/excalidraw/errors.js +3 -0
- package/dist/excalidraw/fractionalIndex.d.ts +40 -0
- package/dist/excalidraw/fractionalIndex.js +239 -0
- package/dist/excalidraw/frame.d.ts +4 -4
- package/dist/excalidraw/gatransforms.d.ts +1 -1
- package/dist/excalidraw/gesture.d.ts +1 -1
- package/dist/excalidraw/groups.d.ts +5 -3
- package/dist/excalidraw/groups.js +17 -0
- package/dist/excalidraw/history.d.ts +35 -47
- package/dist/excalidraw/history.js +100 -167
- package/dist/excalidraw/hooks/useCreatePortalContainer.js +2 -1
- package/dist/excalidraw/hooks/useEmitter.d.ts +2 -0
- package/dist/excalidraw/hooks/useEmitter.js +13 -0
- package/dist/excalidraw/hooks/useLibraryItemSvg.d.ts +1 -1
- package/dist/excalidraw/i18n.d.ts +1 -1
- package/dist/excalidraw/index.d.ts +3 -1
- package/dist/excalidraw/index.js +2 -0
- package/dist/excalidraw/jotai.d.ts +1 -1
- package/dist/excalidraw/laser-trails.d.ts +3 -2
- package/dist/excalidraw/locales/en.json +8 -4
- package/dist/excalidraw/math.d.ts +2 -2
- package/dist/excalidraw/mermaid.d.ts +2 -0
- package/dist/excalidraw/mermaid.js +28 -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/helpers.js +2 -2
- package/dist/excalidraw/renderer/interactiveScene.d.ts +2 -2
- package/dist/excalidraw/renderer/interactiveScene.js +38 -11
- package/dist/excalidraw/renderer/renderElement.d.ts +4 -4
- package/dist/excalidraw/renderer/renderElement.js +7 -7
- package/dist/excalidraw/renderer/renderSnaps.d.ts +1 -1
- package/dist/excalidraw/renderer/renderSnaps.js +2 -1
- package/dist/excalidraw/renderer/staticScene.d.ts +1 -1
- package/dist/excalidraw/renderer/staticScene.js +14 -3
- package/dist/excalidraw/renderer/staticSvgScene.d.ts +4 -4
- package/dist/excalidraw/renderer/staticSvgScene.js +10 -0
- package/dist/excalidraw/scene/Fonts.d.ts +2 -4
- package/dist/excalidraw/scene/Fonts.js +6 -12
- package/dist/excalidraw/scene/Renderer.d.ts +4 -4
- package/dist/excalidraw/scene/Renderer.js +2 -3
- package/dist/excalidraw/scene/Scene.d.ts +19 -12
- package/dist/excalidraw/scene/Scene.js +44 -23
- package/dist/excalidraw/scene/Shape.d.ts +1 -1
- package/dist/excalidraw/scene/ShapeCache.d.ts +4 -4
- package/dist/excalidraw/scene/comparisons.d.ts +2 -2
- package/dist/excalidraw/scene/export.d.ts +2 -2
- package/dist/excalidraw/scene/export.js +6 -5
- 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 +7 -5
- package/dist/excalidraw/scene/zoom.d.ts +1 -1
- package/dist/excalidraw/snapping.d.ts +4 -4
- package/dist/excalidraw/snapping.js +2 -1
- package/dist/excalidraw/store.d.ts +129 -0
- package/dist/excalidraw/store.js +296 -0
- package/dist/excalidraw/types.d.ts +34 -19
- package/dist/excalidraw/utils.d.ts +11 -4
- package/dist/excalidraw/utils.js +8 -0
- package/dist/excalidraw/zindex.d.ts +4 -4
- package/dist/excalidraw/zindex.js +9 -13
- package/dist/prod/{en-II4GK66F.json → en-OIPCBIOA.json} +8 -4
- package/dist/prod/index.css +1 -1
- package/dist/prod/index.js +44 -44
- package/dist/utils/bbox.d.ts +2 -2
- package/dist/utils/collision.d.ts +4 -0
- package/dist/utils/collision.js +48 -0
- package/dist/utils/export.d.ts +2 -2
- package/dist/utils/geometry/geometry.d.ts +71 -0
- package/dist/utils/geometry/geometry.js +674 -0
- package/dist/utils/geometry/shape.d.ts +56 -0
- package/dist/utils/geometry/shape.js +168 -0
- package/dist/utils/withinBounds.d.ts +1 -1
- package/history.ts +163 -218
- package/package.json +3 -2
- package/dist/browser/dev/excalidraw-assets-dev/chunk-AK7SWNLN.js.map +0 -7
- package/dist/browser/dev/excalidraw-assets-dev/chunk-RWZVJAQU.js.map +0 -7
- package/dist/browser/dev/excalidraw-assets-dev/chunk-Z3PH3V2B.js.map +0 -7
- package/dist/browser/dev/excalidraw-assets-dev/dist-Z46EOVOL.js.map +0 -7
- package/dist/browser/dev/excalidraw-assets-dev/image-OFRRV5MB.css.map +0 -7
- package/dist/browser/prod/excalidraw-assets/chunk-LL4GORAM.js +0 -55
- package/dist/browser/prod/excalidraw-assets/dist-PIPZXALV.js +0 -6
- package/dist/browser/prod/excalidraw-assets/image-EFCJDJH3.js +0 -1
- /package/dist/browser/dev/excalidraw-assets-dev/{blockDiagram-91b80b7a-ACFH36JV.js.map → blockDiagram-91b80b7a-H47FTXHA.js.map} +0 -0
- /package/dist/browser/dev/excalidraw-assets-dev/{c4Diagram-b2a90758-QZ27YR47.js.map → c4Diagram-b2a90758-NNJK6GKC.js.map} +0 -0
- /package/dist/browser/dev/excalidraw-assets-dev/{chunk-HO2HMSK7.js.map → chunk-4KQVEBHW.js.map} +0 -0
- /package/dist/browser/dev/excalidraw-assets-dev/{chunk-USGV265L.js.map → chunk-53YI56GV.js.map} +0 -0
- /package/dist/browser/dev/excalidraw-assets-dev/{chunk-EDFX3S7X.js.map → chunk-A2WCJI4I.js.map} +0 -0
- /package/dist/browser/dev/excalidraw-assets-dev/{chunk-IX4V72YG.js.map → chunk-EFLPX7NE.js.map} +0 -0
- /package/dist/browser/dev/excalidraw-assets-dev/{chunk-MXVETLVM.js.map → chunk-JYIQCNWV.js.map} +0 -0
- /package/dist/browser/dev/excalidraw-assets-dev/{chunk-YZIOORVX.js.map → chunk-LVIQQW6F.js.map} +0 -0
- /package/dist/browser/dev/excalidraw-assets-dev/{chunk-6U7GQNJT.js.map → chunk-PXLO3FOU.js.map} +0 -0
- /package/dist/browser/dev/excalidraw-assets-dev/{chunk-7DACDEY3.js.map → chunk-TO2AW5PW.js.map} +0 -0
- /package/dist/browser/dev/excalidraw-assets-dev/{chunk-NJ77ZFNJ.js.map → chunk-VURILHLY.js.map} +0 -0
- /package/dist/browser/dev/excalidraw-assets-dev/{chunk-2T2GU7NF.js.map → chunk-ZAYGSUHF.js.map} +0 -0
- /package/dist/browser/dev/excalidraw-assets-dev/{classDiagram-30eddba6-QSLMH4JW.js.map → classDiagram-30eddba6-CUYIJICN.js.map} +0 -0
- /package/dist/browser/dev/excalidraw-assets-dev/{classDiagram-v2-f2df5561-DY4DYQ5P.js.map → classDiagram-v2-f2df5561-K6WW6K73.js.map} +0 -0
- /package/dist/browser/dev/excalidraw-assets-dev/{en-5TCZHGGJ.js.map → en-Y27YPU72.js.map} +0 -0
- /package/dist/browser/dev/excalidraw-assets-dev/{erDiagram-47591fe2-SOOJRTCB.js.map → erDiagram-47591fe2-XGAD7EEP.js.map} +0 -0
- /package/dist/browser/dev/excalidraw-assets-dev/{flowDiagram-5540d9b9-AHGL4KPK.js.map → flowDiagram-5540d9b9-B6EOVNNO.js.map} +0 -0
- /package/dist/browser/dev/excalidraw-assets-dev/{flowDiagram-v2-3b53844e-56LDZZWY.js.map → flowDiagram-v2-3b53844e-NUG24FJH.js.map} +0 -0
- /package/dist/browser/dev/excalidraw-assets-dev/{flowchart-elk-definition-5fe447d6-27LUKRI6.js.map → flowchart-elk-definition-5fe447d6-25Y7PCBL.js.map} +0 -0
- /package/dist/browser/dev/excalidraw-assets-dev/{ganttDiagram-9a3bba1f-EHGYGNG6.js.map → ganttDiagram-9a3bba1f-GNL6ZDTC.js.map} +0 -0
- /package/dist/browser/dev/excalidraw-assets-dev/{gitGraphDiagram-96e6b4ee-AJQNBDW5.js.map → gitGraphDiagram-96e6b4ee-HNW52NVO.js.map} +0 -0
- /package/dist/browser/dev/excalidraw-assets-dev/{image-EDKQZH7Z.js.map → image-J7S3ALXP.js.map} +0 -0
- /package/dist/browser/dev/excalidraw-assets-dev/{infoDiagram-bcd20f53-SWLLQVES.js.map → infoDiagram-bcd20f53-FWEUVFLT.js.map} +0 -0
- /package/dist/browser/dev/excalidraw-assets-dev/{journeyDiagram-4fe6b3dc-7UAVCWOZ.js.map → journeyDiagram-4fe6b3dc-RZIUI7UG.js.map} +0 -0
- /package/dist/browser/dev/excalidraw-assets-dev/{mindmap-definition-f354de21-SROW5KGM.js.map → mindmap-definition-f354de21-GBVN45GU.js.map} +0 -0
- /package/dist/browser/dev/excalidraw-assets-dev/{pieDiagram-79897490-QKCI6NCB.js.map → pieDiagram-79897490-ECENNII6.js.map} +0 -0
- /package/dist/browser/dev/excalidraw-assets-dev/{quadrantDiagram-62f64e94-LNYJZFC5.js.map → quadrantDiagram-62f64e94-ZMEOFVNL.js.map} +0 -0
- /package/dist/browser/dev/excalidraw-assets-dev/{requirementDiagram-05bf5f74-ZZD7ZHFA.js.map → requirementDiagram-05bf5f74-FHZSFHCR.js.map} +0 -0
- /package/dist/browser/dev/excalidraw-assets-dev/{sankeyDiagram-97764748-L75ZZ4UM.js.map → sankeyDiagram-97764748-VDKIKTA6.js.map} +0 -0
- /package/dist/browser/dev/excalidraw-assets-dev/{sequenceDiagram-acc0e65c-6PCU7TDK.js.map → sequenceDiagram-acc0e65c-6JUSPVKX.js.map} +0 -0
- /package/dist/browser/dev/excalidraw-assets-dev/{stateDiagram-0ff1cf1a-WM76WOPR.js.map → stateDiagram-0ff1cf1a-L3AKWENF.js.map} +0 -0
- /package/dist/browser/dev/excalidraw-assets-dev/{stateDiagram-v2-9a9d610d-N4HZW3O2.js.map → stateDiagram-v2-9a9d610d-NU3GGMCH.js.map} +0 -0
- /package/dist/browser/dev/excalidraw-assets-dev/{timeline-definition-fea2a41d-ZHGCAXGP.js.map → timeline-definition-fea2a41d-JGP7XCHW.js.map} +0 -0
- /package/dist/browser/dev/excalidraw-assets-dev/{xychartDiagram-ab372869-2DLOVRAZ.js.map → xychartDiagram-ab372869-HLFHHF2I.js.map} +0 -0
|
@@ -10,31 +10,34 @@ 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 { DEFAULT_FONT_SIZE } 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,
|
|
19
|
-
import { bindOrUnbindLinearElement,
|
|
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";
|
|
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
23
|
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, isFrameElement, isIframeElement, isIframeLikeElement, isMagicFrameElement, } from "../element/typeChecks";
|
|
24
|
+
import { hasBoundTextElement, isArrowElement, isBindingElement, isBindingElementType, isBoundToContainer, isFrameLikeElement, isImageElement, isEmbeddableElement, isInitializedImageElement, isLinearElement, isLinearElementType, isUsingAdaptiveRadius, isFrameElement, isIframeElement, isIframeLikeElement, isMagicFrameElement, isTextBindableContainer, } from "../element/typeChecks";
|
|
24
25
|
import { getCenter, getDistance } from "../gesture";
|
|
25
26
|
import { editGroupForSelectedElement, getElementsInGroup, getSelectedGroupIdForElement, getSelectedGroupIds, isElementInGroup, isSelectedViaGroup, selectGroupsForSelectedElements, } from "../groups";
|
|
26
|
-
import History from "../history";
|
|
27
|
+
import { History } from "../history";
|
|
27
28
|
import { defaultLang, getLanguage, languages, setLanguage, t } from "../i18n";
|
|
28
29
|
import { CODES, shouldResizeFromCenter, shouldMaintainAspectRatio, shouldRotateWithDiscreteAngle, isArrowKey, KEYS, } from "../keys";
|
|
29
30
|
import { isElementInViewport } from "../element/sizeHelpers";
|
|
30
31
|
import { distance2d, getCornerRadius, getGridPoint, isPathALoop, } from "../math";
|
|
31
|
-
import { calculateScrollCenter,
|
|
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
35
|
import { findShapeByKey } from "../shapes";
|
|
35
|
-
import {
|
|
36
|
+
import { getClosedCurveShape, getCurveShape, getEllipseShape, getFreedrawShape, getPolygonShape, getSelectionBoxShape, } from "../../utils/geometry/shape";
|
|
37
|
+
import { isPointInShape } from "../../utils/collision";
|
|
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";
|
|
36
39
|
import { createSrcDoc, embeddableURLValidator, maybeParseEmbedSrc, getEmbedLink, } from "../element/embeddable";
|
|
37
|
-
import { ContextMenu, CONTEXT_MENU_SEPARATOR
|
|
40
|
+
import { ContextMenu, CONTEXT_MENU_SEPARATOR } from "./ContextMenu";
|
|
38
41
|
import LayerUI from "./LayerUI";
|
|
39
42
|
import { Toast } from "./Toast";
|
|
40
43
|
import { actionToggleViewMode } from "../actions/actionToggleViewMode";
|
|
@@ -42,8 +45,7 @@ import { dataURLToFile, generateIdFromFile, getDataURL, getFileFromEvent, ImageU
|
|
|
42
45
|
import { getInitializedImageElements, loadHTMLImageElement, normalizeSVG, updateImageCache as _updateImageCache, } from "../element/image";
|
|
43
46
|
import throttle from "lodash.throttle";
|
|
44
47
|
import { fileOpen } from "../data/filesystem";
|
|
45
|
-
import { bindTextToShapeAfterDuplication, getApproxMinLineHeight, getApproxMinLineWidth, getBoundTextElement, getContainerCenter, getContainerElement, getDefaultLineHeight, getLineHeightInPx,
|
|
46
|
-
import { isHittingElementNotConsideringBoundingBox } from "../element/collision";
|
|
48
|
+
import { bindTextToShapeAfterDuplication, getApproxMinLineHeight, getApproxMinLineWidth, getBoundTextElement, getContainerCenter, getContainerElement, getDefaultLineHeight, getLineHeightInPx, getMinTextElementWidth, isMeasureTextSupported, isValidTextContainer, measureText, wrapText, } from "../element/textElement";
|
|
47
49
|
import { showHyperlinkTooltip, hideHyperlinkToolip, Hyperlink, } from "../components/hyperlink/Hyperlink";
|
|
48
50
|
import { isLocalLink, normalizeLink, toValidURL } from "../data/url";
|
|
49
51
|
import { shouldShowBoundingBox } from "../element/transformHandles";
|
|
@@ -61,7 +63,7 @@ import { getSnapLinesAtPointer, snapDraggedElements, isActiveToolNonLinearSnappa
|
|
|
61
63
|
import { actionWrapTextInContainer } from "../actions/actionBoundText";
|
|
62
64
|
import BraveMeasureTextError from "./BraveMeasureTextError";
|
|
63
65
|
import { activeEyeDropperAtom } from "./EyeDropper";
|
|
64
|
-
import { convertToExcalidrawElements
|
|
66
|
+
import { convertToExcalidrawElements } from "../data/transform";
|
|
65
67
|
import { isSidebarDockedAtom } from "./Sidebar/Sidebar";
|
|
66
68
|
import { StaticCanvas, InteractiveCanvas } from "./canvases";
|
|
67
69
|
import { Renderer } from "../scene/Renderer";
|
|
@@ -77,15 +79,21 @@ import { ElementCanvasButton } from "./MagicButton";
|
|
|
77
79
|
import { MagicIcon, copyIcon, fullscreenIcon } from "./icons";
|
|
78
80
|
import { EditorLocalStorage } from "../data/EditorLocalStorage";
|
|
79
81
|
import FollowMode from "./FollowMode/FollowMode";
|
|
82
|
+
import { Store, StoreAction } from "../store";
|
|
80
83
|
import { AnimationFrameHandler } from "../animation-frame-handler";
|
|
81
84
|
import { AnimatedTrail } from "../animated-trail";
|
|
82
85
|
import { LaserTrails } from "../laser-trails";
|
|
83
86
|
import { withBatchedUpdates, withBatchedUpdatesThrottled } from "../reactUtils";
|
|
84
87
|
import { getRenderOpacity } from "../renderer/renderElement";
|
|
88
|
+
import { hitElementBoundText, hitElementBoundingBoxOnly, hitElementItself, shouldTestInside, } from "../element/collision";
|
|
85
89
|
import { textWysiwyg } from "../element/textWysiwyg";
|
|
86
90
|
import { isOverScrollBars } from "../scene/scrollbars";
|
|
91
|
+
import { syncInvalidIndices, syncMovedIndices } from "../fractionalIndex";
|
|
87
92
|
import { isPointHittingLink, isPointHittingLinkIcon, } from "./hyperlink/helpers";
|
|
88
93
|
import { getShortcutFromShortcutName } from "../actions/shortcuts";
|
|
94
|
+
import { actionTextAutoResize } from "../actions/actionTextAutoResize";
|
|
95
|
+
import { getVisibleSceneBounds } from "../element/bounds";
|
|
96
|
+
import { isMaybeMermaidDefinition } from "../mermaid";
|
|
89
97
|
const AppContext = React.createContext(null);
|
|
90
98
|
const AppPropsContext = React.createContext(null);
|
|
91
99
|
const deviceContextInitialValue = {
|
|
@@ -165,6 +173,7 @@ class App extends React.Component {
|
|
|
165
173
|
library;
|
|
166
174
|
libraryItemsFromStorage;
|
|
167
175
|
id;
|
|
176
|
+
store;
|
|
168
177
|
history;
|
|
169
178
|
excalidrawContainerValue;
|
|
170
179
|
files = {};
|
|
@@ -236,6 +245,8 @@ class App extends React.Component {
|
|
|
236
245
|
this.canvas = document.createElement("canvas");
|
|
237
246
|
this.rc = rough.canvas(this.canvas);
|
|
238
247
|
this.renderer = new Renderer(this.scene);
|
|
248
|
+
this.store = new Store();
|
|
249
|
+
this.history = new History();
|
|
239
250
|
if (excalidrawAPI) {
|
|
240
251
|
const api = {
|
|
241
252
|
updateScene: this.updateScene,
|
|
@@ -279,14 +290,11 @@ class App extends React.Component {
|
|
|
279
290
|
container: this.excalidrawContainerRef.current,
|
|
280
291
|
id: this.id,
|
|
281
292
|
};
|
|
282
|
-
this.fonts = new Fonts({
|
|
283
|
-
scene: this.scene,
|
|
284
|
-
onSceneUpdated: this.onSceneUpdated,
|
|
285
|
-
});
|
|
293
|
+
this.fonts = new Fonts({ scene: this.scene });
|
|
286
294
|
this.history = new History();
|
|
287
295
|
this.actionManager.registerAll(actions);
|
|
288
|
-
this.actionManager.registerAction(createUndoAction(this.history));
|
|
289
|
-
this.actionManager.registerAction(createRedoAction(this.history));
|
|
296
|
+
this.actionManager.registerAction(createUndoAction(this.history, this.store));
|
|
297
|
+
this.actionManager.registerAction(createRedoAction(this.history, this.store));
|
|
290
298
|
}
|
|
291
299
|
onWindowMessage(event) {
|
|
292
300
|
if (event.origin !== "https://player.vimeo.com" &&
|
|
@@ -437,7 +445,7 @@ class App extends React.Component {
|
|
|
437
445
|
return false;
|
|
438
446
|
});
|
|
439
447
|
if (updated) {
|
|
440
|
-
this.scene.
|
|
448
|
+
this.scene.triggerUpdate();
|
|
441
449
|
}
|
|
442
450
|
// GC
|
|
443
451
|
this.iFrameRefs.forEach((ref, id) => {
|
|
@@ -495,7 +503,7 @@ class App extends React.Component {
|
|
|
495
503
|
html, body {
|
|
496
504
|
width: 100%;
|
|
497
505
|
height: 100%;
|
|
498
|
-
color: ${this.state.theme ===
|
|
506
|
+
color: ${this.state.theme === THEME.DARK ? "white" : "black"};
|
|
499
507
|
}
|
|
500
508
|
body {
|
|
501
509
|
display: flex;
|
|
@@ -650,7 +658,7 @@ class App extends React.Component {
|
|
|
650
658
|
? src.srcdoc(this.state.theme)
|
|
651
659
|
: undefined, src: src?.type !== "document" ? src?.link ?? "" : undefined,
|
|
652
660
|
// https://stackoverflow.com/q/18470015
|
|
653
|
-
scrolling: "no", referrerPolicy: "no-referrer-when-downgrade", title: "Excalidraw Embedded Content", allow: "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture", allowFullScreen: true, sandbox: "allow-same-origin allow-scripts allow-forms allow-popups allow-popups-to-escape-sandbox allow-presentation allow-downloads
|
|
661
|
+
scrolling: "no", referrerPolicy: "no-referrer-when-downgrade", title: "Excalidraw Embedded Content", allow: "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture", allowFullScreen: true, sandbox: `${src?.sandbox?.allowSameOrigin ? "allow-same-origin" : ""} allow-scripts allow-forms allow-popups allow-popups-to-escape-sandbox allow-presentation allow-downloads` })) })] }) }, el.id));
|
|
654
662
|
}) }));
|
|
655
663
|
}
|
|
656
664
|
getFrameNameDOMId = (frameElement) => {
|
|
@@ -692,7 +700,7 @@ class App extends React.Component {
|
|
|
692
700
|
if (!this.state.frameRendering.enabled || !this.state.frameRendering.name) {
|
|
693
701
|
return null;
|
|
694
702
|
}
|
|
695
|
-
const isDarkTheme = this.state.theme ===
|
|
703
|
+
const isDarkTheme = this.state.theme === THEME.DARK;
|
|
696
704
|
let frameIndex = 0;
|
|
697
705
|
let magicFrameIndex = 0;
|
|
698
706
|
return this.scene.getNonDeletedFramesLikes().map((f) => {
|
|
@@ -796,9 +804,9 @@ class App extends React.Component {
|
|
|
796
804
|
render() {
|
|
797
805
|
const selectedElements = this.scene.getSelectedElements(this.state);
|
|
798
806
|
const { renderTopRightUI, renderCustomStats } = this.props;
|
|
799
|
-
const
|
|
807
|
+
const sceneNonce = this.scene.getSceneNonce();
|
|
800
808
|
const { elementsMap, visibleElements } = this.renderer.getRenderableElements({
|
|
801
|
-
|
|
809
|
+
sceneNonce,
|
|
802
810
|
zoom: this.state.zoom,
|
|
803
811
|
offsetLeft: this.state.offsetLeft,
|
|
804
812
|
offsetTop: this.state.offsetTop,
|
|
@@ -867,14 +875,14 @@ class App extends React.Component {
|
|
|
867
875
|
this.focusContainer();
|
|
868
876
|
callback?.();
|
|
869
877
|
});
|
|
870
|
-
} })), _jsx(StaticCanvas, { canvas: this.canvas, rc: this.rc, elementsMap: elementsMap, allElementsMap: allElementsMap, visibleElements: visibleElements,
|
|
878
|
+
} })), _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: {
|
|
871
879
|
imageCache: this.imageCache,
|
|
872
880
|
isExporting: false,
|
|
873
881
|
renderGrid: true,
|
|
874
882
|
canvasBackgroundColor: this.state.viewBackgroundColor,
|
|
875
883
|
embedsValidationStatus: this.embedsValidationStatus,
|
|
876
884
|
elementsPendingErasure: this.elementsPendingErasure,
|
|
877
|
-
} }), _jsx(InteractiveCanvas, { containerRef: this.excalidrawContainerRef, canvas: this.interactiveCanvas, elementsMap: elementsMap, visibleElements: visibleElements, selectedElements: selectedElements,
|
|
885
|
+
} }), _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()] }) }) }) }) }) }) }) }));
|
|
878
886
|
}
|
|
879
887
|
focusContainer = () => {
|
|
880
888
|
this.excalidrawContainerRef.current?.focus();
|
|
@@ -924,7 +932,7 @@ class App extends React.Component {
|
|
|
924
932
|
mutateElement(frameElement, { customData: { generationData: data } }, false);
|
|
925
933
|
}
|
|
926
934
|
this.magicGenerations.set(frameElement.id, data);
|
|
927
|
-
this.
|
|
935
|
+
this.triggerRender();
|
|
928
936
|
};
|
|
929
937
|
getTextFromElements(elements) {
|
|
930
938
|
const text = elements
|
|
@@ -1122,7 +1130,7 @@ class App extends React.Component {
|
|
|
1122
1130
|
opacity: 100,
|
|
1123
1131
|
locked: false,
|
|
1124
1132
|
});
|
|
1125
|
-
this.scene.
|
|
1133
|
+
this.scene.insertElement(frame);
|
|
1126
1134
|
for (const child of selectedElements) {
|
|
1127
1135
|
mutateElement(child, { frameId: frame.id });
|
|
1128
1136
|
}
|
|
@@ -1146,13 +1154,13 @@ class App extends React.Component {
|
|
|
1146
1154
|
if (shouldUpdateStrokeColor) {
|
|
1147
1155
|
this.syncActionResult({
|
|
1148
1156
|
appState: { ...this.state, currentItemStrokeColor: color },
|
|
1149
|
-
|
|
1157
|
+
storeAction: StoreAction.CAPTURE,
|
|
1150
1158
|
});
|
|
1151
1159
|
}
|
|
1152
1160
|
else {
|
|
1153
1161
|
this.syncActionResult({
|
|
1154
1162
|
appState: { ...this.state, currentItemBackgroundColor: color },
|
|
1155
|
-
|
|
1163
|
+
storeAction: StoreAction.CAPTURE,
|
|
1156
1164
|
});
|
|
1157
1165
|
}
|
|
1158
1166
|
}
|
|
@@ -1166,6 +1174,7 @@ class App extends React.Component {
|
|
|
1166
1174
|
}
|
|
1167
1175
|
return el;
|
|
1168
1176
|
}),
|
|
1177
|
+
storeAction: StoreAction.CAPTURE,
|
|
1169
1178
|
});
|
|
1170
1179
|
}
|
|
1171
1180
|
},
|
|
@@ -1185,10 +1194,13 @@ class App extends React.Component {
|
|
|
1185
1194
|
editingElement = element;
|
|
1186
1195
|
}
|
|
1187
1196
|
});
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
this.history.resumeRecording();
|
|
1197
|
+
if (actionResult.storeAction === StoreAction.UPDATE) {
|
|
1198
|
+
this.store.shouldUpdateSnapshot();
|
|
1191
1199
|
}
|
|
1200
|
+
else if (actionResult.storeAction === StoreAction.CAPTURE) {
|
|
1201
|
+
this.store.shouldCaptureIncrement();
|
|
1202
|
+
}
|
|
1203
|
+
this.scene.replaceAllElements(actionResult.elements);
|
|
1192
1204
|
}
|
|
1193
1205
|
if (actionResult.files) {
|
|
1194
1206
|
this.files = actionResult.replaceFiles
|
|
@@ -1197,8 +1209,11 @@ class App extends React.Component {
|
|
|
1197
1209
|
this.addNewImagesToImageCache();
|
|
1198
1210
|
}
|
|
1199
1211
|
if (actionResult.appState || editingElement || this.state.contextMenu) {
|
|
1200
|
-
if (actionResult.
|
|
1201
|
-
this.
|
|
1212
|
+
if (actionResult.storeAction === StoreAction.UPDATE) {
|
|
1213
|
+
this.store.shouldUpdateSnapshot();
|
|
1214
|
+
}
|
|
1215
|
+
else if (actionResult.storeAction === StoreAction.CAPTURE) {
|
|
1216
|
+
this.store.shouldCaptureIncrement();
|
|
1202
1217
|
}
|
|
1203
1218
|
let viewModeEnabled = actionResult?.appState?.viewModeEnabled || false;
|
|
1204
1219
|
let zenModeEnabled = actionResult?.appState?.zenModeEnabled || false;
|
|
@@ -1237,10 +1252,6 @@ class App extends React.Component {
|
|
|
1237
1252
|
name,
|
|
1238
1253
|
errorMessage,
|
|
1239
1254
|
});
|
|
1240
|
-
}, () => {
|
|
1241
|
-
if (actionResult.syncHistory) {
|
|
1242
|
-
this.history.setCurrentState(this.state, this.scene.getElementsIncludingDeleted());
|
|
1243
|
-
}
|
|
1244
1255
|
});
|
|
1245
1256
|
}
|
|
1246
1257
|
});
|
|
@@ -1258,6 +1269,9 @@ class App extends React.Component {
|
|
|
1258
1269
|
resetHistory = () => {
|
|
1259
1270
|
this.history.clear();
|
|
1260
1271
|
};
|
|
1272
|
+
resetStore = () => {
|
|
1273
|
+
this.store.clear();
|
|
1274
|
+
};
|
|
1261
1275
|
/**
|
|
1262
1276
|
* Resets scene & history.
|
|
1263
1277
|
* ! Do not use to clear scene user action !
|
|
@@ -1269,6 +1283,7 @@ class App extends React.Component {
|
|
|
1269
1283
|
isLoading: opts?.resetLoadingState ? false : state.isLoading,
|
|
1270
1284
|
theme: this.state.theme,
|
|
1271
1285
|
}));
|
|
1286
|
+
this.resetStore();
|
|
1272
1287
|
this.resetHistory();
|
|
1273
1288
|
});
|
|
1274
1289
|
initializeScene = async () => {
|
|
@@ -1343,10 +1358,11 @@ class App extends React.Component {
|
|
|
1343
1358
|
// text elements on canvas, and rerender them once done. This also
|
|
1344
1359
|
// seems faster even in browsers that do fire the loadingdone event.
|
|
1345
1360
|
this.fonts.loadFontsForElements(scene.elements);
|
|
1361
|
+
this.resetStore();
|
|
1346
1362
|
this.resetHistory();
|
|
1347
1363
|
this.syncActionResult({
|
|
1348
1364
|
...scene,
|
|
1349
|
-
|
|
1365
|
+
storeAction: StoreAction.UPDATE,
|
|
1350
1366
|
});
|
|
1351
1367
|
};
|
|
1352
1368
|
isMobileBreakpoint = (width, height) => {
|
|
@@ -1417,9 +1433,16 @@ class App extends React.Component {
|
|
|
1417
1433
|
configurable: true,
|
|
1418
1434
|
value: this.history,
|
|
1419
1435
|
},
|
|
1436
|
+
store: {
|
|
1437
|
+
configurable: true,
|
|
1438
|
+
value: this.store,
|
|
1439
|
+
},
|
|
1420
1440
|
});
|
|
1421
1441
|
}
|
|
1422
|
-
this.
|
|
1442
|
+
this.store.onStoreIncrementEmitter.on((increment) => {
|
|
1443
|
+
this.history.record(increment.elementsChange, increment.appStateChange);
|
|
1444
|
+
});
|
|
1445
|
+
this.scene.onUpdate(this.triggerRender);
|
|
1423
1446
|
this.addEventListeners();
|
|
1424
1447
|
if (this.props.autoFocus && this.excalidrawContainerRef.current) {
|
|
1425
1448
|
this.focusContainer();
|
|
@@ -1457,6 +1480,7 @@ class App extends React.Component {
|
|
|
1457
1480
|
componentWillUnmount() {
|
|
1458
1481
|
this.renderer.destroy();
|
|
1459
1482
|
this.scene = new Scene();
|
|
1483
|
+
this.fonts = new Fonts({ scene: this.scene });
|
|
1460
1484
|
this.renderer = new Renderer(this.scene);
|
|
1461
1485
|
this.files = {};
|
|
1462
1486
|
this.imageCache.clear();
|
|
@@ -1468,6 +1492,7 @@ class App extends React.Component {
|
|
|
1468
1492
|
this.laserTrails.stop();
|
|
1469
1493
|
this.eraserTrail.stop();
|
|
1470
1494
|
this.onChangeEmitter.clear();
|
|
1495
|
+
this.store.onStoreIncrementEmitter.clear();
|
|
1471
1496
|
ShapeCache.destroy();
|
|
1472
1497
|
SnapCache.destroy();
|
|
1473
1498
|
clearTimeout(touchTimeout);
|
|
@@ -1511,7 +1536,7 @@ class App extends React.Component {
|
|
|
1511
1536
|
this.onRemoveEventListenersEmitter.once(addEventListener(document, EVENT.KEYDOWN, this.onKeyDown, false));
|
|
1512
1537
|
}
|
|
1513
1538
|
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
|
|
1514
|
-
addEventListener(document, EVENT.COPY, this.onCopy), addEventListener(document, EVENT.KEYUP, this.onKeyUp, { passive: true }), addEventListener(document, EVENT.
|
|
1539
|
+
addEventListener(document, EVENT.COPY, this.onCopy), addEventListener(document, EVENT.KEYUP, this.onKeyUp, { passive: true }), addEventListener(document, EVENT.POINTER_MOVE, this.updateCurrentCursorPosition),
|
|
1515
1540
|
// rerender text elements on font load to fix #637 && #1553
|
|
1516
1541
|
addEventListener(document.fonts, "loadingdone", (event) => {
|
|
1517
1542
|
const loadedFontFaces = event.fontfaces;
|
|
@@ -1520,6 +1545,9 @@ class App extends React.Component {
|
|
|
1520
1545
|
// Safari-only desktop pinch zoom
|
|
1521
1546
|
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, () => {
|
|
1522
1547
|
this.maybeCleanupAfterMissingPointerUp(null);
|
|
1548
|
+
// browsers (chrome?) tend to free up memory a lot, which results
|
|
1549
|
+
// in canvas context being cleared. Thus re-render on focus.
|
|
1550
|
+
this.triggerRender(true);
|
|
1523
1551
|
}));
|
|
1524
1552
|
if (this.state.viewModeEnabled) {
|
|
1525
1553
|
return;
|
|
@@ -1535,7 +1563,8 @@ class App extends React.Component {
|
|
|
1535
1563
|
componentDidUpdate(prevProps, prevState) {
|
|
1536
1564
|
this.updateEmbeddables();
|
|
1537
1565
|
const elements = this.scene.getElementsIncludingDeleted();
|
|
1538
|
-
const elementsMap = this.scene.
|
|
1566
|
+
const elementsMap = this.scene.getElementsMapIncludingDeleted();
|
|
1567
|
+
const nonDeletedElementsMap = this.scene.getNonDeletedElementsMap();
|
|
1539
1568
|
if (!this.state.showWelcomeScreen && !elements.length) {
|
|
1540
1569
|
this.setState({ showWelcomeScreen: true });
|
|
1541
1570
|
}
|
|
@@ -1608,10 +1637,10 @@ class App extends React.Component {
|
|
|
1608
1637
|
gridSize: this.props.gridModeEnabled ? GRID_SIZE : null,
|
|
1609
1638
|
});
|
|
1610
1639
|
}
|
|
1611
|
-
this.excalidrawContainerRef.current?.classList.toggle("theme--dark", this.state.theme ===
|
|
1640
|
+
this.excalidrawContainerRef.current?.classList.toggle("theme--dark", this.state.theme === THEME.DARK);
|
|
1612
1641
|
if (this.state.editingLinearElement &&
|
|
1613
1642
|
!this.state.selectedElementIds[this.state.editingLinearElement.elementId]) {
|
|
1614
|
-
// defer so that the
|
|
1643
|
+
// defer so that the storeAction flag isn't reset via current update
|
|
1615
1644
|
setTimeout(() => {
|
|
1616
1645
|
// execute only if the condition still holds when the deferred callback
|
|
1617
1646
|
// executes (it can be scheduled multiple times depending on how
|
|
@@ -1636,9 +1665,9 @@ class App extends React.Component {
|
|
|
1636
1665
|
multiElement != null &&
|
|
1637
1666
|
isBindingEnabled(this.state) &&
|
|
1638
1667
|
isBindingElement(multiElement, false)) {
|
|
1639
|
-
maybeBindLinearElement(multiElement, this.state,
|
|
1668
|
+
maybeBindLinearElement(multiElement, this.state, tupleToCoors(LinearElementEditor.getPointAtIndexGlobalCoordinates(multiElement, -1, nonDeletedElementsMap)), this);
|
|
1640
1669
|
}
|
|
1641
|
-
this.
|
|
1670
|
+
this.store.commit(elementsMap, this.state);
|
|
1642
1671
|
// Do not notify consumers if we're still loading the scene. Among other
|
|
1643
1672
|
// potential issues, this fixes a case where the tab isn't focused during
|
|
1644
1673
|
// init, which would trigger onChange with empty elements, which would then
|
|
@@ -1825,6 +1854,26 @@ class App extends React.Component {
|
|
|
1825
1854
|
});
|
|
1826
1855
|
}
|
|
1827
1856
|
else if (data.text) {
|
|
1857
|
+
if (data.text && isMaybeMermaidDefinition(data.text)) {
|
|
1858
|
+
const api = await import("@excalidraw/mermaid-to-excalidraw");
|
|
1859
|
+
try {
|
|
1860
|
+
const { elements: skeletonElements, files } = await api.parseMermaidToExcalidraw(data.text, {
|
|
1861
|
+
fontSize: DEFAULT_FONT_SIZE,
|
|
1862
|
+
});
|
|
1863
|
+
const elements = convertToExcalidrawElements(skeletonElements, {
|
|
1864
|
+
regenerateIds: true,
|
|
1865
|
+
});
|
|
1866
|
+
this.addElementsFromPasteOrLibrary({
|
|
1867
|
+
elements,
|
|
1868
|
+
files,
|
|
1869
|
+
position: "cursor",
|
|
1870
|
+
});
|
|
1871
|
+
return;
|
|
1872
|
+
}
|
|
1873
|
+
catch (err) {
|
|
1874
|
+
console.warn(`parsing pasted text as mermaid definition failed: ${err.message}`);
|
|
1875
|
+
}
|
|
1876
|
+
}
|
|
1828
1877
|
const nonEmptyLines = normalizeEOL(data.text)
|
|
1829
1878
|
.split(/\n+/)
|
|
1830
1879
|
.map((s) => s.trim())
|
|
@@ -1894,16 +1943,15 @@ class App extends React.Component {
|
|
|
1894
1943
|
}), {
|
|
1895
1944
|
randomizeSeed: !opts.retainSeed,
|
|
1896
1945
|
});
|
|
1897
|
-
const
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
];
|
|
1946
|
+
const prevElements = this.scene.getElementsIncludingDeleted();
|
|
1947
|
+
const nextElements = [...prevElements, ...newElements];
|
|
1948
|
+
syncMovedIndices(nextElements, arrayToMap(newElements));
|
|
1901
1949
|
const topLayerFrame = this.getTopLayerFrameAtSceneCoords({ x, y });
|
|
1902
1950
|
if (topLayerFrame) {
|
|
1903
1951
|
const eligibleElements = filterElementsEligibleAsFrameChildren(newElements, topLayerFrame);
|
|
1904
|
-
addElementsToFrame(
|
|
1952
|
+
addElementsToFrame(nextElements, eligibleElements, topLayerFrame);
|
|
1905
1953
|
}
|
|
1906
|
-
this.scene.replaceAllElements(
|
|
1954
|
+
this.scene.replaceAllElements(nextElements);
|
|
1907
1955
|
newElements.forEach((newElement) => {
|
|
1908
1956
|
if (isTextElement(newElement) && isBoundToContainer(newElement)) {
|
|
1909
1957
|
const container = getContainerElement(newElement, this.scene.getElementsMapIncludingDeleted());
|
|
@@ -1913,7 +1961,7 @@ class App extends React.Component {
|
|
|
1913
1961
|
if (opts.files) {
|
|
1914
1962
|
this.files = { ...this.files, ...opts.files };
|
|
1915
1963
|
}
|
|
1916
|
-
this.
|
|
1964
|
+
this.store.shouldCaptureIncrement();
|
|
1917
1965
|
const nextElementsToSelect = excludeElementsInFramesFromSelection(newElements);
|
|
1918
1966
|
this.setState({
|
|
1919
1967
|
...this.state,
|
|
@@ -2030,27 +2078,46 @@ class App extends React.Component {
|
|
|
2030
2078
|
text,
|
|
2031
2079
|
fontSize: this.state.currentItemFontSize,
|
|
2032
2080
|
fontFamily: this.state.currentItemFontFamily,
|
|
2033
|
-
textAlign:
|
|
2081
|
+
textAlign: DEFAULT_TEXT_ALIGN,
|
|
2034
2082
|
verticalAlign: DEFAULT_VERTICAL_ALIGN,
|
|
2035
2083
|
locked: false,
|
|
2036
2084
|
};
|
|
2085
|
+
const fontString = getFontString({
|
|
2086
|
+
fontSize: textElementProps.fontSize,
|
|
2087
|
+
fontFamily: textElementProps.fontFamily,
|
|
2088
|
+
});
|
|
2089
|
+
const lineHeight = getDefaultLineHeight(textElementProps.fontFamily);
|
|
2090
|
+
const [x1, , x2] = getVisibleSceneBounds(this.state);
|
|
2091
|
+
// long texts should not go beyond 800 pixels in width nor should it go below 200 px
|
|
2092
|
+
const maxTextWidth = Math.max(Math.min((x2 - x1) * 0.5, 800), 200);
|
|
2037
2093
|
const LINE_GAP = 10;
|
|
2038
2094
|
let currentY = y;
|
|
2039
2095
|
const lines = isPlainPaste ? [text] : text.split("\n");
|
|
2040
2096
|
const textElements = lines.reduce((acc, line, idx) => {
|
|
2041
|
-
const
|
|
2042
|
-
|
|
2043
|
-
if (text.length) {
|
|
2097
|
+
const originalText = line.trim();
|
|
2098
|
+
if (originalText.length) {
|
|
2044
2099
|
const topLayerFrame = this.getTopLayerFrameAtSceneCoords({
|
|
2045
2100
|
x,
|
|
2046
2101
|
y: currentY,
|
|
2047
2102
|
});
|
|
2103
|
+
let metrics = measureText(originalText, fontString, lineHeight);
|
|
2104
|
+
const isTextWrapped = metrics.width > maxTextWidth;
|
|
2105
|
+
const text = isTextWrapped
|
|
2106
|
+
? wrapText(originalText, fontString, maxTextWidth)
|
|
2107
|
+
: originalText;
|
|
2108
|
+
metrics = isTextWrapped
|
|
2109
|
+
? measureText(text, fontString, lineHeight)
|
|
2110
|
+
: metrics;
|
|
2111
|
+
const startX = x - metrics.width / 2;
|
|
2112
|
+
const startY = currentY - metrics.height / 2;
|
|
2048
2113
|
const element = newTextElement({
|
|
2049
2114
|
...textElementProps,
|
|
2050
|
-
x,
|
|
2051
|
-
y:
|
|
2115
|
+
x: startX,
|
|
2116
|
+
y: startY,
|
|
2052
2117
|
text,
|
|
2118
|
+
originalText,
|
|
2053
2119
|
lineHeight,
|
|
2120
|
+
autoResize: !isTextWrapped,
|
|
2054
2121
|
frameId: topLayerFrame ? topLayerFrame.id : null,
|
|
2055
2122
|
});
|
|
2056
2123
|
acc.push(element);
|
|
@@ -2071,16 +2138,7 @@ class App extends React.Component {
|
|
|
2071
2138
|
if (textElements.length === 0) {
|
|
2072
2139
|
return;
|
|
2073
2140
|
}
|
|
2074
|
-
|
|
2075
|
-
if (frameId) {
|
|
2076
|
-
this.scene.insertElementsAtIndex(textElements, this.scene.getElementIndex(frameId));
|
|
2077
|
-
}
|
|
2078
|
-
else {
|
|
2079
|
-
this.scene.replaceAllElements([
|
|
2080
|
-
...this.scene.getElementsIncludingDeleted(),
|
|
2081
|
-
...textElements,
|
|
2082
|
-
]);
|
|
2083
|
-
}
|
|
2141
|
+
this.scene.insertElements(textElements);
|
|
2084
2142
|
this.setState({
|
|
2085
2143
|
selectedElementIds: makeNextSelectedElementIds(Object.fromEntries(textElements.map((el) => [el.id, true])), this.state),
|
|
2086
2144
|
});
|
|
@@ -2096,7 +2154,7 @@ class App extends React.Component {
|
|
|
2096
2154
|
});
|
|
2097
2155
|
PLAIN_PASTE_TOAST_SHOWN = true;
|
|
2098
2156
|
}
|
|
2099
|
-
this.
|
|
2157
|
+
this.store.shouldCaptureIncrement();
|
|
2100
2158
|
}
|
|
2101
2159
|
setAppState = (state, callback) => {
|
|
2102
2160
|
this.setState(state, callback);
|
|
@@ -2278,25 +2336,49 @@ class App extends React.Component {
|
|
|
2278
2336
|
ShapeCache.delete(element);
|
|
2279
2337
|
}
|
|
2280
2338
|
});
|
|
2281
|
-
this.scene.
|
|
2339
|
+
this.scene.triggerUpdate();
|
|
2282
2340
|
this.addNewImagesToImageCache();
|
|
2283
2341
|
});
|
|
2284
2342
|
updateScene = withBatchedUpdates((sceneData) => {
|
|
2285
|
-
|
|
2286
|
-
|
|
2343
|
+
const nextElements = syncInvalidIndices(sceneData.elements ?? []);
|
|
2344
|
+
if (sceneData.storeAction && sceneData.storeAction !== StoreAction.NONE) {
|
|
2345
|
+
const prevCommittedAppState = this.store.snapshot.appState;
|
|
2346
|
+
const prevCommittedElements = this.store.snapshot.elements;
|
|
2347
|
+
const nextCommittedAppState = sceneData.appState
|
|
2348
|
+
? Object.assign({}, prevCommittedAppState, sceneData.appState) // new instance, with partial appstate applied to previously captured one, including hidden prop inside `prevCommittedAppState`
|
|
2349
|
+
: prevCommittedAppState;
|
|
2350
|
+
const nextCommittedElements = sceneData.elements
|
|
2351
|
+
? this.store.filterUncomittedElements(this.scene.getElementsMapIncludingDeleted(), // Only used to detect uncomitted local elements
|
|
2352
|
+
arrayToMap(nextElements))
|
|
2353
|
+
: prevCommittedElements;
|
|
2354
|
+
// WARN: store action always performs deep clone of changed elements, for ephemeral remote updates (i.e. remote dragging, resizing, drawing) we might consider doing something smarter
|
|
2355
|
+
// do NOT schedule store actions (execute after re-render), as it might cause unexpected concurrency issues if not handled well
|
|
2356
|
+
if (sceneData.storeAction === StoreAction.CAPTURE) {
|
|
2357
|
+
this.store.captureIncrement(nextCommittedElements, nextCommittedAppState);
|
|
2358
|
+
}
|
|
2359
|
+
else if (sceneData.storeAction === StoreAction.UPDATE) {
|
|
2360
|
+
this.store.updateSnapshot(nextCommittedElements, nextCommittedAppState);
|
|
2361
|
+
}
|
|
2287
2362
|
}
|
|
2288
2363
|
if (sceneData.appState) {
|
|
2289
2364
|
this.setState(sceneData.appState);
|
|
2290
2365
|
}
|
|
2291
2366
|
if (sceneData.elements) {
|
|
2292
|
-
this.scene.replaceAllElements(
|
|
2367
|
+
this.scene.replaceAllElements(nextElements);
|
|
2293
2368
|
}
|
|
2294
2369
|
if (sceneData.collaborators) {
|
|
2295
2370
|
this.setState({ collaborators: sceneData.collaborators });
|
|
2296
2371
|
}
|
|
2297
2372
|
});
|
|
2298
|
-
|
|
2299
|
-
|
|
2373
|
+
triggerRender = (
|
|
2374
|
+
/** force always re-renders canvas even if no change */
|
|
2375
|
+
force) => {
|
|
2376
|
+
if (force === true) {
|
|
2377
|
+
this.scene.triggerUpdate();
|
|
2378
|
+
}
|
|
2379
|
+
else {
|
|
2380
|
+
this.setState({});
|
|
2381
|
+
}
|
|
2300
2382
|
};
|
|
2301
2383
|
/**
|
|
2302
2384
|
* @returns whether the menu was toggled on or off
|
|
@@ -2355,8 +2437,7 @@ class App extends React.Component {
|
|
|
2355
2437
|
!event.altKey) {
|
|
2356
2438
|
this.setToast({
|
|
2357
2439
|
message: t("commandPalette.shortcutHint", {
|
|
2358
|
-
|
|
2359
|
-
shortcutTwo: getShortcutFromShortcutName("commandPalette", 1),
|
|
2440
|
+
shortcut: getShortcutFromShortcutName("commandPalette"),
|
|
2360
2441
|
}),
|
|
2361
2442
|
});
|
|
2362
2443
|
event.preventDefault();
|
|
@@ -2464,7 +2545,9 @@ class App extends React.Component {
|
|
|
2464
2545
|
simultaneouslyUpdated: selectedElements,
|
|
2465
2546
|
});
|
|
2466
2547
|
});
|
|
2467
|
-
this.
|
|
2548
|
+
this.setState({
|
|
2549
|
+
suggestedBindings: getSuggestedBindingsForArrows(selectedElements, this),
|
|
2550
|
+
});
|
|
2468
2551
|
event.preventDefault();
|
|
2469
2552
|
}
|
|
2470
2553
|
else if (event.key === KEYS.ENTER) {
|
|
@@ -2476,7 +2559,7 @@ class App extends React.Component {
|
|
|
2476
2559
|
if (!this.state.editingLinearElement ||
|
|
2477
2560
|
this.state.editingLinearElement.elementId !==
|
|
2478
2561
|
selectedElements[0].id) {
|
|
2479
|
-
this.
|
|
2562
|
+
this.store.shouldCaptureIncrement();
|
|
2480
2563
|
this.setState({
|
|
2481
2564
|
editingLinearElement: new LinearElementEditor(selectedElement),
|
|
2482
2565
|
});
|
|
@@ -2602,11 +2685,7 @@ class App extends React.Component {
|
|
|
2602
2685
|
this.setState({ isBindingEnabled: true });
|
|
2603
2686
|
}
|
|
2604
2687
|
if (isArrowKey(event.key)) {
|
|
2605
|
-
|
|
2606
|
-
const elementsMap = this.scene.getNonDeletedElementsMap();
|
|
2607
|
-
isBindingEnabled(this.state)
|
|
2608
|
-
? bindOrUnbindSelectedElements(selectedElements, this.scene.getNonDeletedElements(), elementsMap)
|
|
2609
|
-
: unbindLinearElements(selectedElements, elementsMap);
|
|
2688
|
+
bindOrUnbindLinearElements(this.scene.getSelectedElements(this.state).filter(isLinearElement), this, isBindingEnabled(this.state), this.state.selectedLinearElement?.selectedPointsIndices ?? []);
|
|
2610
2689
|
this.setState({ suggestedBindings: [] });
|
|
2611
2690
|
}
|
|
2612
2691
|
});
|
|
@@ -2644,6 +2723,9 @@ class App extends React.Component {
|
|
|
2644
2723
|
originSnapOffset: null,
|
|
2645
2724
|
activeEmbeddable: null,
|
|
2646
2725
|
};
|
|
2726
|
+
if (nextActiveTool.type === "freedraw") {
|
|
2727
|
+
this.store.shouldCaptureIncrement();
|
|
2728
|
+
}
|
|
2647
2729
|
if (nextActiveTool.type !== "selection") {
|
|
2648
2730
|
return {
|
|
2649
2731
|
...prevState,
|
|
@@ -2741,15 +2823,16 @@ class App extends React.Component {
|
|
|
2741
2823
|
});
|
|
2742
2824
|
handleTextWysiwyg(element, { isExistingElement = false, }) {
|
|
2743
2825
|
const elementsMap = this.scene.getElementsMapIncludingDeleted();
|
|
2744
|
-
const updateElement = (
|
|
2826
|
+
const updateElement = (nextOriginalText, isDeleted) => {
|
|
2745
2827
|
this.scene.replaceAllElements([
|
|
2746
2828
|
// Not sure why we include deleted elements as well hence using deleted elements map
|
|
2747
2829
|
...this.scene.getElementsIncludingDeleted().map((_element) => {
|
|
2748
2830
|
if (_element.id === element.id && isTextElement(_element)) {
|
|
2749
|
-
return
|
|
2750
|
-
|
|
2751
|
-
isDeleted,
|
|
2752
|
-
|
|
2831
|
+
return newElementWith(_element, {
|
|
2832
|
+
originalText: nextOriginalText,
|
|
2833
|
+
isDeleted: isDeleted ?? _element.isDeleted,
|
|
2834
|
+
// returns (wrapped) text and new dimensions
|
|
2835
|
+
...refreshTextDimensions(_element, getContainerElement(_element, elementsMap), elementsMap, nextOriginalText),
|
|
2753
2836
|
});
|
|
2754
2837
|
}
|
|
2755
2838
|
return _element;
|
|
@@ -2769,15 +2852,15 @@ class App extends React.Component {
|
|
|
2769
2852
|
viewportY - this.state.offsetTop,
|
|
2770
2853
|
];
|
|
2771
2854
|
},
|
|
2772
|
-
onChange: withBatchedUpdates((
|
|
2773
|
-
updateElement(
|
|
2855
|
+
onChange: withBatchedUpdates((nextOriginalText) => {
|
|
2856
|
+
updateElement(nextOriginalText, false);
|
|
2774
2857
|
if (isNonDeletedElement(element)) {
|
|
2775
2858
|
updateBoundElements(element, elementsMap);
|
|
2776
2859
|
}
|
|
2777
2860
|
}),
|
|
2778
|
-
onSubmit: withBatchedUpdates(({
|
|
2779
|
-
const isDeleted = !
|
|
2780
|
-
updateElement(
|
|
2861
|
+
onSubmit: withBatchedUpdates(({ viaKeyboard, nextOriginalText }) => {
|
|
2862
|
+
const isDeleted = !nextOriginalText.trim();
|
|
2863
|
+
updateElement(nextOriginalText, isDeleted);
|
|
2781
2864
|
// select the created text element only if submitting via keyboard
|
|
2782
2865
|
// (when submitting via click it should act as signal to deselect)
|
|
2783
2866
|
if (!isDeleted && viaKeyboard) {
|
|
@@ -2797,7 +2880,7 @@ class App extends React.Component {
|
|
|
2797
2880
|
]);
|
|
2798
2881
|
}
|
|
2799
2882
|
if (!isDeleted || isExistingElement) {
|
|
2800
|
-
this.
|
|
2883
|
+
this.store.shouldCaptureIncrement();
|
|
2801
2884
|
}
|
|
2802
2885
|
this.setState({
|
|
2803
2886
|
draggingElement: null,
|
|
@@ -2811,12 +2894,17 @@ class App extends React.Component {
|
|
|
2811
2894
|
element,
|
|
2812
2895
|
excalidrawContainer: this.excalidrawContainerRef.current,
|
|
2813
2896
|
app: this,
|
|
2897
|
+
// when text is selected, it's hard (at least on iOS) to re-position the
|
|
2898
|
+
// caret (i.e. deselect). There's not much use for always selecting
|
|
2899
|
+
// the text on edit anyway (and users can select-all from contextmenu
|
|
2900
|
+
// if needed)
|
|
2901
|
+
autoSelect: !this.device.isTouchScreen,
|
|
2814
2902
|
});
|
|
2815
2903
|
// deselect all other elements when inserting text
|
|
2816
2904
|
this.deselectElements();
|
|
2817
2905
|
// do an initial update to re-initialize element position since we were
|
|
2818
2906
|
// modifying element's x/y for sake of editor (case: syncing to remote)
|
|
2819
|
-
updateElement(element.
|
|
2907
|
+
updateElement(element.originalText, false);
|
|
2820
2908
|
}
|
|
2821
2909
|
deselectElements() {
|
|
2822
2910
|
this.setState({
|
|
@@ -2835,6 +2923,57 @@ class App extends React.Component {
|
|
|
2835
2923
|
}
|
|
2836
2924
|
return null;
|
|
2837
2925
|
}
|
|
2926
|
+
/**
|
|
2927
|
+
* get the pure geometric shape of an excalidraw element
|
|
2928
|
+
* which is then used for hit detection
|
|
2929
|
+
*/
|
|
2930
|
+
getElementShape(element) {
|
|
2931
|
+
switch (element.type) {
|
|
2932
|
+
case "rectangle":
|
|
2933
|
+
case "diamond":
|
|
2934
|
+
case "frame":
|
|
2935
|
+
case "magicframe":
|
|
2936
|
+
case "embeddable":
|
|
2937
|
+
case "image":
|
|
2938
|
+
case "iframe":
|
|
2939
|
+
case "text":
|
|
2940
|
+
case "selection":
|
|
2941
|
+
return getPolygonShape(element);
|
|
2942
|
+
case "arrow":
|
|
2943
|
+
case "line": {
|
|
2944
|
+
const roughShape = ShapeCache.get(element)?.[0] ??
|
|
2945
|
+
ShapeCache.generateElementShape(element, null)[0];
|
|
2946
|
+
const [, , , , cx, cy] = getElementAbsoluteCoords(element, this.scene.getNonDeletedElementsMap());
|
|
2947
|
+
return shouldTestInside(element)
|
|
2948
|
+
? getClosedCurveShape(element, roughShape, [element.x, element.y], element.angle, [cx, cy])
|
|
2949
|
+
: getCurveShape(roughShape, [element.x, element.y], element.angle, [
|
|
2950
|
+
cx,
|
|
2951
|
+
cy,
|
|
2952
|
+
]);
|
|
2953
|
+
}
|
|
2954
|
+
case "ellipse":
|
|
2955
|
+
return getEllipseShape(element);
|
|
2956
|
+
case "freedraw": {
|
|
2957
|
+
const [, , , , cx, cy] = getElementAbsoluteCoords(element, this.scene.getNonDeletedElementsMap());
|
|
2958
|
+
return getFreedrawShape(element, [cx, cy], shouldTestInside(element));
|
|
2959
|
+
}
|
|
2960
|
+
}
|
|
2961
|
+
}
|
|
2962
|
+
getBoundTextShape(element) {
|
|
2963
|
+
const boundTextElement = getBoundTextElement(element, this.scene.getNonDeletedElementsMap());
|
|
2964
|
+
if (boundTextElement) {
|
|
2965
|
+
if (element.type === "arrow") {
|
|
2966
|
+
return this.getElementShape({
|
|
2967
|
+
...boundTextElement,
|
|
2968
|
+
// arrow's bound text accurate position is not stored in the element's property
|
|
2969
|
+
// but rather calculated and returned from the following static method
|
|
2970
|
+
...LinearElementEditor.getBoundTextElementPosition(element, boundTextElement, this.scene.getNonDeletedElementsMap()),
|
|
2971
|
+
});
|
|
2972
|
+
}
|
|
2973
|
+
return this.getElementShape(boundTextElement);
|
|
2974
|
+
}
|
|
2975
|
+
return null;
|
|
2976
|
+
}
|
|
2838
2977
|
getElementAtPosition(x, y, opts) {
|
|
2839
2978
|
const allHitElements = this.getElementsAtPosition(x, y, opts?.includeBoundTextElement, opts?.includeLockedElements);
|
|
2840
2979
|
if (allHitElements.length > 1) {
|
|
@@ -2848,9 +2987,20 @@ class App extends React.Component {
|
|
|
2848
2987
|
const elementWithHighestZIndex = allHitElements[allHitElements.length - 1];
|
|
2849
2988
|
// If we're hitting element with highest z-index only on its bounding box
|
|
2850
2989
|
// while also hitting other element figure, the latter should be considered.
|
|
2851
|
-
return
|
|
2852
|
-
|
|
2853
|
-
|
|
2990
|
+
return hitElementItself({
|
|
2991
|
+
x,
|
|
2992
|
+
y,
|
|
2993
|
+
element: elementWithHighestZIndex,
|
|
2994
|
+
shape: this.getElementShape(elementWithHighestZIndex),
|
|
2995
|
+
// when overlapping, we would like to be more precise
|
|
2996
|
+
// this also avoids the need to update past tests
|
|
2997
|
+
threshold: this.getElementHitThreshold() / 2,
|
|
2998
|
+
frameNameBound: isFrameLikeElement(elementWithHighestZIndex)
|
|
2999
|
+
? this.frameNameBoundsCache.get(elementWithHighestZIndex)
|
|
3000
|
+
: null,
|
|
3001
|
+
})
|
|
3002
|
+
? elementWithHighestZIndex
|
|
3003
|
+
: allHitElements[allHitElements.length - 2];
|
|
2854
3004
|
}
|
|
2855
3005
|
if (allHitElements.length === 1) {
|
|
2856
3006
|
return allHitElements[0];
|
|
@@ -2858,15 +3008,17 @@ class App extends React.Component {
|
|
|
2858
3008
|
return null;
|
|
2859
3009
|
}
|
|
2860
3010
|
getElementsAtPosition(x, y, includeBoundTextElement = false, includeLockedElements = false) {
|
|
2861
|
-
const
|
|
3011
|
+
const iframeLikes = [];
|
|
3012
|
+
const elementsMap = this.scene.getNonDeletedElementsMap();
|
|
3013
|
+
const elements = (includeBoundTextElement && includeLockedElements
|
|
2862
3014
|
? this.scene.getNonDeletedElements()
|
|
2863
3015
|
: this.scene
|
|
2864
3016
|
.getNonDeletedElements()
|
|
2865
3017
|
.filter((element) => (includeLockedElements || !element.locked) &&
|
|
2866
3018
|
(includeBoundTextElement ||
|
|
2867
|
-
!(isTextElement(element) && element.containerId)))
|
|
2868
|
-
|
|
2869
|
-
|
|
3019
|
+
!(isTextElement(element) && element.containerId))))
|
|
3020
|
+
.filter((el) => this.hitElement(x, y, el))
|
|
3021
|
+
.filter((element) => {
|
|
2870
3022
|
// hitting a frame's element from outside the frame is not considered a hit
|
|
2871
3023
|
const containingFrame = getContainingFrame(element, elementsMap);
|
|
2872
3024
|
return containingFrame &&
|
|
@@ -2874,9 +3026,82 @@ class App extends React.Component {
|
|
|
2874
3026
|
this.state.frameRendering.clip
|
|
2875
3027
|
? isCursorInFrame({ x, y }, containingFrame, elementsMap)
|
|
2876
3028
|
: true;
|
|
3029
|
+
})
|
|
3030
|
+
.filter((el) => {
|
|
3031
|
+
// The parameter elements comes ordered from lower z-index to higher.
|
|
3032
|
+
// We want to preserve that order on the returned array.
|
|
3033
|
+
// Exception being embeddables which should be on top of everything else in
|
|
3034
|
+
// terms of hit testing.
|
|
3035
|
+
if (isIframeElement(el)) {
|
|
3036
|
+
iframeLikes.push(el);
|
|
3037
|
+
return false;
|
|
3038
|
+
}
|
|
3039
|
+
return true;
|
|
3040
|
+
})
|
|
3041
|
+
.concat(iframeLikes);
|
|
3042
|
+
return elements;
|
|
3043
|
+
}
|
|
3044
|
+
getElementHitThreshold() {
|
|
3045
|
+
return DEFAULT_COLLISION_THRESHOLD / this.state.zoom.value;
|
|
3046
|
+
}
|
|
3047
|
+
hitElement(x, y, element, considerBoundingBox = true) {
|
|
3048
|
+
// if the element is selected, then hit test is done against its bounding box
|
|
3049
|
+
if (considerBoundingBox &&
|
|
3050
|
+
this.state.selectedElementIds[element.id] &&
|
|
3051
|
+
shouldShowBoundingBox([element], this.state)) {
|
|
3052
|
+
const selectionShape = getSelectionBoxShape(element, this.scene.getNonDeletedElementsMap(), this.getElementHitThreshold());
|
|
3053
|
+
return isPointInShape([x, y], selectionShape);
|
|
3054
|
+
}
|
|
3055
|
+
// take bound text element into consideration for hit collision as well
|
|
3056
|
+
const hitBoundTextOfElement = hitElementBoundText(x, y, this.getBoundTextShape(element));
|
|
3057
|
+
if (hitBoundTextOfElement) {
|
|
3058
|
+
return true;
|
|
3059
|
+
}
|
|
3060
|
+
return hitElementItself({
|
|
3061
|
+
x,
|
|
3062
|
+
y,
|
|
3063
|
+
element,
|
|
3064
|
+
shape: this.getElementShape(element),
|
|
3065
|
+
threshold: this.getElementHitThreshold(),
|
|
3066
|
+
frameNameBound: isFrameLikeElement(element)
|
|
3067
|
+
? this.frameNameBoundsCache.get(element)
|
|
3068
|
+
: null,
|
|
2877
3069
|
});
|
|
2878
3070
|
}
|
|
2879
|
-
|
|
3071
|
+
getTextBindableContainerAtPosition(x, y) {
|
|
3072
|
+
const elements = this.scene.getNonDeletedElements();
|
|
3073
|
+
const selectedElements = this.scene.getSelectedElements(this.state);
|
|
3074
|
+
if (selectedElements.length === 1) {
|
|
3075
|
+
return isTextBindableContainer(selectedElements[0], false)
|
|
3076
|
+
? selectedElements[0]
|
|
3077
|
+
: null;
|
|
3078
|
+
}
|
|
3079
|
+
let hitElement = null;
|
|
3080
|
+
// We need to do hit testing from front (end of the array) to back (beginning of the array)
|
|
3081
|
+
for (let index = elements.length - 1; index >= 0; --index) {
|
|
3082
|
+
if (elements[index].isDeleted) {
|
|
3083
|
+
continue;
|
|
3084
|
+
}
|
|
3085
|
+
const [x1, y1, x2, y2] = getElementAbsoluteCoords(elements[index], this.scene.getNonDeletedElementsMap());
|
|
3086
|
+
if (isArrowElement(elements[index]) &&
|
|
3087
|
+
hitElementItself({
|
|
3088
|
+
x,
|
|
3089
|
+
y,
|
|
3090
|
+
element: elements[index],
|
|
3091
|
+
shape: this.getElementShape(elements[index]),
|
|
3092
|
+
threshold: this.getElementHitThreshold(),
|
|
3093
|
+
})) {
|
|
3094
|
+
hitElement = elements[index];
|
|
3095
|
+
break;
|
|
3096
|
+
}
|
|
3097
|
+
else if (x1 < x && x < x2 && y1 < y && y < y2) {
|
|
3098
|
+
hitElement = elements[index];
|
|
3099
|
+
break;
|
|
3100
|
+
}
|
|
3101
|
+
}
|
|
3102
|
+
return isTextBindableContainer(hitElement, false) ? hitElement : null;
|
|
3103
|
+
}
|
|
3104
|
+
startTextEditing = ({ sceneX, sceneY, insertAtParentCenter = true, container, autoEdit = true, }) => {
|
|
2880
3105
|
let shouldBindToContainer = false;
|
|
2881
3106
|
let parentCenterPosition = insertAtParentCenter &&
|
|
2882
3107
|
this.getTextWysiwygSnappedToCenterPosition(sceneX, sceneY, this.state, container);
|
|
@@ -2974,15 +3199,20 @@ class App extends React.Component {
|
|
|
2974
3199
|
this.scene.insertElementAtIndex(element, containerIndex + 1);
|
|
2975
3200
|
}
|
|
2976
3201
|
else {
|
|
2977
|
-
this.scene.
|
|
3202
|
+
this.scene.insertElement(element);
|
|
2978
3203
|
}
|
|
2979
3204
|
}
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
3205
|
+
if (autoEdit || existingTextElement || container) {
|
|
3206
|
+
this.handleTextWysiwyg(element, {
|
|
3207
|
+
isExistingElement: !!existingTextElement,
|
|
3208
|
+
});
|
|
3209
|
+
}
|
|
3210
|
+
else {
|
|
3211
|
+
this.setState({
|
|
3212
|
+
draggingElement: element,
|
|
3213
|
+
multiElement: null,
|
|
3214
|
+
});
|
|
3215
|
+
}
|
|
2986
3216
|
};
|
|
2987
3217
|
handleCanvasDoubleClick = (event) => {
|
|
2988
3218
|
// case: double-clicking with arrow/line tool selected would both create
|
|
@@ -2999,7 +3229,7 @@ class App extends React.Component {
|
|
|
2999
3229
|
if (event[KEYS.CTRL_OR_CMD] &&
|
|
3000
3230
|
(!this.state.editingLinearElement ||
|
|
3001
3231
|
this.state.editingLinearElement.elementId !== selectedElements[0].id)) {
|
|
3002
|
-
this.
|
|
3232
|
+
this.store.shouldCaptureIncrement();
|
|
3003
3233
|
this.setState({
|
|
3004
3234
|
editingLinearElement: new LinearElementEditor(selectedElements[0]),
|
|
3005
3235
|
});
|
|
@@ -3014,6 +3244,7 @@ class App extends React.Component {
|
|
|
3014
3244
|
const selectedGroupId = hitElement &&
|
|
3015
3245
|
getSelectedGroupIdForElement(hitElement, this.state.selectedGroupIds);
|
|
3016
3246
|
if (selectedGroupId) {
|
|
3247
|
+
this.store.shouldCaptureIncrement();
|
|
3017
3248
|
this.setState((prevState) => ({
|
|
3018
3249
|
...prevState,
|
|
3019
3250
|
...selectGroupsForSelectedElements({
|
|
@@ -3033,11 +3264,17 @@ class App extends React.Component {
|
|
|
3033
3264
|
});
|
|
3034
3265
|
return;
|
|
3035
3266
|
}
|
|
3036
|
-
const container =
|
|
3267
|
+
const container = this.getTextBindableContainerAtPosition(sceneX, sceneY);
|
|
3037
3268
|
if (container) {
|
|
3038
3269
|
if (hasBoundTextElement(container) ||
|
|
3039
3270
|
!isTransparent(container.backgroundColor) ||
|
|
3040
|
-
|
|
3271
|
+
hitElementItself({
|
|
3272
|
+
x: sceneX,
|
|
3273
|
+
y: sceneY,
|
|
3274
|
+
element: container,
|
|
3275
|
+
shape: this.getElementShape(container),
|
|
3276
|
+
threshold: this.getElementHitThreshold(),
|
|
3277
|
+
})) {
|
|
3041
3278
|
const midPoint = getContainerCenter(container, this.state, this.scene.getNonDeletedElementsMap());
|
|
3042
3279
|
sceneX = midPoint.x;
|
|
3043
3280
|
sceneY = midPoint.y;
|
|
@@ -3092,7 +3329,7 @@ class App extends React.Component {
|
|
|
3092
3329
|
}
|
|
3093
3330
|
if (!customEvent?.defaultPrevented) {
|
|
3094
3331
|
const target = isLocalLink(url) ? "_self" : "_blank";
|
|
3095
|
-
const newWindow = window.open(undefined, target
|
|
3332
|
+
const newWindow = window.open(undefined, target);
|
|
3096
3333
|
// https://mathiasbynens.github.io/rel-noopener/
|
|
3097
3334
|
if (newWindow) {
|
|
3098
3335
|
newWindow.opener = null;
|
|
@@ -3142,8 +3379,11 @@ class App extends React.Component {
|
|
|
3142
3379
|
}, state);
|
|
3143
3380
|
this.translateCanvas({
|
|
3144
3381
|
zoom: zoomState.zoom,
|
|
3145
|
-
|
|
3146
|
-
|
|
3382
|
+
// 2x multiplier is just a magic number that makes this work correctly
|
|
3383
|
+
// on touchscreen devices (note: if we get report that panning is slower/faster
|
|
3384
|
+
// than actual movement, consider swapping with devicePixelRatio)
|
|
3385
|
+
scrollX: zoomState.scrollX + 2 * (deltaX / nextZoom),
|
|
3386
|
+
scrollY: zoomState.scrollY + 2 * (deltaY / nextZoom),
|
|
3147
3387
|
shouldCacheIgnoreZoom: true,
|
|
3148
3388
|
});
|
|
3149
3389
|
});
|
|
@@ -3308,15 +3548,23 @@ class App extends React.Component {
|
|
|
3308
3548
|
if (selectedElements.length === 1 &&
|
|
3309
3549
|
!isOverScrollBar &&
|
|
3310
3550
|
!this.state.editingLinearElement) {
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3551
|
+
// for linear elements, we'd like to prioritize point dragging over edge resizing
|
|
3552
|
+
// therefore, we update and check hovered point index first
|
|
3553
|
+
if (this.state.selectedLinearElement) {
|
|
3554
|
+
this.handleHoverSelectedLinearElement(this.state.selectedLinearElement, scenePointerX, scenePointerY);
|
|
3555
|
+
}
|
|
3556
|
+
if (!this.state.selectedLinearElement ||
|
|
3557
|
+
this.state.selectedLinearElement.hoverPointIndex === -1) {
|
|
3558
|
+
const elementWithTransformHandleType = getElementWithTransformHandleType(elements, this.state, scenePointerX, scenePointerY, this.state.zoom, event.pointerType, this.scene.getNonDeletedElementsMap(), this.device);
|
|
3559
|
+
if (elementWithTransformHandleType &&
|
|
3560
|
+
elementWithTransformHandleType.transformHandleType) {
|
|
3561
|
+
setCursor(this.interactiveCanvas, getCursorForResizingElement(elementWithTransformHandleType));
|
|
3562
|
+
return;
|
|
3563
|
+
}
|
|
3316
3564
|
}
|
|
3317
3565
|
}
|
|
3318
3566
|
else if (selectedElements.length > 1 && !isOverScrollBar) {
|
|
3319
|
-
const transformHandleType = getTransformHandleTypeFromCoords(getCommonBounds(selectedElements), scenePointerX, scenePointerY, this.state.zoom, event.pointerType);
|
|
3567
|
+
const transformHandleType = getTransformHandleTypeFromCoords(getCommonBounds(selectedElements), scenePointerX, scenePointerY, this.state.zoom, event.pointerType, this.device);
|
|
3320
3568
|
if (transformHandleType) {
|
|
3321
3569
|
setCursor(this.interactiveCanvas, getCursorForResizingElement({
|
|
3322
3570
|
transformHandleType,
|
|
@@ -3420,7 +3668,7 @@ class App extends React.Component {
|
|
|
3420
3668
|
}
|
|
3421
3669
|
};
|
|
3422
3670
|
const distance = distance2d(pointerDownState.lastCoords.x, pointerDownState.lastCoords.y, scenePointer.x, scenePointer.y);
|
|
3423
|
-
const threshold =
|
|
3671
|
+
const threshold = this.getElementHitThreshold();
|
|
3424
3672
|
const point = { ...pointerDownState.lastCoords };
|
|
3425
3673
|
let samplingInterval = 0;
|
|
3426
3674
|
while (samplingInterval <= distance) {
|
|
@@ -3456,7 +3704,7 @@ class App extends React.Component {
|
|
|
3456
3704
|
}
|
|
3457
3705
|
}
|
|
3458
3706
|
this.elementsPendingErasure = new Set(this.elementsPendingErasure);
|
|
3459
|
-
this.
|
|
3707
|
+
this.triggerRender();
|
|
3460
3708
|
}
|
|
3461
3709
|
};
|
|
3462
3710
|
// set touch moving for mobile context menu
|
|
@@ -3466,30 +3714,29 @@ class App extends React.Component {
|
|
|
3466
3714
|
handleHoverSelectedLinearElement(linearElementEditor, scenePointerX, scenePointerY) {
|
|
3467
3715
|
const elementsMap = this.scene.getNonDeletedElementsMap();
|
|
3468
3716
|
const element = LinearElementEditor.getElement(linearElementEditor.elementId, elementsMap);
|
|
3469
|
-
const boundTextElement = getBoundTextElement(element, elementsMap);
|
|
3470
3717
|
if (!element) {
|
|
3471
3718
|
return;
|
|
3472
3719
|
}
|
|
3473
3720
|
if (this.state.selectedLinearElement) {
|
|
3474
3721
|
let hoverPointIndex = -1;
|
|
3475
3722
|
let segmentMidPointHoveredCoords = null;
|
|
3476
|
-
if (
|
|
3723
|
+
if (hitElementItself({
|
|
3724
|
+
x: scenePointerX,
|
|
3725
|
+
y: scenePointerY,
|
|
3726
|
+
element,
|
|
3727
|
+
shape: this.getElementShape(element),
|
|
3728
|
+
})) {
|
|
3477
3729
|
hoverPointIndex = LinearElementEditor.getPointIndexUnderCursor(element, elementsMap, this.state.zoom, scenePointerX, scenePointerY);
|
|
3478
3730
|
segmentMidPointHoveredCoords =
|
|
3479
3731
|
LinearElementEditor.getSegmentMidpointHitCoords(linearElementEditor, { x: scenePointerX, y: scenePointerY }, this.state, this.scene.getNonDeletedElementsMap());
|
|
3480
3732
|
if (hoverPointIndex >= 0 || segmentMidPointHoveredCoords) {
|
|
3481
3733
|
setCursor(this.interactiveCanvas, CURSOR_TYPE.POINTER);
|
|
3482
3734
|
}
|
|
3483
|
-
else {
|
|
3735
|
+
else if (this.hitElement(scenePointerX, scenePointerY, element)) {
|
|
3484
3736
|
setCursor(this.interactiveCanvas, CURSOR_TYPE.MOVE);
|
|
3485
3737
|
}
|
|
3486
3738
|
}
|
|
3487
|
-
else if (
|
|
3488
|
-
isHittingElementBoundingBoxWithoutHittingElement(element, this.state, this.frameNameBoundsCache, scenePointerX, scenePointerY, elementsMap)) {
|
|
3489
|
-
setCursor(this.interactiveCanvas, CURSOR_TYPE.MOVE);
|
|
3490
|
-
}
|
|
3491
|
-
else if (boundTextElement &&
|
|
3492
|
-
hitTest(boundTextElement, this.state, this.frameNameBoundsCache, scenePointerX, scenePointerY, this.scene.getNonDeletedElementsMap())) {
|
|
3739
|
+
else if (this.hitElement(scenePointerX, scenePointerY, element)) {
|
|
3493
3740
|
setCursor(this.interactiveCanvas, CURSOR_TYPE.MOVE);
|
|
3494
3741
|
}
|
|
3495
3742
|
if (this.state.selectedLinearElement.hoverPointIndex !== hoverPointIndex) {
|
|
@@ -3556,6 +3803,7 @@ class App extends React.Component {
|
|
|
3556
3803
|
return obj;
|
|
3557
3804
|
}, {}), this.state),
|
|
3558
3805
|
},
|
|
3806
|
+
storeAction: StoreAction.UPDATE,
|
|
3559
3807
|
});
|
|
3560
3808
|
return;
|
|
3561
3809
|
}
|
|
@@ -3667,7 +3915,6 @@ class App extends React.Component {
|
|
|
3667
3915
|
}
|
|
3668
3916
|
if (this.state.activeTool.type === "text") {
|
|
3669
3917
|
this.handleTextOnPointerDown(event, pointerDownState);
|
|
3670
|
-
return;
|
|
3671
3918
|
}
|
|
3672
3919
|
else if (this.state.activeTool.type === "arrow" ||
|
|
3673
3920
|
this.state.activeTool.type === "line") {
|
|
@@ -3995,8 +4242,11 @@ class App extends React.Component {
|
|
|
3995
4242
|
const elements = this.scene.getNonDeletedElements();
|
|
3996
4243
|
const elementsMap = this.scene.getNonDeletedElementsMap();
|
|
3997
4244
|
const selectedElements = this.scene.getSelectedElements(this.state);
|
|
3998
|
-
if (selectedElements.length === 1 &&
|
|
3999
|
-
|
|
4245
|
+
if (selectedElements.length === 1 &&
|
|
4246
|
+
!this.state.editingLinearElement &&
|
|
4247
|
+
!(this.state.selectedLinearElement &&
|
|
4248
|
+
this.state.selectedLinearElement.hoverPointIndex !== -1)) {
|
|
4249
|
+
const elementWithTransformHandleType = getElementWithTransformHandleType(elements, this.state, pointerDownState.origin.x, pointerDownState.origin.y, this.state.zoom, event.pointerType, this.scene.getNonDeletedElementsMap(), this.device);
|
|
4000
4250
|
if (elementWithTransformHandleType != null) {
|
|
4001
4251
|
this.setState({
|
|
4002
4252
|
resizingElement: elementWithTransformHandleType.element,
|
|
@@ -4006,7 +4256,7 @@ class App extends React.Component {
|
|
|
4006
4256
|
}
|
|
4007
4257
|
}
|
|
4008
4258
|
else if (selectedElements.length > 1) {
|
|
4009
|
-
pointerDownState.resize.handleType = getTransformHandleTypeFromCoords(getCommonBounds(selectedElements), pointerDownState.origin.x, pointerDownState.origin.y, this.state.zoom, event.pointerType);
|
|
4259
|
+
pointerDownState.resize.handleType = getTransformHandleTypeFromCoords(getCommonBounds(selectedElements), pointerDownState.origin.x, pointerDownState.origin.y, this.state.zoom, event.pointerType, this.device);
|
|
4010
4260
|
}
|
|
4011
4261
|
if (pointerDownState.resize.handleType) {
|
|
4012
4262
|
pointerDownState.resize.isResizing = true;
|
|
@@ -4020,7 +4270,7 @@ class App extends React.Component {
|
|
|
4020
4270
|
else {
|
|
4021
4271
|
if (this.state.selectedLinearElement) {
|
|
4022
4272
|
const linearElementEditor = this.state.editingLinearElement || this.state.selectedLinearElement;
|
|
4023
|
-
const ret = LinearElementEditor.handlePointerDown(event, this.state, this.
|
|
4273
|
+
const ret = LinearElementEditor.handlePointerDown(event, this.state, this.store, pointerDownState.origin, linearElementEditor, this);
|
|
4024
4274
|
if (ret.hitElement) {
|
|
4025
4275
|
pointerDownState.hit.element = ret.hitElement;
|
|
4026
4276
|
}
|
|
@@ -4181,7 +4431,7 @@ class App extends React.Component {
|
|
|
4181
4431
|
return false;
|
|
4182
4432
|
}
|
|
4183
4433
|
// How many pixels off the shape boundary we still consider a hit
|
|
4184
|
-
const threshold =
|
|
4434
|
+
const threshold = this.getElementHitThreshold();
|
|
4185
4435
|
const [x1, y1, x2, y2] = getCommonBounds(selectedElements);
|
|
4186
4436
|
return (point.x > x1 - threshold &&
|
|
4187
4437
|
point.x < x2 + threshold &&
|
|
@@ -4201,7 +4451,7 @@ class App extends React.Component {
|
|
|
4201
4451
|
includeBoundTextElement: true,
|
|
4202
4452
|
});
|
|
4203
4453
|
// FIXME
|
|
4204
|
-
let container =
|
|
4454
|
+
let container = this.getTextBindableContainerAtPosition(sceneX, sceneY);
|
|
4205
4455
|
if (hasBoundTextElement(element)) {
|
|
4206
4456
|
container = element;
|
|
4207
4457
|
sceneX = element.x + element.width / 2;
|
|
@@ -4212,6 +4462,7 @@ class App extends React.Component {
|
|
|
4212
4462
|
sceneY,
|
|
4213
4463
|
insertAtParentCenter: !event.altKey,
|
|
4214
4464
|
container,
|
|
4465
|
+
autoEdit: false,
|
|
4215
4466
|
});
|
|
4216
4467
|
resetCursor(this.interactiveCanvas);
|
|
4217
4468
|
if (!this.state.activeTool.locked) {
|
|
@@ -4259,8 +4510,8 @@ class App extends React.Component {
|
|
|
4259
4510
|
points: [[0, 0]],
|
|
4260
4511
|
pressures,
|
|
4261
4512
|
});
|
|
4262
|
-
const boundElement = getHoveredElementForBinding(pointerDownState.origin, this
|
|
4263
|
-
this.scene.
|
|
4513
|
+
const boundElement = getHoveredElementForBinding(pointerDownState.origin, this);
|
|
4514
|
+
this.scene.insertElement(element);
|
|
4264
4515
|
this.setState({
|
|
4265
4516
|
draggingElement: element,
|
|
4266
4517
|
editingElement: element,
|
|
@@ -4288,10 +4539,7 @@ class App extends React.Component {
|
|
|
4288
4539
|
width,
|
|
4289
4540
|
height,
|
|
4290
4541
|
});
|
|
4291
|
-
this.scene.
|
|
4292
|
-
...this.scene.getElementsIncludingDeleted(),
|
|
4293
|
-
element,
|
|
4294
|
-
]);
|
|
4542
|
+
this.scene.insertElement(element);
|
|
4295
4543
|
return element;
|
|
4296
4544
|
};
|
|
4297
4545
|
//create rectangle element with youtube top left on nearest grid point width / hight 640/360
|
|
@@ -4326,10 +4574,7 @@ class App extends React.Component {
|
|
|
4326
4574
|
height: embedLink.intrinsicSize.h,
|
|
4327
4575
|
link,
|
|
4328
4576
|
});
|
|
4329
|
-
this.scene.
|
|
4330
|
-
...this.scene.getElementsIncludingDeleted(),
|
|
4331
|
-
element,
|
|
4332
|
-
]);
|
|
4577
|
+
this.scene.insertElement(element);
|
|
4333
4578
|
return element;
|
|
4334
4579
|
};
|
|
4335
4580
|
createImageElement = ({ sceneX, sceneY, addToFrameUnderCursor = true, }) => {
|
|
@@ -4437,8 +4682,8 @@ class App extends React.Component {
|
|
|
4437
4682
|
mutateElement(element, {
|
|
4438
4683
|
points: [...element.points, [0, 0]],
|
|
4439
4684
|
});
|
|
4440
|
-
const boundElement = getHoveredElementForBinding(pointerDownState.origin, this
|
|
4441
|
-
this.scene.
|
|
4685
|
+
const boundElement = getHoveredElementForBinding(pointerDownState.origin, this);
|
|
4686
|
+
this.scene.insertElement(element);
|
|
4442
4687
|
this.setState({
|
|
4443
4688
|
draggingElement: element,
|
|
4444
4689
|
editingElement: element,
|
|
@@ -4498,7 +4743,7 @@ class App extends React.Component {
|
|
|
4498
4743
|
});
|
|
4499
4744
|
}
|
|
4500
4745
|
else {
|
|
4501
|
-
this.scene.
|
|
4746
|
+
this.scene.insertElement(element);
|
|
4502
4747
|
this.setState({
|
|
4503
4748
|
multiElement: null,
|
|
4504
4749
|
draggingElement: element,
|
|
@@ -4520,10 +4765,7 @@ class App extends React.Component {
|
|
|
4520
4765
|
const frame = type === TOOL_TYPE.magicframe
|
|
4521
4766
|
? newMagicFrameElement(constructorOpts)
|
|
4522
4767
|
: newFrameElement(constructorOpts);
|
|
4523
|
-
this.scene.
|
|
4524
|
-
...this.scene.getElementsIncludingDeleted(),
|
|
4525
|
-
frame,
|
|
4526
|
-
]);
|
|
4768
|
+
this.scene.insertElement(frame);
|
|
4527
4769
|
this.setState({
|
|
4528
4770
|
multiElement: null,
|
|
4529
4771
|
draggingElement: frame,
|
|
@@ -4737,7 +4979,9 @@ class App extends React.Component {
|
|
|
4737
4979
|
// able to select and interact with the text input
|
|
4738
4980
|
!this.state.editingFrame &&
|
|
4739
4981
|
dragSelectedElements(pointerDownState, selectedElements, dragOffset, this.state, this.scene, snapOffset, event[KEYS.CTRL_OR_CMD] ? null : this.state.gridSize);
|
|
4740
|
-
this.
|
|
4982
|
+
this.setState({
|
|
4983
|
+
suggestedBindings: getSuggestedBindingsForArrows(selectedElements, this),
|
|
4984
|
+
});
|
|
4741
4985
|
// We duplicate the selected element if alt is pressed on pointer move
|
|
4742
4986
|
if (event.altKey && !pointerDownState.hit.hasBeenDuplicated) {
|
|
4743
4987
|
// Move the currently selected elements to the top of the z index stack, and
|
|
@@ -4781,6 +5025,7 @@ class App extends React.Component {
|
|
|
4781
5025
|
}
|
|
4782
5026
|
}
|
|
4783
5027
|
const nextSceneElements = [...nextElements, ...elementsToAppend];
|
|
5028
|
+
syncMovedIndices(nextSceneElements, arrayToMap(elementsToAppend));
|
|
4784
5029
|
bindTextToShapeAfterDuplication(nextElements, elementsToAppend, oldIdToDuplicatedId);
|
|
4785
5030
|
fixBindingsAfterDuplication(nextSceneElements, elementsToAppend, oldIdToDuplicatedId, "duplicatesServeAsOld");
|
|
4786
5031
|
bindElementsToFramesAfterDuplication(nextSceneElements, elementsToAppend, oldIdToDuplicatedId);
|
|
@@ -4972,7 +5217,7 @@ class App extends React.Component {
|
|
|
4972
5217
|
this.actionManager.executeAction(actionFinalize);
|
|
4973
5218
|
}
|
|
4974
5219
|
else {
|
|
4975
|
-
const editingLinearElement = LinearElementEditor.handlePointerUp(childEvent, this.state.editingLinearElement, this.state, this
|
|
5220
|
+
const editingLinearElement = LinearElementEditor.handlePointerUp(childEvent, this.state.editingLinearElement, this.state, this);
|
|
4976
5221
|
if (editingLinearElement !== this.state.editingLinearElement) {
|
|
4977
5222
|
this.setState({
|
|
4978
5223
|
editingLinearElement,
|
|
@@ -4991,7 +5236,7 @@ class App extends React.Component {
|
|
|
4991
5236
|
}
|
|
4992
5237
|
}
|
|
4993
5238
|
else {
|
|
4994
|
-
const linearElementEditor = LinearElementEditor.handlePointerUp(childEvent, this.state.selectedLinearElement, this.state, this
|
|
5239
|
+
const linearElementEditor = LinearElementEditor.handlePointerUp(childEvent, this.state.selectedLinearElement, this.state, this);
|
|
4995
5240
|
const { startBindingElement, endBindingElement } = linearElementEditor;
|
|
4996
5241
|
const element = this.scene.getElement(linearElementEditor.elementId);
|
|
4997
5242
|
if (isBindingElement(element)) {
|
|
@@ -5060,7 +5305,7 @@ class App extends React.Component {
|
|
|
5060
5305
|
}
|
|
5061
5306
|
if (isLinearElement(draggingElement)) {
|
|
5062
5307
|
if (draggingElement.points.length > 1) {
|
|
5063
|
-
this.
|
|
5308
|
+
this.store.shouldCaptureIncrement();
|
|
5064
5309
|
}
|
|
5065
5310
|
const pointerCoords = viewportCoordsToSceneCoords(childEvent, this.state);
|
|
5066
5311
|
if (!pointerDownState.drag.hasOccurred &&
|
|
@@ -5083,7 +5328,7 @@ class App extends React.Component {
|
|
|
5083
5328
|
else if (pointerDownState.drag.hasOccurred && !multiElement) {
|
|
5084
5329
|
if (isBindingEnabled(this.state) &&
|
|
5085
5330
|
isBindingElement(draggingElement, false)) {
|
|
5086
|
-
maybeBindLinearElement(draggingElement, this.state,
|
|
5331
|
+
maybeBindLinearElement(draggingElement, this.state, pointerCoords, this);
|
|
5087
5332
|
}
|
|
5088
5333
|
this.setState({ suggestedBindings: [], startBoundElement: null });
|
|
5089
5334
|
if (!activeTool.locked) {
|
|
@@ -5108,15 +5353,34 @@ class App extends React.Component {
|
|
|
5108
5353
|
}
|
|
5109
5354
|
return;
|
|
5110
5355
|
}
|
|
5356
|
+
if (isTextElement(draggingElement)) {
|
|
5357
|
+
const minWidth = getMinTextElementWidth(getFontString({
|
|
5358
|
+
fontSize: draggingElement.fontSize,
|
|
5359
|
+
fontFamily: draggingElement.fontFamily,
|
|
5360
|
+
}), draggingElement.lineHeight);
|
|
5361
|
+
if (draggingElement.width < minWidth) {
|
|
5362
|
+
mutateElement(draggingElement, {
|
|
5363
|
+
autoResize: true,
|
|
5364
|
+
});
|
|
5365
|
+
}
|
|
5366
|
+
this.resetCursor();
|
|
5367
|
+
this.handleTextWysiwyg(draggingElement, {
|
|
5368
|
+
isExistingElement: true,
|
|
5369
|
+
});
|
|
5370
|
+
}
|
|
5111
5371
|
if (activeTool.type !== "selection" &&
|
|
5112
5372
|
draggingElement &&
|
|
5113
5373
|
isInvisiblySmallElement(draggingElement)) {
|
|
5114
5374
|
// remove invisible element which was added in onPointerDown
|
|
5115
|
-
|
|
5116
|
-
|
|
5117
|
-
|
|
5118
|
-
|
|
5119
|
-
|
|
5375
|
+
// update the store snapshot, so that invisible elements are not captured by the store
|
|
5376
|
+
this.updateScene({
|
|
5377
|
+
elements: this.scene
|
|
5378
|
+
.getElementsIncludingDeleted()
|
|
5379
|
+
.filter((el) => el.id !== draggingElement.id),
|
|
5380
|
+
appState: {
|
|
5381
|
+
draggingElement: null,
|
|
5382
|
+
},
|
|
5383
|
+
storeAction: StoreAction.UPDATE,
|
|
5120
5384
|
});
|
|
5121
5385
|
return;
|
|
5122
5386
|
}
|
|
@@ -5139,7 +5403,7 @@ class App extends React.Component {
|
|
|
5139
5403
|
groupIds: [],
|
|
5140
5404
|
});
|
|
5141
5405
|
removeElementsFromFrame([linearElement], this.scene.getNonDeletedElementsMap());
|
|
5142
|
-
this.scene.
|
|
5406
|
+
this.scene.triggerUpdate();
|
|
5143
5407
|
}
|
|
5144
5408
|
}
|
|
5145
5409
|
}
|
|
@@ -5197,12 +5461,16 @@ class App extends React.Component {
|
|
|
5197
5461
|
mutateElement(draggingElement, getNormalizedDimensions(draggingElement));
|
|
5198
5462
|
}
|
|
5199
5463
|
if (resizingElement) {
|
|
5200
|
-
this.
|
|
5464
|
+
this.store.shouldCaptureIncrement();
|
|
5201
5465
|
}
|
|
5202
5466
|
if (resizingElement && isInvisiblySmallElement(resizingElement)) {
|
|
5203
|
-
|
|
5204
|
-
|
|
5205
|
-
|
|
5467
|
+
// update the store snapshot, so that invisible elements are not captured by the store
|
|
5468
|
+
this.updateScene({
|
|
5469
|
+
elements: this.scene
|
|
5470
|
+
.getElementsIncludingDeleted()
|
|
5471
|
+
.filter((el) => el.id !== resizingElement.id),
|
|
5472
|
+
storeAction: StoreAction.UPDATE,
|
|
5473
|
+
});
|
|
5206
5474
|
}
|
|
5207
5475
|
// handle frame membership for resizing frames and/or selected elements
|
|
5208
5476
|
if (pointerDownState.resize.isResizing) {
|
|
@@ -5357,10 +5625,23 @@ class App extends React.Component {
|
|
|
5357
5625
|
}));
|
|
5358
5626
|
}
|
|
5359
5627
|
}
|
|
5360
|
-
if (
|
|
5628
|
+
if (
|
|
5629
|
+
// not dragged
|
|
5630
|
+
!pointerDownState.drag.hasOccurred &&
|
|
5631
|
+
// not resized
|
|
5361
5632
|
!this.state.isResizing &&
|
|
5633
|
+
// only hitting the bounding box of the previous hit element
|
|
5362
5634
|
((hitElement &&
|
|
5363
|
-
|
|
5635
|
+
hitElementBoundingBoxOnly({
|
|
5636
|
+
x: pointerDownState.origin.x,
|
|
5637
|
+
y: pointerDownState.origin.y,
|
|
5638
|
+
element: hitElement,
|
|
5639
|
+
shape: this.getElementShape(hitElement),
|
|
5640
|
+
threshold: this.getElementHitThreshold(),
|
|
5641
|
+
frameNameBound: isFrameLikeElement(hitElement)
|
|
5642
|
+
? this.frameNameBoundsCache.get(hitElement)
|
|
5643
|
+
: null,
|
|
5644
|
+
}, elementsMap)) ||
|
|
5364
5645
|
(!hitElement &&
|
|
5365
5646
|
pointerDownState.hit.hasHitCommonBoundingBoxOfSelectedElements))) {
|
|
5366
5647
|
if (this.state.editingLinearElement) {
|
|
@@ -5375,6 +5656,8 @@ class App extends React.Component {
|
|
|
5375
5656
|
activeEmbeddable: null,
|
|
5376
5657
|
});
|
|
5377
5658
|
}
|
|
5659
|
+
// reset cursor
|
|
5660
|
+
setCursor(this.interactiveCanvas, CURSOR_TYPE.AUTO);
|
|
5378
5661
|
return;
|
|
5379
5662
|
}
|
|
5380
5663
|
if (!activeTool.locked &&
|
|
@@ -5392,13 +5675,17 @@ class App extends React.Component {
|
|
|
5392
5675
|
}));
|
|
5393
5676
|
}
|
|
5394
5677
|
if (activeTool.type !== "selection" ||
|
|
5395
|
-
isSomeElementSelected(this.scene.getNonDeletedElements(), this.state)
|
|
5396
|
-
this.
|
|
5678
|
+
isSomeElementSelected(this.scene.getNonDeletedElements(), this.state) ||
|
|
5679
|
+
!isShallowEqual(this.state.previousSelectedElementIds, this.state.selectedElementIds)) {
|
|
5680
|
+
this.store.shouldCaptureIncrement();
|
|
5397
5681
|
}
|
|
5398
5682
|
if (pointerDownState.drag.hasOccurred || isResizing || isRotating) {
|
|
5399
|
-
|
|
5400
|
-
|
|
5401
|
-
|
|
5683
|
+
// We only allow binding via linear elements, specifically via dragging
|
|
5684
|
+
// the endpoints ("start" or "end").
|
|
5685
|
+
const linearElements = this.scene
|
|
5686
|
+
.getSelectedElements(this.state)
|
|
5687
|
+
.filter(isLinearElement);
|
|
5688
|
+
bindOrUnbindLinearElements(linearElements, this, isBindingEnabled(this.state), this.state.selectedLinearElement?.selectedPointsIndices ?? []);
|
|
5402
5689
|
}
|
|
5403
5690
|
if (activeTool.type === "laser") {
|
|
5404
5691
|
this.laserTrails.endPath();
|
|
@@ -5433,7 +5720,7 @@ class App extends React.Component {
|
|
|
5433
5720
|
}
|
|
5434
5721
|
restoreReadyToEraseElements = () => {
|
|
5435
5722
|
this.elementsPendingErasure = new Set();
|
|
5436
|
-
this.
|
|
5723
|
+
this.triggerRender();
|
|
5437
5724
|
};
|
|
5438
5725
|
eraseElements = () => {
|
|
5439
5726
|
let didChange = false;
|
|
@@ -5449,7 +5736,7 @@ class App extends React.Component {
|
|
|
5449
5736
|
});
|
|
5450
5737
|
this.elementsPendingErasure = new Set();
|
|
5451
5738
|
if (didChange) {
|
|
5452
|
-
this.
|
|
5739
|
+
this.store.shouldCaptureIncrement();
|
|
5453
5740
|
this.scene.replaceAllElements(elements);
|
|
5454
5741
|
}
|
|
5455
5742
|
};
|
|
@@ -5552,7 +5839,7 @@ class App extends React.Component {
|
|
|
5552
5839
|
this.setState({ errorMessage: t("errors.imageToolNotSupported") });
|
|
5553
5840
|
return;
|
|
5554
5841
|
}
|
|
5555
|
-
this.scene.
|
|
5842
|
+
this.scene.insertElement(imageElement);
|
|
5556
5843
|
try {
|
|
5557
5844
|
return await this.initializeImage({
|
|
5558
5845
|
imageFile,
|
|
@@ -5725,7 +6012,7 @@ class App extends React.Component {
|
|
|
5725
6012
|
if (uncachedImageElements.length) {
|
|
5726
6013
|
const { updatedFiles } = await this.updateImageCache(uncachedImageElements, files);
|
|
5727
6014
|
if (updatedFiles.size) {
|
|
5728
|
-
this.scene.
|
|
6015
|
+
this.scene.triggerUpdate();
|
|
5729
6016
|
}
|
|
5730
6017
|
}
|
|
5731
6018
|
};
|
|
@@ -5741,7 +6028,7 @@ class App extends React.Component {
|
|
|
5741
6028
|
}
|
|
5742
6029
|
};
|
|
5743
6030
|
maybeSuggestBindingAtCursor = (pointerCoords) => {
|
|
5744
|
-
const hoveredBindableElement = getHoveredElementForBinding(pointerCoords, this
|
|
6031
|
+
const hoveredBindableElement = getHoveredElementForBinding(pointerCoords, this);
|
|
5745
6032
|
this.setState({
|
|
5746
6033
|
suggestedBindings: hoveredBindableElement != null ? [hoveredBindableElement] : [],
|
|
5747
6034
|
});
|
|
@@ -5756,7 +6043,7 @@ class App extends React.Component {
|
|
|
5756
6043
|
return;
|
|
5757
6044
|
}
|
|
5758
6045
|
const suggestedBindings = pointerCoords.reduce((acc, coords) => {
|
|
5759
|
-
const hoveredBindableElement = getHoveredElementForBinding(coords, this
|
|
6046
|
+
const hoveredBindableElement = getHoveredElementForBinding(coords, this);
|
|
5760
6047
|
if (hoveredBindableElement != null &&
|
|
5761
6048
|
!isLinearElementSimpleAndAlreadyBound(linearElement, oppositeBindingBoundElement?.id, hoveredBindableElement)) {
|
|
5762
6049
|
acc.push(hoveredBindableElement);
|
|
@@ -5765,13 +6052,6 @@ class App extends React.Component {
|
|
|
5765
6052
|
}, []);
|
|
5766
6053
|
this.setState({ suggestedBindings });
|
|
5767
6054
|
};
|
|
5768
|
-
maybeSuggestBindingForAll(selectedElements) {
|
|
5769
|
-
if (selectedElements.length > 50) {
|
|
5770
|
-
return;
|
|
5771
|
-
}
|
|
5772
|
-
const suggestedBindings = getEligibleElementsForBinding(selectedElements, this.scene.getNonDeletedElements(), this.scene.getNonDeletedElementsMap());
|
|
5773
|
-
this.setState({ suggestedBindings });
|
|
5774
|
-
}
|
|
5775
6055
|
clearSelection(hitElement) {
|
|
5776
6056
|
this.setState((prevState) => ({
|
|
5777
6057
|
selectedElementIds: makeNextSelectedElementIds({}, prevState),
|
|
@@ -5831,7 +6111,7 @@ class App extends React.Component {
|
|
|
5831
6111
|
isLoading: false,
|
|
5832
6112
|
},
|
|
5833
6113
|
replaceFiles: true,
|
|
5834
|
-
|
|
6114
|
+
storeAction: StoreAction.CAPTURE,
|
|
5835
6115
|
});
|
|
5836
6116
|
return;
|
|
5837
6117
|
}
|
|
@@ -5899,9 +6179,10 @@ class App extends React.Component {
|
|
|
5899
6179
|
loadFileToCanvas = async (file, fileHandle) => {
|
|
5900
6180
|
file = await normalizeFile(file);
|
|
5901
6181
|
try {
|
|
6182
|
+
const elements = this.scene.getElementsIncludingDeleted();
|
|
5902
6183
|
let ret;
|
|
5903
6184
|
try {
|
|
5904
|
-
ret = await loadSceneOrLibraryFromBlob(file, this.state,
|
|
6185
|
+
ret = await loadSceneOrLibraryFromBlob(file, this.state, elements, fileHandle);
|
|
5905
6186
|
}
|
|
5906
6187
|
catch (error) {
|
|
5907
6188
|
const imageSceneDataError = error instanceof ImageSceneDataError;
|
|
@@ -5926,6 +6207,10 @@ class App extends React.Component {
|
|
|
5926
6207
|
return;
|
|
5927
6208
|
}
|
|
5928
6209
|
if (ret.type === MIME_TYPES.excalidraw) {
|
|
6210
|
+
// restore the fractional indices by mutating elements
|
|
6211
|
+
syncInvalidIndices(elements.concat(ret.data.elements));
|
|
6212
|
+
// update the store snapshot for old elements, otherwise we would end up with duplicated fractional indices on undo
|
|
6213
|
+
this.store.updateSnapshot(arrayToMap(elements), this.state);
|
|
5929
6214
|
this.setState({ isLoading: true });
|
|
5930
6215
|
this.syncActionResult({
|
|
5931
6216
|
...ret.data,
|
|
@@ -5934,7 +6219,7 @@ class App extends React.Component {
|
|
|
5934
6219
|
isLoading: false,
|
|
5935
6220
|
},
|
|
5936
6221
|
replaceFiles: true,
|
|
5937
|
-
|
|
6222
|
+
storeAction: StoreAction.CAPTURE,
|
|
5938
6223
|
});
|
|
5939
6224
|
}
|
|
5940
6225
|
else if (ret.type === MIME_TYPES.excalidrawlib) {
|
|
@@ -6006,7 +6291,7 @@ class App extends React.Component {
|
|
|
6006
6291
|
}
|
|
6007
6292
|
if (draggingElement.type === "selection" &&
|
|
6008
6293
|
this.state.activeTool.type !== "eraser") {
|
|
6009
|
-
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));
|
|
6294
|
+
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);
|
|
6010
6295
|
}
|
|
6011
6296
|
else {
|
|
6012
6297
|
let [gridX, gridY] = getGridPoint(pointerCoords.x, pointerCoords.y, event[KEYS.CTRL_OR_CMD] ? null : this.state.gridSize);
|
|
@@ -6032,8 +6317,7 @@ class App extends React.Component {
|
|
|
6032
6317
|
});
|
|
6033
6318
|
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)
|
|
6034
6319
|
? !shouldMaintainAspectRatio(event)
|
|
6035
|
-
: shouldMaintainAspectRatio(event), shouldResizeFromCenter(event), aspectRatio, this.state.originSnapOffset);
|
|
6036
|
-
this.maybeSuggestBindingForAll([draggingElement]);
|
|
6320
|
+
: shouldMaintainAspectRatio(event), shouldResizeFromCenter(event), this.state.zoom.value, aspectRatio, this.state.originSnapOffset);
|
|
6037
6321
|
// highlight elements that are to be added to frames on frames creation
|
|
6038
6322
|
if (this.state.activeTool.type === TOOL_TYPE.frame ||
|
|
6039
6323
|
this.state.activeTool.type === TOOL_TYPE.magicframe) {
|
|
@@ -6087,16 +6371,17 @@ class App extends React.Component {
|
|
|
6087
6371
|
snapLines,
|
|
6088
6372
|
});
|
|
6089
6373
|
}
|
|
6090
|
-
if (transformElements(pointerDownState.originalElements, transformHandleType, selectedElements, this.scene.getElementsMapIncludingDeleted(), shouldRotateWithDiscreteAngle(event), shouldResizeFromCenter(event), selectedElements.
|
|
6374
|
+
if (transformElements(pointerDownState.originalElements, transformHandleType, selectedElements, this.scene.getElementsMapIncludingDeleted(), shouldRotateWithDiscreteAngle(event), shouldResizeFromCenter(event), selectedElements.some((element) => isImageElement(element))
|
|
6091
6375
|
? !shouldMaintainAspectRatio(event)
|
|
6092
6376
|
: shouldMaintainAspectRatio(event), resizeX, resizeY, pointerDownState.resize.center.x, pointerDownState.resize.center.y)) {
|
|
6093
|
-
|
|
6377
|
+
const suggestedBindings = getSuggestedBindingsForArrows(selectedElements, this);
|
|
6094
6378
|
const elementsToHighlight = new Set();
|
|
6095
6379
|
selectedFrames.forEach((frame) => {
|
|
6096
6380
|
getElementsInResizingFrame(this.scene.getNonDeletedElements(), frame, this.state, this.scene.getNonDeletedElementsMap()).forEach((element) => elementsToHighlight.add(element));
|
|
6097
6381
|
});
|
|
6098
6382
|
this.setState({
|
|
6099
6383
|
elementsToHighlight: [...elementsToHighlight],
|
|
6384
|
+
suggestedBindings,
|
|
6100
6385
|
});
|
|
6101
6386
|
return true;
|
|
6102
6387
|
}
|
|
@@ -6141,6 +6426,7 @@ class App extends React.Component {
|
|
|
6141
6426
|
return [actionCopy, ...options];
|
|
6142
6427
|
}
|
|
6143
6428
|
return [
|
|
6429
|
+
CONTEXT_MENU_SEPARATOR,
|
|
6144
6430
|
actionCut,
|
|
6145
6431
|
actionCopy,
|
|
6146
6432
|
actionPaste,
|
|
@@ -6153,6 +6439,7 @@ class App extends React.Component {
|
|
|
6153
6439
|
actionPasteStyles,
|
|
6154
6440
|
CONTEXT_MENU_SEPARATOR,
|
|
6155
6441
|
actionGroup,
|
|
6442
|
+
actionTextAutoResize,
|
|
6156
6443
|
actionUnbindText,
|
|
6157
6444
|
actionBindText,
|
|
6158
6445
|
actionWrapTextInContainer,
|
|
@@ -6321,7 +6608,7 @@ export const createTestHook = () => {
|
|
|
6321
6608
|
return this.app?.scene.getElementsIncludingDeleted();
|
|
6322
6609
|
},
|
|
6323
6610
|
set(elements) {
|
|
6324
|
-
return this.app?.scene.replaceAllElements(elements);
|
|
6611
|
+
return this.app?.scene.replaceAllElements(syncInvalidIndices(elements));
|
|
6325
6612
|
},
|
|
6326
6613
|
},
|
|
6327
6614
|
});
|