@excalidraw/excalidraw 0.17.1-890ed9f → 0.17.1-96eeec5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (451) hide show
  1. package/CHANGELOG.md +15 -2
  2. package/dist/browser/dev/excalidraw-assets-dev/{blockDiagram-91b80b7a-ACFH36JV.js → blockDiagram-91b80b7a-H47FTXHA.js} +5 -5
  3. package/dist/browser/dev/excalidraw-assets-dev/{c4Diagram-b2a90758-QZ27YR47.js → c4Diagram-b2a90758-NNJK6GKC.js} +3 -3
  4. package/dist/browser/dev/excalidraw-assets-dev/{chunk-HO2HMSK7.js → chunk-4KQVEBHW.js} +3 -3
  5. package/dist/browser/dev/excalidraw-assets-dev/{chunk-USGV265L.js → chunk-53YI56GV.js} +4 -4
  6. package/dist/browser/dev/excalidraw-assets-dev/{chunk-EDFX3S7X.js → chunk-A2WCJI4I.js} +3 -3
  7. package/dist/browser/dev/excalidraw-assets-dev/{chunk-WQFMSDPT.js → chunk-DEYXWPUO.js} +7503 -2575
  8. package/dist/browser/dev/excalidraw-assets-dev/chunk-DEYXWPUO.js.map +7 -0
  9. package/dist/browser/dev/excalidraw-assets-dev/{chunk-IX4V72YG.js → chunk-EFLPX7NE.js} +6 -6
  10. package/dist/browser/dev/excalidraw-assets-dev/{chunk-XOM7LNOU.js → chunk-EM6LVGFW.js} +27 -4
  11. package/dist/browser/dev/excalidraw-assets-dev/chunk-EM6LVGFW.js.map +7 -0
  12. package/dist/browser/dev/excalidraw-assets-dev/{chunk-MXVETLVM.js → chunk-JYIQCNWV.js} +2 -2
  13. package/dist/browser/dev/excalidraw-assets-dev/{chunk-YZIOORVX.js → chunk-LVIQQW6F.js} +2 -2
  14. package/dist/browser/dev/excalidraw-assets-dev/{chunk-6U7GQNJT.js → chunk-PXLO3FOU.js} +2 -2
  15. package/dist/browser/dev/excalidraw-assets-dev/{chunk-7DACDEY3.js → chunk-TO2AW5PW.js} +2 -2
  16. package/dist/browser/dev/excalidraw-assets-dev/{chunk-NJ77ZFNJ.js → chunk-VURILHLY.js} +2 -2
  17. package/dist/browser/dev/excalidraw-assets-dev/{chunk-2T2GU7NF.js → chunk-ZAYGSUHF.js} +2 -2
  18. package/dist/browser/dev/excalidraw-assets-dev/{chunk-Z3PH3V2B.js → chunk-ZQR5ML6Y.js} +26 -26
  19. package/dist/browser/dev/excalidraw-assets-dev/chunk-ZQR5ML6Y.js.map +7 -0
  20. package/dist/browser/dev/excalidraw-assets-dev/{classDiagram-30eddba6-QSLMH4JW.js → classDiagram-30eddba6-CUYIJICN.js} +5 -5
  21. package/dist/browser/dev/excalidraw-assets-dev/{classDiagram-v2-f2df5561-DY4DYQ5P.js → classDiagram-v2-f2df5561-K6WW6K73.js} +8 -8
  22. package/dist/browser/dev/excalidraw-assets-dev/{dist-Z46EOVOL.js → dist-6QVAH5JA.js} +37 -15
  23. package/dist/browser/dev/excalidraw-assets-dev/dist-6QVAH5JA.js.map +7 -0
  24. package/dist/browser/dev/excalidraw-assets-dev/{en-TR4QLF5E.js → en-AZFA5HJJ.js} +4 -2
  25. package/dist/browser/dev/excalidraw-assets-dev/{erDiagram-47591fe2-SOOJRTCB.js → erDiagram-47591fe2-XGAD7EEP.js} +4 -4
  26. package/dist/browser/dev/excalidraw-assets-dev/{flowDiagram-5540d9b9-AHGL4KPK.js → flowDiagram-5540d9b9-B6EOVNNO.js} +9 -9
  27. package/dist/browser/dev/excalidraw-assets-dev/{flowDiagram-v2-3b53844e-56LDZZWY.js → flowDiagram-v2-3b53844e-NUG24FJH.js} +9 -9
  28. package/dist/browser/dev/excalidraw-assets-dev/{flowchart-elk-definition-5fe447d6-27LUKRI6.js → flowchart-elk-definition-5fe447d6-25Y7PCBL.js} +5 -5
  29. package/dist/browser/dev/excalidraw-assets-dev/{ganttDiagram-9a3bba1f-EHGYGNG6.js → ganttDiagram-9a3bba1f-GNL6ZDTC.js} +2 -2
  30. package/dist/browser/dev/excalidraw-assets-dev/{gitGraphDiagram-96e6b4ee-AJQNBDW5.js → gitGraphDiagram-96e6b4ee-HNW52NVO.js} +2 -2
  31. package/dist/browser/dev/excalidraw-assets-dev/{image-OIPMBJGR.js → image-5XCR4WHS.js} +2 -2
  32. package/dist/browser/dev/excalidraw-assets-dev/{image-OFRRV5MB.css → image-O66MQ7WQ.css} +1 -1
  33. package/dist/browser/dev/excalidraw-assets-dev/image-O66MQ7WQ.css.map +7 -0
  34. package/dist/browser/dev/excalidraw-assets-dev/{infoDiagram-bcd20f53-SWLLQVES.js → infoDiagram-bcd20f53-FWEUVFLT.js} +2 -2
  35. package/dist/browser/dev/excalidraw-assets-dev/{journeyDiagram-4fe6b3dc-7UAVCWOZ.js → journeyDiagram-4fe6b3dc-RZIUI7UG.js} +3 -3
  36. package/dist/browser/dev/excalidraw-assets-dev/{mindmap-definition-f354de21-SROW5KGM.js → mindmap-definition-f354de21-GBVN45GU.js} +3 -3
  37. package/dist/browser/dev/excalidraw-assets-dev/{pieDiagram-79897490-QKCI6NCB.js → pieDiagram-79897490-ECENNII6.js} +2 -2
  38. package/dist/browser/dev/excalidraw-assets-dev/{quadrantDiagram-62f64e94-LNYJZFC5.js → quadrantDiagram-62f64e94-ZMEOFVNL.js} +2 -2
  39. package/dist/browser/dev/excalidraw-assets-dev/{requirementDiagram-05bf5f74-ZZD7ZHFA.js → requirementDiagram-05bf5f74-FHZSFHCR.js} +4 -4
  40. package/dist/browser/dev/excalidraw-assets-dev/{sankeyDiagram-97764748-L75ZZ4UM.js → sankeyDiagram-97764748-VDKIKTA6.js} +2 -2
  41. package/dist/browser/dev/excalidraw-assets-dev/{sequenceDiagram-acc0e65c-6PCU7TDK.js → sequenceDiagram-acc0e65c-6JUSPVKX.js} +3 -3
  42. package/dist/browser/dev/excalidraw-assets-dev/{stateDiagram-0ff1cf1a-WM76WOPR.js → stateDiagram-0ff1cf1a-L3AKWENF.js} +5 -5
  43. package/dist/browser/dev/excalidraw-assets-dev/{stateDiagram-v2-9a9d610d-N4HZW3O2.js → stateDiagram-v2-9a9d610d-NU3GGMCH.js} +8 -8
  44. package/dist/browser/dev/excalidraw-assets-dev/{timeline-definition-fea2a41d-ZHGCAXGP.js → timeline-definition-fea2a41d-JGP7XCHW.js} +2 -2
  45. package/dist/browser/dev/excalidraw-assets-dev/{xychartDiagram-ab372869-2DLOVRAZ.js → xychartDiagram-ab372869-HLFHHF2I.js} +3 -3
  46. package/dist/browser/dev/index.css +199 -77
  47. package/dist/browser/dev/index.css.map +3 -3
  48. package/dist/browser/dev/index.js +12477 -8028
  49. package/dist/browser/dev/index.js.map +4 -4
  50. package/dist/browser/prod/excalidraw-assets/{blockDiagram-91b80b7a-ONPS22AM.js → blockDiagram-91b80b7a-FVCRVGN5.js} +1 -1
  51. package/dist/browser/prod/excalidraw-assets/{c4Diagram-b2a90758-XMIQY7ZT.js → c4Diagram-b2a90758-56CXO7GA.js} +1 -1
  52. package/dist/browser/prod/excalidraw-assets/{chunk-GCHQBOKV.js → chunk-635MQ3CK.js} +1 -1
  53. package/dist/browser/prod/excalidraw-assets/{chunk-5SYIAZGL.js → chunk-7DXALCB2.js} +5 -5
  54. package/dist/browser/prod/excalidraw-assets/{chunk-P5M3G2RP.js → chunk-AIKXYJX3.js} +1 -1
  55. package/dist/browser/prod/excalidraw-assets/{chunk-E2YLWFZX.js → chunk-CR7VMNWC.js} +1 -1
  56. package/dist/browser/prod/excalidraw-assets/{chunk-WEYK4A2L.js → chunk-FFF2CSVG.js} +1 -1
  57. package/dist/browser/prod/excalidraw-assets/{chunk-R3HAIP6R.js → chunk-G4WDCSPE.js} +1 -1
  58. package/dist/browser/prod/excalidraw-assets/{chunk-HFOXJM22.js → chunk-HKZSHFLX.js} +1 -1
  59. package/dist/browser/prod/excalidraw-assets/{chunk-XIMFFJTE.js → chunk-IKCDYWMW.js} +1 -1
  60. package/dist/browser/prod/excalidraw-assets/{chunk-AHLLBBVJ.js → chunk-L5DS24G6.js} +1 -1
  61. package/dist/browser/prod/excalidraw-assets/{chunk-CQJF3C6G.js → chunk-MUNOKHUD.js} +1 -1
  62. package/dist/browser/prod/excalidraw-assets/chunk-ODWTVSS7.js +68 -0
  63. package/dist/browser/prod/excalidraw-assets/{chunk-NI6SYCUG.js → chunk-QOQYOOQ4.js} +1 -1
  64. package/dist/browser/prod/excalidraw-assets/{chunk-I2PZFXTK.js → chunk-ZTIWFPBM.js} +21 -21
  65. package/dist/browser/prod/excalidraw-assets/{classDiagram-30eddba6-IEJXXCVX.js → classDiagram-30eddba6-BCUTAUMD.js} +1 -1
  66. package/dist/browser/prod/excalidraw-assets/{classDiagram-v2-f2df5561-7LZDSWOS.js → classDiagram-v2-f2df5561-6SOXSGQ2.js} +1 -1
  67. package/dist/browser/prod/excalidraw-assets/dist-567JAXHK.js +7 -0
  68. package/dist/browser/prod/excalidraw-assets/en-6E7MYLWO.js +1 -0
  69. package/dist/browser/prod/excalidraw-assets/{erDiagram-47591fe2-E5V666CF.js → erDiagram-47591fe2-RE6HB7RM.js} +1 -1
  70. package/dist/browser/prod/excalidraw-assets/{flowDiagram-5540d9b9-GMBRCYVF.js → flowDiagram-5540d9b9-ZNJZBERW.js} +1 -1
  71. package/dist/browser/prod/excalidraw-assets/{flowDiagram-v2-3b53844e-Z4HUWP6B.js → flowDiagram-v2-3b53844e-LY44JLQJ.js} +1 -1
  72. package/dist/browser/prod/excalidraw-assets/{flowchart-elk-definition-5fe447d6-5ZCYTX5N.js → flowchart-elk-definition-5fe447d6-TMTJ6Z7O.js} +1 -1
  73. package/dist/browser/prod/excalidraw-assets/{ganttDiagram-9a3bba1f-WM32OMT5.js → ganttDiagram-9a3bba1f-5O6EA6LX.js} +1 -1
  74. package/dist/browser/prod/excalidraw-assets/{gitGraphDiagram-96e6b4ee-CAKZ2U6E.js → gitGraphDiagram-96e6b4ee-UHYNM5DI.js} +1 -1
  75. package/dist/browser/prod/excalidraw-assets/image-LQAMCFQI.js +1 -0
  76. package/dist/browser/prod/excalidraw-assets/{infoDiagram-bcd20f53-MUIKXGC4.js → infoDiagram-bcd20f53-BP77NQEH.js} +1 -1
  77. package/dist/browser/prod/excalidraw-assets/{journeyDiagram-4fe6b3dc-NYRV4HK2.js → journeyDiagram-4fe6b3dc-XMGKCMES.js} +1 -1
  78. package/dist/browser/prod/excalidraw-assets/{mindmap-definition-f354de21-MY55DRSM.js → mindmap-definition-f354de21-ZQRRBRWF.js} +1 -1
  79. package/dist/browser/prod/excalidraw-assets/{pieDiagram-79897490-47L6J6L2.js → pieDiagram-79897490-IGXEC2KX.js} +1 -1
  80. package/dist/browser/prod/excalidraw-assets/{quadrantDiagram-62f64e94-DF5C2GDT.js → quadrantDiagram-62f64e94-WTHHDYJL.js} +1 -1
  81. package/dist/browser/prod/excalidraw-assets/{requirementDiagram-05bf5f74-C4IMUBDN.js → requirementDiagram-05bf5f74-MV4OFRVW.js} +1 -1
  82. package/dist/browser/prod/excalidraw-assets/{sankeyDiagram-97764748-YHW7EUST.js → sankeyDiagram-97764748-ZGYUHEJT.js} +1 -1
  83. package/dist/browser/prod/excalidraw-assets/{sequenceDiagram-acc0e65c-H3XEHT32.js → sequenceDiagram-acc0e65c-IBSENK6W.js} +1 -1
  84. package/dist/browser/prod/excalidraw-assets/{stateDiagram-0ff1cf1a-Z5WB6Q3P.js → stateDiagram-0ff1cf1a-DB73XNZH.js} +1 -1
  85. package/dist/browser/prod/excalidraw-assets/{stateDiagram-v2-9a9d610d-T7OZETQC.js → stateDiagram-v2-9a9d610d-2OOBUPNR.js} +1 -1
  86. package/dist/browser/prod/excalidraw-assets/{timeline-definition-fea2a41d-VVC22BWF.js → timeline-definition-fea2a41d-P3NQQVDU.js} +1 -1
  87. package/dist/browser/prod/excalidraw-assets/{xychartDiagram-ab372869-JAXODQF7.js → xychartDiagram-ab372869-HI3XLK3Y.js} +1 -1
  88. package/dist/browser/prod/index.css +1 -1
  89. package/dist/browser/prod/index.js +69 -51
  90. package/dist/{prod/en-XW4JO6VX.json → dev/en-EB2MBPAV.json} +24 -3
  91. package/dist/dev/index.css +199 -77
  92. package/dist/dev/index.css.map +3 -3
  93. package/dist/dev/index.js +15120 -11334
  94. package/dist/dev/index.js.map +4 -4
  95. package/dist/excalidraw/actions/actionAddToLibrary.d.ts +16 -7
  96. package/dist/excalidraw/actions/actionAddToLibrary.js +4 -3
  97. package/dist/excalidraw/actions/actionAlign.d.ts +22 -22
  98. package/dist/excalidraw/actions/actionAlign.js +7 -6
  99. package/dist/excalidraw/actions/actionBoundText.d.ts +18 -12
  100. package/dist/excalidraw/actions/actionBoundText.js +7 -4
  101. package/dist/excalidraw/actions/actionCanvas.d.ts +100 -64
  102. package/dist/excalidraw/actions/actionCanvas.js +17 -14
  103. package/dist/excalidraw/actions/actionClipboard.d.ts +52 -31
  104. package/dist/excalidraw/actions/actionClipboard.js +14 -13
  105. package/dist/excalidraw/actions/actionDeleteSelected.d.ts +22 -13
  106. package/dist/excalidraw/actions/actionDeleteSelected.js +6 -3
  107. package/dist/excalidraw/actions/actionDistribute.d.ts +10 -10
  108. package/dist/excalidraw/actions/actionDistribute.js +3 -2
  109. package/dist/excalidraw/actions/actionDuplicateSelection.d.ts +7 -8
  110. package/dist/excalidraw/actions/actionDuplicateSelection.js +4 -4
  111. package/dist/excalidraw/actions/actionElementLock.d.ts +17 -11
  112. package/dist/excalidraw/actions/actionElementLock.js +3 -2
  113. package/dist/excalidraw/actions/actionExport.d.ts +68 -41
  114. package/dist/excalidraw/actions/actionExport.js +15 -11
  115. package/dist/excalidraw/actions/actionFinalize.d.ts +17 -11
  116. package/dist/excalidraw/actions/actionFinalize.js +7 -3
  117. package/dist/excalidraw/actions/actionFlip.d.ts +10 -10
  118. package/dist/excalidraw/actions/actionFlip.js +9 -9
  119. package/dist/excalidraw/actions/actionFrame.d.ts +186 -21
  120. package/dist/excalidraw/actions/actionFrame.js +7 -6
  121. package/dist/excalidraw/actions/actionGroup.d.ts +24 -18
  122. package/dist/excalidraw/actions/actionGroup.js +7 -11
  123. package/dist/excalidraw/actions/actionHistory.d.ts +4 -3
  124. package/dist/excalidraw/actions/actionHistory.js +27 -31
  125. package/dist/excalidraw/actions/actionLinearEditor.d.ts +10 -5
  126. package/dist/excalidraw/actions/actionLinearEditor.js +21 -5
  127. package/dist/excalidraw/actions/actionLink.d.ts +9 -6
  128. package/dist/excalidraw/actions/actionLink.js +2 -1
  129. package/dist/excalidraw/actions/actionMenu.d.ts +20 -11
  130. package/dist/excalidraw/actions/actionMenu.js +4 -3
  131. package/dist/excalidraw/actions/actionNavigate.d.ts +12 -6
  132. package/dist/excalidraw/actions/actionNavigate.js +3 -2
  133. package/dist/excalidraw/actions/actionProperties.d.ts +86 -47
  134. package/dist/excalidraw/actions/actionProperties.js +19 -14
  135. package/dist/excalidraw/actions/actionSelectAll.d.ts +9 -6
  136. package/dist/excalidraw/actions/actionSelectAll.js +2 -1
  137. package/dist/excalidraw/actions/actionStyles.d.ts +15 -12
  138. package/dist/excalidraw/actions/actionStyles.js +4 -3
  139. package/dist/excalidraw/actions/actionTextAutoResize.d.ts +17 -0
  140. package/dist/excalidraw/actions/actionTextAutoResize.js +38 -0
  141. package/dist/excalidraw/actions/actionToggleGridMode.d.ts +9 -6
  142. package/dist/excalidraw/actions/actionToggleGridMode.js +2 -1
  143. package/dist/excalidraw/actions/actionToggleObjectsSnapMode.d.ts +8 -5
  144. package/dist/excalidraw/actions/actionToggleObjectsSnapMode.js +2 -1
  145. package/dist/excalidraw/actions/actionToggleStats.d.ts +9 -5
  146. package/dist/excalidraw/actions/actionToggleStats.js +6 -4
  147. package/dist/excalidraw/actions/actionToggleViewMode.d.ts +8 -5
  148. package/dist/excalidraw/actions/actionToggleViewMode.js +2 -1
  149. package/dist/excalidraw/actions/actionToggleZenMode.d.ts +8 -5
  150. package/dist/excalidraw/actions/actionToggleZenMode.js +2 -1
  151. package/dist/excalidraw/actions/actionZindex.d.ts +20 -16
  152. package/dist/excalidraw/actions/actionZindex.js +9 -4
  153. package/dist/excalidraw/actions/manager.d.ts +5 -5
  154. package/dist/excalidraw/actions/register.d.ts +1 -1
  155. package/dist/excalidraw/actions/shortcuts.d.ts +2 -2
  156. package/dist/excalidraw/actions/types.d.ts +8 -8
  157. package/dist/excalidraw/align.d.ts +1 -1
  158. package/dist/excalidraw/animated-trail.d.ts +2 -2
  159. package/dist/excalidraw/appState.d.ts +9 -6
  160. package/dist/excalidraw/appState.js +6 -3
  161. package/dist/excalidraw/change.d.ts +191 -0
  162. package/dist/excalidraw/change.js +901 -0
  163. package/dist/excalidraw/charts.d.ts +1 -1
  164. package/dist/excalidraw/clients.d.ts +2 -2
  165. package/dist/excalidraw/clients.js +1 -1
  166. package/dist/excalidraw/clipboard.d.ts +3 -3
  167. package/dist/excalidraw/colors.d.ts +1 -1
  168. package/dist/excalidraw/components/Actions.d.ts +3 -3
  169. package/dist/excalidraw/components/Actions.js +9 -6
  170. package/dist/excalidraw/components/App.d.ts +19 -20
  171. package/dist/excalidraw/components/App.js +323 -195
  172. package/dist/excalidraw/components/ButtonIconSelect.js +1 -1
  173. package/dist/excalidraw/components/CheckboxItem.js +1 -1
  174. package/dist/excalidraw/components/ColorPicker/ColorInput.d.ts +1 -1
  175. package/dist/excalidraw/components/ColorPicker/ColorInput.js +1 -1
  176. package/dist/excalidraw/components/ColorPicker/ColorPicker.d.ts +4 -4
  177. package/dist/excalidraw/components/ColorPicker/ColorPicker.js +1 -1
  178. package/dist/excalidraw/components/ColorPicker/Picker.d.ts +3 -3
  179. package/dist/excalidraw/components/ColorPicker/PickerColorList.d.ts +1 -1
  180. package/dist/excalidraw/components/ColorPicker/PickerHeading.d.ts +1 -1
  181. package/dist/excalidraw/components/ColorPicker/ShadeList.d.ts +1 -1
  182. package/dist/excalidraw/components/ColorPicker/TopPicks.d.ts +1 -1
  183. package/dist/excalidraw/components/ColorPicker/colorPickerUtils.d.ts +2 -2
  184. package/dist/excalidraw/components/ColorPicker/colorPickerUtils.js +1 -1
  185. package/dist/excalidraw/components/ColorPicker/keyboardNavHandlers.d.ts +2 -2
  186. package/dist/excalidraw/components/ColorPicker/keyboardNavHandlers.js +1 -1
  187. package/dist/excalidraw/components/CommandPalette/CommandPalette.d.ts +1 -1
  188. package/dist/excalidraw/components/CommandPalette/CommandPalette.js +5 -5
  189. package/dist/excalidraw/components/CommandPalette/defaultCommandPaletteItems.d.ts +1 -1
  190. package/dist/excalidraw/components/CommandPalette/types.d.ts +3 -3
  191. package/dist/excalidraw/components/ConfirmDialog.d.ts +1 -1
  192. package/dist/excalidraw/components/ContextMenu.d.ts +2 -2
  193. package/dist/excalidraw/components/ContextMenu.js +2 -2
  194. package/dist/excalidraw/components/DarkModeToggle.d.ts +1 -1
  195. package/dist/excalidraw/components/DefaultSidebar.d.ts +2 -2
  196. package/dist/excalidraw/components/Dialog.js +1 -1
  197. package/dist/excalidraw/components/DialogActionButton.d.ts +1 -1
  198. package/dist/excalidraw/components/EyeDropper.d.ts +2 -2
  199. package/dist/excalidraw/components/FollowMode/FollowMode.d.ts +1 -1
  200. package/dist/excalidraw/components/FollowMode/FollowMode.js +1 -1
  201. package/dist/excalidraw/components/HelpDialog.js +1 -1
  202. package/dist/excalidraw/components/HintViewer.d.ts +1 -1
  203. package/dist/excalidraw/components/IconPicker.js +2 -2
  204. package/dist/excalidraw/components/ImageExportDialog.d.ts +1 -1
  205. package/dist/excalidraw/components/InitializeApp.d.ts +2 -2
  206. package/dist/excalidraw/components/JSONExportDialog.d.ts +3 -3
  207. package/dist/excalidraw/components/LayerUI.d.ts +4 -4
  208. package/dist/excalidraw/components/LayerUI.js +10 -7
  209. package/dist/excalidraw/components/LibraryMenu.d.ts +2 -2
  210. package/dist/excalidraw/components/LibraryMenuBrowseButton.d.ts +1 -1
  211. package/dist/excalidraw/components/LibraryMenuControlButtons.d.ts +1 -1
  212. package/dist/excalidraw/components/LibraryMenuHeaderContent.d.ts +2 -2
  213. package/dist/excalidraw/components/LibraryMenuItems.d.ts +1 -1
  214. package/dist/excalidraw/components/LibraryMenuSection.d.ts +5 -4
  215. package/dist/excalidraw/components/LibraryUnit.d.ts +2 -2
  216. package/dist/excalidraw/components/LoadingMessage.d.ts +1 -1
  217. package/dist/excalidraw/components/MagicSettings.js +2 -2
  218. package/dist/excalidraw/components/MobileMenu.d.ts +3 -3
  219. package/dist/excalidraw/components/MobileMenu.js +2 -6
  220. package/dist/excalidraw/components/Modal.d.ts +1 -1
  221. package/dist/excalidraw/components/OverwriteConfirm/OverwriteConfirmState.d.ts +1 -1
  222. package/dist/excalidraw/components/PasteChartDialog.d.ts +1 -1
  223. package/dist/excalidraw/components/PasteChartDialog.js +1 -1
  224. package/dist/excalidraw/components/PublishLibrary.d.ts +1 -1
  225. package/dist/excalidraw/components/SVGLayer.d.ts +1 -1
  226. package/dist/excalidraw/components/Sidebar/Sidebar.d.ts +2 -2
  227. package/dist/excalidraw/components/Sidebar/Sidebar.js +1 -1
  228. package/dist/excalidraw/components/Sidebar/SidebarTab.d.ts +1 -1
  229. package/dist/excalidraw/components/Sidebar/SidebarTabTrigger.d.ts +1 -1
  230. package/dist/excalidraw/components/Sidebar/SidebarTrigger.d.ts +1 -1
  231. package/dist/excalidraw/components/Sidebar/common.d.ts +1 -1
  232. package/dist/excalidraw/components/Stack.d.ts +2 -2
  233. package/dist/excalidraw/components/Stats/Angle.d.ts +12 -0
  234. package/dist/excalidraw/components/Stats/Angle.js +52 -0
  235. package/dist/excalidraw/components/Stats/Collapsible.d.ts +9 -0
  236. package/dist/excalidraw/components/Stats/Collapsible.js +12 -0
  237. package/dist/excalidraw/components/Stats/Dimension.d.ts +12 -0
  238. package/dist/excalidraw/components/Stats/Dimension.js +67 -0
  239. package/dist/excalidraw/components/Stats/DragInput.d.ts +32 -0
  240. package/dist/excalidraw/components/Stats/DragInput.js +174 -0
  241. package/dist/excalidraw/components/Stats/FontSize.d.ts +12 -0
  242. package/dist/excalidraw/components/Stats/FontSize.js +50 -0
  243. package/dist/excalidraw/components/Stats/MultiAngle.d.ts +12 -0
  244. package/dist/excalidraw/components/Stats/MultiAngle.js +66 -0
  245. package/dist/excalidraw/components/Stats/MultiDimension.d.ts +15 -0
  246. package/dist/excalidraw/components/Stats/MultiDimension.js +197 -0
  247. package/dist/excalidraw/components/Stats/MultiFontSize.d.ts +13 -0
  248. package/dist/excalidraw/components/Stats/MultiFontSize.js +72 -0
  249. package/dist/excalidraw/components/Stats/MultiPosition.d.ts +15 -0
  250. package/dist/excalidraw/components/Stats/MultiPosition.js +100 -0
  251. package/dist/excalidraw/components/Stats/Position.d.ts +13 -0
  252. package/dist/excalidraw/components/Stats/Position.js +39 -0
  253. package/dist/excalidraw/components/Stats/index.d.ts +16 -0
  254. package/dist/excalidraw/components/Stats/index.js +78 -0
  255. package/dist/excalidraw/components/Stats/utils.d.ts +25 -0
  256. package/dist/excalidraw/components/Stats/utils.js +158 -0
  257. package/dist/excalidraw/components/TTDDialog/MermaidToExcalidraw.d.ts +1 -1
  258. package/dist/excalidraw/components/TTDDialog/TTDDialog.js +2 -2
  259. package/dist/excalidraw/components/TTDDialog/TTDDialogInput.d.ts +1 -1
  260. package/dist/excalidraw/components/TTDDialog/TTDDialogPanel.d.ts +1 -1
  261. package/dist/excalidraw/components/TTDDialog/TTDDialogPanels.d.ts +1 -1
  262. package/dist/excalidraw/components/TTDDialog/TTDDialogTabs.d.ts +1 -1
  263. package/dist/excalidraw/components/TTDDialog/TTDDialogTrigger.d.ts +1 -1
  264. package/dist/excalidraw/components/TTDDialog/common.d.ts +4 -4
  265. package/dist/excalidraw/components/TextField.d.ts +1 -1
  266. package/dist/excalidraw/components/Toast.d.ts +1 -1
  267. package/dist/excalidraw/components/ToolButton.d.ts +4 -2
  268. package/dist/excalidraw/components/ToolButton.js +1 -1
  269. package/dist/excalidraw/components/Trans.d.ts +1 -1
  270. package/dist/excalidraw/components/UserList.d.ts +1 -1
  271. package/dist/excalidraw/components/canvases/InteractiveCanvas.d.ts +5 -3
  272. package/dist/excalidraw/components/canvases/InteractiveCanvas.js +5 -2
  273. package/dist/excalidraw/components/canvases/StaticCanvas.d.ts +2 -2
  274. package/dist/excalidraw/components/canvases/StaticCanvas.js +2 -2
  275. package/dist/excalidraw/components/dropdownMenu/DropdownMenuItem.js +2 -2
  276. package/dist/excalidraw/components/footer/Footer.d.ts +2 -2
  277. package/dist/excalidraw/components/hyperlink/Hyperlink.d.ts +2 -2
  278. package/dist/excalidraw/components/hyperlink/helpers.d.ts +3 -3
  279. package/dist/excalidraw/components/icons.d.ts +6 -2
  280. package/dist/excalidraw/components/icons.js +22 -6
  281. package/dist/excalidraw/constants.d.ts +11 -2
  282. package/dist/excalidraw/constants.js +14 -1
  283. package/dist/excalidraw/context/ui-appState.d.ts +1 -1
  284. package/dist/excalidraw/cursor.d.ts +1 -1
  285. package/dist/excalidraw/data/EditorLocalStorage.d.ts +2 -2
  286. package/dist/excalidraw/data/blob.d.ts +5 -5
  287. package/dist/excalidraw/data/filesystem.d.ts +2 -1
  288. package/dist/excalidraw/data/index.d.ts +4 -4
  289. package/dist/excalidraw/data/json.d.ts +3 -3
  290. package/dist/excalidraw/data/library.d.ts +3 -3
  291. package/dist/excalidraw/data/magic.d.ts +3 -3
  292. package/dist/excalidraw/data/reconcile.d.ts +3 -3
  293. package/dist/excalidraw/data/reconcile.js +1 -1
  294. package/dist/excalidraw/data/resave.d.ts +2 -2
  295. package/dist/excalidraw/data/restore.d.ts +3 -3
  296. package/dist/excalidraw/data/restore.js +17 -2
  297. package/dist/excalidraw/data/transform.d.ts +3 -3
  298. package/dist/excalidraw/data/types.d.ts +3 -3
  299. package/dist/excalidraw/element/ElementCanvasButtons.d.ts +1 -1
  300. package/dist/excalidraw/element/binding.d.ts +48 -20
  301. package/dist/excalidraw/element/binding.js +354 -168
  302. package/dist/excalidraw/element/bounds.d.ts +3 -3
  303. package/dist/excalidraw/element/collision.d.ts +3 -3
  304. package/dist/excalidraw/element/collision.js +1 -1
  305. package/dist/excalidraw/element/containerCache.d.ts +1 -1
  306. package/dist/excalidraw/element/dragElements.d.ts +4 -4
  307. package/dist/excalidraw/element/dragElements.js +27 -3
  308. package/dist/excalidraw/element/embeddable.d.ts +10 -7
  309. package/dist/excalidraw/element/embeddable.js +2 -1
  310. package/dist/excalidraw/element/image.d.ts +2 -2
  311. package/dist/excalidraw/element/index.d.ts +2 -2
  312. package/dist/excalidraw/element/index.js +1 -1
  313. package/dist/excalidraw/element/linearElementEditor.d.ts +10 -7
  314. package/dist/excalidraw/element/linearElementEditor.js +9 -6
  315. package/dist/excalidraw/element/mutateElement.d.ts +3 -4
  316. package/dist/excalidraw/element/mutateElement.js +1 -1
  317. package/dist/excalidraw/element/newElement.d.ts +5 -8
  318. package/dist/excalidraw/element/newElement.js +16 -14
  319. package/dist/excalidraw/element/resizeElements.d.ts +12 -4
  320. package/dist/excalidraw/element/resizeElements.js +174 -98
  321. package/dist/excalidraw/element/resizeTest.d.ts +7 -7
  322. package/dist/excalidraw/element/resizeTest.js +53 -8
  323. package/dist/excalidraw/element/showSelectedShapeActions.d.ts +2 -2
  324. package/dist/excalidraw/element/sizeHelpers.d.ts +2 -2
  325. package/dist/excalidraw/element/sizeHelpers.js +3 -0
  326. package/dist/excalidraw/element/sortElements.d.ts +1 -1
  327. package/dist/excalidraw/element/textElement.d.ts +6 -5
  328. package/dist/excalidraw/element/textElement.js +16 -7
  329. package/dist/excalidraw/element/textWysiwyg.d.ts +12 -6
  330. package/dist/excalidraw/element/textWysiwyg.js +38 -17
  331. package/dist/excalidraw/element/transformHandles.d.ts +24 -6
  332. package/dist/excalidraw/element/transformHandles.js +22 -11
  333. package/dist/excalidraw/element/typeChecks.d.ts +5 -5
  334. package/dist/excalidraw/element/types.d.ts +16 -8
  335. package/dist/excalidraw/emitter.d.ts +1 -1
  336. package/dist/excalidraw/fractionalIndex.d.ts +1 -1
  337. package/dist/excalidraw/fractionalIndex.js +2 -4
  338. package/dist/excalidraw/frame.d.ts +3 -3
  339. package/dist/excalidraw/gatransforms.d.ts +1 -1
  340. package/dist/excalidraw/gesture.d.ts +1 -1
  341. package/dist/excalidraw/groups.d.ts +6 -4
  342. package/dist/excalidraw/groups.js +17 -0
  343. package/dist/excalidraw/history.d.ts +35 -47
  344. package/dist/excalidraw/history.js +100 -167
  345. package/dist/excalidraw/hooks/useEmitter.d.ts +2 -0
  346. package/dist/excalidraw/hooks/useEmitter.js +13 -0
  347. package/dist/excalidraw/hooks/useLibraryItemSvg.d.ts +1 -1
  348. package/dist/excalidraw/i18n.d.ts +1 -1
  349. package/dist/excalidraw/index.d.ts +3 -1
  350. package/dist/excalidraw/index.js +2 -0
  351. package/dist/excalidraw/jotai.d.ts +1 -1
  352. package/dist/excalidraw/laser-trails.d.ts +3 -2
  353. package/dist/excalidraw/locales/en.json +24 -3
  354. package/dist/excalidraw/math.d.ts +4 -2
  355. package/dist/excalidraw/math.js +6 -0
  356. package/dist/excalidraw/mermaid.d.ts +2 -0
  357. package/dist/excalidraw/mermaid.js +28 -0
  358. package/dist/excalidraw/points.d.ts +1 -1
  359. package/dist/excalidraw/queue.d.ts +1 -1
  360. package/dist/excalidraw/renderer/helpers.d.ts +2 -2
  361. package/dist/excalidraw/renderer/interactiveScene.d.ts +2 -2
  362. package/dist/excalidraw/renderer/interactiveScene.js +38 -11
  363. package/dist/excalidraw/renderer/renderElement.d.ts +4 -4
  364. package/dist/excalidraw/renderer/renderElement.js +5 -5
  365. package/dist/excalidraw/renderer/renderSnaps.d.ts +1 -1
  366. package/dist/excalidraw/renderer/staticScene.d.ts +1 -1
  367. package/dist/excalidraw/renderer/staticScene.js +1 -1
  368. package/dist/excalidraw/renderer/staticSvgScene.d.ts +4 -4
  369. package/dist/excalidraw/scene/Fonts.d.ts +2 -4
  370. package/dist/excalidraw/scene/Fonts.js +12 -15
  371. package/dist/excalidraw/scene/Renderer.d.ts +4 -4
  372. package/dist/excalidraw/scene/Renderer.js +2 -3
  373. package/dist/excalidraw/scene/Scene.d.ts +17 -8
  374. package/dist/excalidraw/scene/Scene.js +19 -10
  375. package/dist/excalidraw/scene/Shape.d.ts +1 -1
  376. package/dist/excalidraw/scene/ShapeCache.d.ts +4 -4
  377. package/dist/excalidraw/scene/comparisons.d.ts +2 -2
  378. package/dist/excalidraw/scene/export.d.ts +2 -2
  379. package/dist/excalidraw/scene/export.js +2 -2
  380. package/dist/excalidraw/scene/scroll.d.ts +2 -2
  381. package/dist/excalidraw/scene/scrollbars.d.ts +3 -3
  382. package/dist/excalidraw/scene/selection.d.ts +2 -2
  383. package/dist/excalidraw/scene/types.d.ts +7 -8
  384. package/dist/excalidraw/scene/zoom.d.ts +1 -1
  385. package/dist/excalidraw/shapes.d.ts +7 -0
  386. package/dist/excalidraw/shapes.js +40 -0
  387. package/dist/excalidraw/snapping.d.ts +4 -4
  388. package/dist/excalidraw/snapping.js +2 -1
  389. package/dist/excalidraw/store.d.ts +129 -0
  390. package/dist/excalidraw/store.js +296 -0
  391. package/dist/excalidraw/types.d.ts +38 -20
  392. package/dist/excalidraw/utils.d.ts +10 -4
  393. package/dist/excalidraw/utils.js +7 -0
  394. package/dist/excalidraw/zindex.d.ts +2 -2
  395. package/dist/{dev/en-XW4JO6VX.json → prod/en-EB2MBPAV.json} +24 -3
  396. package/dist/prod/index.css +1 -1
  397. package/dist/prod/index.js +39 -39
  398. package/dist/utils/bbox.d.ts +2 -2
  399. package/dist/utils/collision.d.ts +1 -1
  400. package/dist/utils/export.d.ts +2 -2
  401. package/dist/utils/geometry/geometry.d.ts +1 -1
  402. package/dist/utils/geometry/shape.d.ts +2 -1
  403. package/dist/utils/geometry/shape.js +19 -0
  404. package/dist/utils/withinBounds.d.ts +1 -1
  405. package/history.ts +163 -218
  406. package/package.json +2 -2
  407. package/dist/browser/dev/excalidraw-assets-dev/chunk-WQFMSDPT.js.map +0 -7
  408. package/dist/browser/dev/excalidraw-assets-dev/chunk-XOM7LNOU.js.map +0 -7
  409. package/dist/browser/dev/excalidraw-assets-dev/chunk-Z3PH3V2B.js.map +0 -7
  410. package/dist/browser/dev/excalidraw-assets-dev/dist-Z46EOVOL.js.map +0 -7
  411. package/dist/browser/dev/excalidraw-assets-dev/image-OFRRV5MB.css.map +0 -7
  412. package/dist/browser/prod/excalidraw-assets/chunk-U3COIHDW.js +0 -55
  413. package/dist/browser/prod/excalidraw-assets/dist-PIPZXALV.js +0 -6
  414. package/dist/browser/prod/excalidraw-assets/en-7GPZE2Y2.js +0 -1
  415. package/dist/browser/prod/excalidraw-assets/image-ZLNYKWVQ.js +0 -1
  416. package/dist/excalidraw/components/Stats.d.ts +0 -11
  417. package/dist/excalidraw/components/Stats.js +0 -13
  418. /package/dist/browser/dev/excalidraw-assets-dev/{blockDiagram-91b80b7a-ACFH36JV.js.map → blockDiagram-91b80b7a-H47FTXHA.js.map} +0 -0
  419. /package/dist/browser/dev/excalidraw-assets-dev/{c4Diagram-b2a90758-QZ27YR47.js.map → c4Diagram-b2a90758-NNJK6GKC.js.map} +0 -0
  420. /package/dist/browser/dev/excalidraw-assets-dev/{chunk-HO2HMSK7.js.map → chunk-4KQVEBHW.js.map} +0 -0
  421. /package/dist/browser/dev/excalidraw-assets-dev/{chunk-USGV265L.js.map → chunk-53YI56GV.js.map} +0 -0
  422. /package/dist/browser/dev/excalidraw-assets-dev/{chunk-EDFX3S7X.js.map → chunk-A2WCJI4I.js.map} +0 -0
  423. /package/dist/browser/dev/excalidraw-assets-dev/{chunk-IX4V72YG.js.map → chunk-EFLPX7NE.js.map} +0 -0
  424. /package/dist/browser/dev/excalidraw-assets-dev/{chunk-MXVETLVM.js.map → chunk-JYIQCNWV.js.map} +0 -0
  425. /package/dist/browser/dev/excalidraw-assets-dev/{chunk-YZIOORVX.js.map → chunk-LVIQQW6F.js.map} +0 -0
  426. /package/dist/browser/dev/excalidraw-assets-dev/{chunk-6U7GQNJT.js.map → chunk-PXLO3FOU.js.map} +0 -0
  427. /package/dist/browser/dev/excalidraw-assets-dev/{chunk-7DACDEY3.js.map → chunk-TO2AW5PW.js.map} +0 -0
  428. /package/dist/browser/dev/excalidraw-assets-dev/{chunk-NJ77ZFNJ.js.map → chunk-VURILHLY.js.map} +0 -0
  429. /package/dist/browser/dev/excalidraw-assets-dev/{chunk-2T2GU7NF.js.map → chunk-ZAYGSUHF.js.map} +0 -0
  430. /package/dist/browser/dev/excalidraw-assets-dev/{classDiagram-30eddba6-QSLMH4JW.js.map → classDiagram-30eddba6-CUYIJICN.js.map} +0 -0
  431. /package/dist/browser/dev/excalidraw-assets-dev/{classDiagram-v2-f2df5561-DY4DYQ5P.js.map → classDiagram-v2-f2df5561-K6WW6K73.js.map} +0 -0
  432. /package/dist/browser/dev/excalidraw-assets-dev/{en-TR4QLF5E.js.map → en-AZFA5HJJ.js.map} +0 -0
  433. /package/dist/browser/dev/excalidraw-assets-dev/{erDiagram-47591fe2-SOOJRTCB.js.map → erDiagram-47591fe2-XGAD7EEP.js.map} +0 -0
  434. /package/dist/browser/dev/excalidraw-assets-dev/{flowDiagram-5540d9b9-AHGL4KPK.js.map → flowDiagram-5540d9b9-B6EOVNNO.js.map} +0 -0
  435. /package/dist/browser/dev/excalidraw-assets-dev/{flowDiagram-v2-3b53844e-56LDZZWY.js.map → flowDiagram-v2-3b53844e-NUG24FJH.js.map} +0 -0
  436. /package/dist/browser/dev/excalidraw-assets-dev/{flowchart-elk-definition-5fe447d6-27LUKRI6.js.map → flowchart-elk-definition-5fe447d6-25Y7PCBL.js.map} +0 -0
  437. /package/dist/browser/dev/excalidraw-assets-dev/{ganttDiagram-9a3bba1f-EHGYGNG6.js.map → ganttDiagram-9a3bba1f-GNL6ZDTC.js.map} +0 -0
  438. /package/dist/browser/dev/excalidraw-assets-dev/{gitGraphDiagram-96e6b4ee-AJQNBDW5.js.map → gitGraphDiagram-96e6b4ee-HNW52NVO.js.map} +0 -0
  439. /package/dist/browser/dev/excalidraw-assets-dev/{image-OIPMBJGR.js.map → image-5XCR4WHS.js.map} +0 -0
  440. /package/dist/browser/dev/excalidraw-assets-dev/{infoDiagram-bcd20f53-SWLLQVES.js.map → infoDiagram-bcd20f53-FWEUVFLT.js.map} +0 -0
  441. /package/dist/browser/dev/excalidraw-assets-dev/{journeyDiagram-4fe6b3dc-7UAVCWOZ.js.map → journeyDiagram-4fe6b3dc-RZIUI7UG.js.map} +0 -0
  442. /package/dist/browser/dev/excalidraw-assets-dev/{mindmap-definition-f354de21-SROW5KGM.js.map → mindmap-definition-f354de21-GBVN45GU.js.map} +0 -0
  443. /package/dist/browser/dev/excalidraw-assets-dev/{pieDiagram-79897490-QKCI6NCB.js.map → pieDiagram-79897490-ECENNII6.js.map} +0 -0
  444. /package/dist/browser/dev/excalidraw-assets-dev/{quadrantDiagram-62f64e94-LNYJZFC5.js.map → quadrantDiagram-62f64e94-ZMEOFVNL.js.map} +0 -0
  445. /package/dist/browser/dev/excalidraw-assets-dev/{requirementDiagram-05bf5f74-ZZD7ZHFA.js.map → requirementDiagram-05bf5f74-FHZSFHCR.js.map} +0 -0
  446. /package/dist/browser/dev/excalidraw-assets-dev/{sankeyDiagram-97764748-L75ZZ4UM.js.map → sankeyDiagram-97764748-VDKIKTA6.js.map} +0 -0
  447. /package/dist/browser/dev/excalidraw-assets-dev/{sequenceDiagram-acc0e65c-6PCU7TDK.js.map → sequenceDiagram-acc0e65c-6JUSPVKX.js.map} +0 -0
  448. /package/dist/browser/dev/excalidraw-assets-dev/{stateDiagram-0ff1cf1a-WM76WOPR.js.map → stateDiagram-0ff1cf1a-L3AKWENF.js.map} +0 -0
  449. /package/dist/browser/dev/excalidraw-assets-dev/{stateDiagram-v2-9a9d610d-N4HZW3O2.js.map → stateDiagram-v2-9a9d610d-NU3GGMCH.js.map} +0 -0
  450. /package/dist/browser/dev/excalidraw-assets-dev/{timeline-definition-fea2a41d-ZHGCAXGP.js.map → timeline-definition-fea2a41d-JGP7XCHW.js.map} +0 -0
  451. /package/dist/browser/dev/excalidraw-assets-dev/{xychartDiagram-ab372869-2DLOVRAZ.js.map → xychartDiagram-ab372869-HLFHHF2I.js.map} +0 -0
@@ -10,20 +10,21 @@ 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, } from "../clipboard";
14
- 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, } from "../constants";
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, isInvisiblySmallElement, isNonDeletedElement, isTextElement, newElement, newLinearElement, newTextElement, newImageElement, transformElements, updateTextElement, redrawTextBoundingBox, getElementAbsoluteCoords, } from "../element";
19
- import { bindOrUnbindLinearElement, bindOrUnbindSelectedElements, fixBindingsAfterDeletion, fixBindingsAfterDuplication, getEligibleElementsForBinding, getHoveredElementForBinding, isBindingEnabled, isLinearElementSimpleAndAlreadyBound, maybeBindLinearElement, shouldEnableBindingForPointerEvent, unbindLinearElements, updateBoundElements, } from "../element/binding";
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
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";
@@ -31,12 +32,12 @@ import { distance2d, getCornerRadius, getGridPoint, isPathALoop, } from "../math
31
32
  import { calculateScrollCenter, getElementsWithinSelection, getNormalizedZoom, getSelectedElements, hasBackground, isSomeElementSelected, } from "../scene";
32
33
  import Scene from "../scene/Scene";
33
34
  import { getStateForZoom } from "../scene/zoom";
34
- import { findShapeByKey } from "../shapes";
35
- import { getClosedCurveShape, getCurveShape, getEllipseShape, getFreedrawShape, getPolygonShape, } from "../../utils/geometry/shape";
35
+ import { findShapeByKey, getElementShape } from "../shapes";
36
+ import { getSelectionBoxShape } from "../../utils/geometry/shape";
36
37
  import { isPointInShape } from "../../utils/collision";
37
- import { debounce, distance, getFontString, getNearestScrollableContainer, isInputLike, isToolIcon, isWritableElement, sceneCoordsToViewportCoords, tupleToCoors, viewportCoordsToSceneCoords, wrapEvent, updateObject, updateActiveTool, getShortcutKey, isTransparent, easeToValuesRAF, muteFSAbortError, isTestEnv, easeOut, arrayToMap, updateStable, addEventListener, normalizeEOL, getDateTime, } from "../utils";
38
+ import { debounce, distance, getFontString, getNearestScrollableContainer, isInputLike, isToolIcon, isWritableElement, sceneCoordsToViewportCoords, tupleToCoors, viewportCoordsToSceneCoords, wrapEvent, updateObject, updateActiveTool, getShortcutKey, isTransparent, easeToValuesRAF, muteFSAbortError, isTestEnv, easeOut, updateStable, addEventListener, normalizeEOL, getDateTime, isShallowEqual, arrayToMap, } from "../utils";
38
39
  import { createSrcDoc, embeddableURLValidator, maybeParseEmbedSrc, getEmbedLink, } from "../element/embeddable";
39
- import { ContextMenu, CONTEXT_MENU_SEPARATOR, } from "./ContextMenu";
40
+ import { ContextMenu, CONTEXT_MENU_SEPARATOR } from "./ContextMenu";
40
41
  import LayerUI from "./LayerUI";
41
42
  import { Toast } from "./Toast";
42
43
  import { actionToggleViewMode } from "../actions/actionToggleViewMode";
@@ -44,7 +45,7 @@ import { dataURLToFile, generateIdFromFile, getDataURL, getFileFromEvent, ImageU
44
45
  import { getInitializedImageElements, loadHTMLImageElement, normalizeSVG, updateImageCache as _updateImageCache, } from "../element/image";
45
46
  import throttle from "lodash.throttle";
46
47
  import { fileOpen } from "../data/filesystem";
47
- import { bindTextToShapeAfterDuplication, getApproxMinLineHeight, getApproxMinLineWidth, getBoundTextElement, getContainerCenter, getContainerElement, getDefaultLineHeight, getLineHeightInPx, isMeasureTextSupported, isValidTextContainer, } from "../element/textElement";
48
+ import { bindTextToShapeAfterDuplication, getApproxMinLineHeight, getApproxMinLineWidth, getBoundTextElement, getContainerCenter, getContainerElement, getDefaultLineHeight, getLineHeightInPx, getMinTextElementWidth, isMeasureTextSupported, isValidTextContainer, measureText, wrapText, } from "../element/textElement";
48
49
  import { showHyperlinkTooltip, hideHyperlinkToolip, Hyperlink, } from "../components/hyperlink/Hyperlink";
49
50
  import { isLocalLink, normalizeLink, toValidURL } from "../data/url";
50
51
  import { shouldShowBoundingBox } from "../element/transformHandles";
@@ -62,7 +63,7 @@ import { getSnapLinesAtPointer, snapDraggedElements, isActiveToolNonLinearSnappa
62
63
  import { actionWrapTextInContainer } from "../actions/actionBoundText";
63
64
  import BraveMeasureTextError from "./BraveMeasureTextError";
64
65
  import { activeEyeDropperAtom } from "./EyeDropper";
65
- import { convertToExcalidrawElements, } from "../data/transform";
66
+ import { convertToExcalidrawElements } from "../data/transform";
66
67
  import { isSidebarDockedAtom } from "./Sidebar/Sidebar";
67
68
  import { StaticCanvas, InteractiveCanvas } from "./canvases";
68
69
  import { Renderer } from "../scene/Renderer";
@@ -78,17 +79,21 @@ import { ElementCanvasButton } from "./MagicButton";
78
79
  import { MagicIcon, copyIcon, fullscreenIcon } from "./icons";
79
80
  import { EditorLocalStorage } from "../data/EditorLocalStorage";
80
81
  import FollowMode from "./FollowMode/FollowMode";
82
+ import { Store, StoreAction } from "../store";
81
83
  import { AnimationFrameHandler } from "../animation-frame-handler";
82
84
  import { AnimatedTrail } from "../animated-trail";
83
85
  import { LaserTrails } from "../laser-trails";
84
86
  import { withBatchedUpdates, withBatchedUpdatesThrottled } from "../reactUtils";
85
87
  import { getRenderOpacity } from "../renderer/renderElement";
86
- import { hitElementBoundText, hitElementBoundingBox, hitElementBoundingBoxOnly, hitElementItself, shouldTestInside, } from "../element/collision";
88
+ import { hitElementBoundText, hitElementBoundingBoxOnly, hitElementItself, } from "../element/collision";
87
89
  import { textWysiwyg } from "../element/textWysiwyg";
88
90
  import { isOverScrollBars } from "../scene/scrollbars";
89
91
  import { syncInvalidIndices, syncMovedIndices } from "../fractionalIndex";
90
92
  import { isPointHittingLink, isPointHittingLinkIcon, } from "./hyperlink/helpers";
91
93
  import { getShortcutFromShortcutName } from "../actions/shortcuts";
94
+ import { actionTextAutoResize } from "../actions/actionTextAutoResize";
95
+ import { getVisibleSceneBounds } from "../element/bounds";
96
+ import { isMaybeMermaidDefinition } from "../mermaid";
92
97
  const AppContext = React.createContext(null);
93
98
  const AppPropsContext = React.createContext(null);
94
99
  const deviceContextInitialValue = {
@@ -168,6 +173,7 @@ class App extends React.Component {
168
173
  library;
169
174
  libraryItemsFromStorage;
170
175
  id;
176
+ store;
171
177
  history;
172
178
  excalidrawContainerValue;
173
179
  files = {};
@@ -239,6 +245,8 @@ class App extends React.Component {
239
245
  this.canvas = document.createElement("canvas");
240
246
  this.rc = rough.canvas(this.canvas);
241
247
  this.renderer = new Renderer(this.scene);
248
+ this.store = new Store();
249
+ this.history = new History();
242
250
  if (excalidrawAPI) {
243
251
  const api = {
244
252
  updateScene: this.updateScene,
@@ -282,14 +290,11 @@ class App extends React.Component {
282
290
  container: this.excalidrawContainerRef.current,
283
291
  id: this.id,
284
292
  };
285
- this.fonts = new Fonts({
286
- scene: this.scene,
287
- onSceneUpdated: this.onSceneUpdated,
288
- });
293
+ this.fonts = new Fonts({ scene: this.scene });
289
294
  this.history = new History();
290
295
  this.actionManager.registerAll(actions);
291
- this.actionManager.registerAction(createUndoAction(this.history));
292
- this.actionManager.registerAction(createRedoAction(this.history));
296
+ this.actionManager.registerAction(createUndoAction(this.history, this.store));
297
+ this.actionManager.registerAction(createRedoAction(this.history, this.store));
293
298
  }
294
299
  onWindowMessage(event) {
295
300
  if (event.origin !== "https://player.vimeo.com" &&
@@ -440,7 +445,7 @@ class App extends React.Component {
440
445
  return false;
441
446
  });
442
447
  if (updated) {
443
- this.scene.informMutation();
448
+ this.scene.triggerUpdate();
444
449
  }
445
450
  // GC
446
451
  this.iFrameRefs.forEach((ref, id) => {
@@ -799,9 +804,9 @@ class App extends React.Component {
799
804
  render() {
800
805
  const selectedElements = this.scene.getSelectedElements(this.state);
801
806
  const { renderTopRightUI, renderCustomStats } = this.props;
802
- const versionNonce = this.scene.getVersionNonce();
807
+ const sceneNonce = this.scene.getSceneNonce();
803
808
  const { elementsMap, visibleElements } = this.renderer.getRenderableElements({
804
- versionNonce,
809
+ sceneNonce,
805
810
  zoom: this.state.zoom,
806
811
  offsetLeft: this.state.offsetLeft,
807
812
  offsetTop: this.state.offsetTop,
@@ -870,14 +875,14 @@ class App extends React.Component {
870
875
  this.focusContainer();
871
876
  callback?.();
872
877
  });
873
- } })), _jsx(StaticCanvas, { canvas: this.canvas, rc: this.rc, elementsMap: elementsMap, allElementsMap: allElementsMap, visibleElements: visibleElements, versionNonce: versionNonce, selectionNonce: this.state.selectionElement?.versionNonce, scale: window.devicePixelRatio, appState: this.state, renderConfig: {
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: {
874
879
  imageCache: this.imageCache,
875
880
  isExporting: false,
876
881
  renderGrid: true,
877
882
  canvasBackgroundColor: this.state.viewBackgroundColor,
878
883
  embedsValidationStatus: this.embedsValidationStatus,
879
884
  elementsPendingErasure: this.elementsPendingErasure,
880
- } }), _jsx(InteractiveCanvas, { containerRef: this.excalidrawContainerRef, canvas: this.interactiveCanvas, elementsMap: elementsMap, visibleElements: visibleElements, selectedElements: selectedElements, versionNonce: versionNonce, selectionNonce: this.state.selectionElement?.versionNonce, scale: window.devicePixelRatio, appState: this.state, renderInteractiveSceneCallback: this.renderInteractiveSceneCallback, handleCanvasRef: this.handleInteractiveCanvasRef, onContextMenu: this.handleCanvasContextMenu, onPointerMove: this.handleCanvasPointerMove, onPointerUp: this.handleCanvasPointerUp, onPointerCancel: this.removePointer, onTouchMove: this.handleTouchMove, onPointerDown: this.handleCanvasPointerDown, onDoubleClick: this.handleCanvasDoubleClick }), this.state.userToFollow && (_jsx(FollowMode, { width: this.state.width, height: this.state.height, userToFollow: this.state.userToFollow, onDisconnect: this.maybeUnfollowRemoteUser })), this.renderFrameNames()] }), this.renderEmbeddables()] }) }) }) }) }) }) }) }));
885
+ } }), _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()] }) }) }) }) }) }) }) }));
881
886
  }
882
887
  focusContainer = () => {
883
888
  this.excalidrawContainerRef.current?.focus();
@@ -927,7 +932,7 @@ class App extends React.Component {
927
932
  mutateElement(frameElement, { customData: { generationData: data } }, false);
928
933
  }
929
934
  this.magicGenerations.set(frameElement.id, data);
930
- this.onSceneUpdated();
935
+ this.triggerRender();
931
936
  };
932
937
  getTextFromElements(elements) {
933
938
  const text = elements
@@ -1149,13 +1154,13 @@ class App extends React.Component {
1149
1154
  if (shouldUpdateStrokeColor) {
1150
1155
  this.syncActionResult({
1151
1156
  appState: { ...this.state, currentItemStrokeColor: color },
1152
- commitToHistory: true,
1157
+ storeAction: StoreAction.CAPTURE,
1153
1158
  });
1154
1159
  }
1155
1160
  else {
1156
1161
  this.syncActionResult({
1157
1162
  appState: { ...this.state, currentItemBackgroundColor: color },
1158
- commitToHistory: true,
1163
+ storeAction: StoreAction.CAPTURE,
1159
1164
  });
1160
1165
  }
1161
1166
  }
@@ -1169,6 +1174,7 @@ class App extends React.Component {
1169
1174
  }
1170
1175
  return el;
1171
1176
  }),
1177
+ storeAction: StoreAction.CAPTURE,
1172
1178
  });
1173
1179
  }
1174
1180
  },
@@ -1179,6 +1185,13 @@ class App extends React.Component {
1179
1185
  if (this.unmounted || actionResult === false) {
1180
1186
  return;
1181
1187
  }
1188
+ if (actionResult.storeAction === StoreAction.UPDATE) {
1189
+ this.store.shouldUpdateSnapshot();
1190
+ }
1191
+ else if (actionResult.storeAction === StoreAction.CAPTURE) {
1192
+ this.store.shouldCaptureIncrement();
1193
+ }
1194
+ let didUpdate = false;
1182
1195
  let editingElement = null;
1183
1196
  if (actionResult.elements) {
1184
1197
  actionResult.elements.forEach((element) => {
@@ -1189,9 +1202,7 @@ class App extends React.Component {
1189
1202
  }
1190
1203
  });
1191
1204
  this.scene.replaceAllElements(actionResult.elements);
1192
- if (actionResult.commitToHistory) {
1193
- this.history.resumeRecording();
1194
- }
1205
+ didUpdate = true;
1195
1206
  }
1196
1207
  if (actionResult.files) {
1197
1208
  this.files = actionResult.replaceFiles
@@ -1200,9 +1211,6 @@ class App extends React.Component {
1200
1211
  this.addNewImagesToImageCache();
1201
1212
  }
1202
1213
  if (actionResult.appState || editingElement || this.state.contextMenu) {
1203
- if (actionResult.commitToHistory) {
1204
- this.history.resumeRecording();
1205
- }
1206
1214
  let viewModeEnabled = actionResult?.appState?.viewModeEnabled || false;
1207
1215
  let zenModeEnabled = actionResult?.appState?.zenModeEnabled || false;
1208
1216
  let gridSize = actionResult?.appState?.gridSize || null;
@@ -1240,11 +1248,11 @@ class App extends React.Component {
1240
1248
  name,
1241
1249
  errorMessage,
1242
1250
  });
1243
- }, () => {
1244
- if (actionResult.syncHistory) {
1245
- this.history.setCurrentState(this.state, this.scene.getElementsIncludingDeleted());
1246
- }
1247
1251
  });
1252
+ didUpdate = true;
1253
+ }
1254
+ if (!didUpdate && actionResult.storeAction !== StoreAction.NONE) {
1255
+ this.scene.triggerUpdate();
1248
1256
  }
1249
1257
  });
1250
1258
  // Lifecycle
@@ -1261,6 +1269,9 @@ class App extends React.Component {
1261
1269
  resetHistory = () => {
1262
1270
  this.history.clear();
1263
1271
  };
1272
+ resetStore = () => {
1273
+ this.store.clear();
1274
+ };
1264
1275
  /**
1265
1276
  * Resets scene & history.
1266
1277
  * ! Do not use to clear scene user action !
@@ -1272,6 +1283,7 @@ class App extends React.Component {
1272
1283
  isLoading: opts?.resetLoadingState ? false : state.isLoading,
1273
1284
  theme: this.state.theme,
1274
1285
  }));
1286
+ this.resetStore();
1275
1287
  this.resetHistory();
1276
1288
  });
1277
1289
  initializeScene = async () => {
@@ -1293,7 +1305,12 @@ class App extends React.Component {
1293
1305
  }
1294
1306
  let initialData = null;
1295
1307
  try {
1296
- initialData = (await this.props.initialData) || null;
1308
+ if (typeof this.props.initialData === "function") {
1309
+ initialData = (await this.props.initialData()) || null;
1310
+ }
1311
+ else {
1312
+ initialData = (await this.props.initialData) || null;
1313
+ }
1297
1314
  if (initialData?.libraryItems) {
1298
1315
  this.library
1299
1316
  .updateLibrary({
@@ -1346,10 +1363,11 @@ class App extends React.Component {
1346
1363
  // text elements on canvas, and rerender them once done. This also
1347
1364
  // seems faster even in browsers that do fire the loadingdone event.
1348
1365
  this.fonts.loadFontsForElements(scene.elements);
1366
+ this.resetStore();
1349
1367
  this.resetHistory();
1350
1368
  this.syncActionResult({
1351
1369
  ...scene,
1352
- commitToHistory: true,
1370
+ storeAction: StoreAction.UPDATE,
1353
1371
  });
1354
1372
  };
1355
1373
  isMobileBreakpoint = (width, height) => {
@@ -1420,9 +1438,16 @@ class App extends React.Component {
1420
1438
  configurable: true,
1421
1439
  value: this.history,
1422
1440
  },
1441
+ store: {
1442
+ configurable: true,
1443
+ value: this.store,
1444
+ },
1423
1445
  });
1424
1446
  }
1425
- this.scene.addCallback(this.onSceneUpdated);
1447
+ this.store.onStoreIncrementEmitter.on((increment) => {
1448
+ this.history.record(increment.elementsChange, increment.appStateChange);
1449
+ });
1450
+ this.scene.onUpdate(this.triggerRender);
1426
1451
  this.addEventListeners();
1427
1452
  if (this.props.autoFocus && this.excalidrawContainerRef.current) {
1428
1453
  this.focusContainer();
@@ -1458,19 +1483,22 @@ class App extends React.Component {
1458
1483
  }
1459
1484
  }
1460
1485
  componentWillUnmount() {
1486
+ window.launchQueue?.setConsumer(() => { });
1461
1487
  this.renderer.destroy();
1488
+ this.scene.destroy();
1462
1489
  this.scene = new Scene();
1490
+ this.fonts = new Fonts({ scene: this.scene });
1463
1491
  this.renderer = new Renderer(this.scene);
1464
1492
  this.files = {};
1465
1493
  this.imageCache.clear();
1466
1494
  this.resizeObserver?.disconnect();
1467
1495
  this.unmounted = true;
1468
1496
  this.removeEventListeners();
1469
- this.scene.destroy();
1470
1497
  this.library.destroy();
1471
1498
  this.laserTrails.stop();
1472
1499
  this.eraserTrail.stop();
1473
1500
  this.onChangeEmitter.clear();
1501
+ this.store.onStoreIncrementEmitter.clear();
1474
1502
  ShapeCache.destroy();
1475
1503
  SnapCache.destroy();
1476
1504
  clearTimeout(touchTimeout);
@@ -1514,7 +1542,7 @@ class App extends React.Component {
1514
1542
  this.onRemoveEventListenersEmitter.once(addEventListener(document, EVENT.KEYDOWN, this.onKeyDown, false));
1515
1543
  }
1516
1544
  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
1517
- addEventListener(document, EVENT.COPY, this.onCopy), addEventListener(document, EVENT.KEYUP, this.onKeyUp, { passive: true }), addEventListener(document, EVENT.MOUSE_MOVE, this.updateCurrentCursorPosition),
1545
+ addEventListener(document, EVENT.COPY, this.onCopy), addEventListener(document, EVENT.KEYUP, this.onKeyUp, { passive: true }), addEventListener(document, EVENT.POINTER_MOVE, this.updateCurrentCursorPosition),
1518
1546
  // rerender text elements on font load to fix #637 && #1553
1519
1547
  addEventListener(document.fonts, "loadingdone", (event) => {
1520
1548
  const loadedFontFaces = event.fontfaces;
@@ -1523,6 +1551,9 @@ class App extends React.Component {
1523
1551
  // Safari-only desktop pinch zoom
1524
1552
  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, () => {
1525
1553
  this.maybeCleanupAfterMissingPointerUp(null);
1554
+ // browsers (chrome?) tend to free up memory a lot, which results
1555
+ // in canvas context being cleared. Thus re-render on focus.
1556
+ this.triggerRender(true);
1526
1557
  }));
1527
1558
  if (this.state.viewModeEnabled) {
1528
1559
  return;
@@ -1538,7 +1569,8 @@ class App extends React.Component {
1538
1569
  componentDidUpdate(prevProps, prevState) {
1539
1570
  this.updateEmbeddables();
1540
1571
  const elements = this.scene.getElementsIncludingDeleted();
1541
- const elementsMap = this.scene.getNonDeletedElementsMap();
1572
+ const elementsMap = this.scene.getElementsMapIncludingDeleted();
1573
+ const nonDeletedElementsMap = this.scene.getNonDeletedElementsMap();
1542
1574
  if (!this.state.showWelcomeScreen && !elements.length) {
1543
1575
  this.setState({ showWelcomeScreen: true });
1544
1576
  }
@@ -1614,7 +1646,7 @@ class App extends React.Component {
1614
1646
  this.excalidrawContainerRef.current?.classList.toggle("theme--dark", this.state.theme === THEME.DARK);
1615
1647
  if (this.state.editingLinearElement &&
1616
1648
  !this.state.selectedElementIds[this.state.editingLinearElement.elementId]) {
1617
- // defer so that the commitToHistory flag isn't reset via current update
1649
+ // defer so that the storeAction flag isn't reset via current update
1618
1650
  setTimeout(() => {
1619
1651
  // execute only if the condition still holds when the deferred callback
1620
1652
  // executes (it can be scheduled multiple times depending on how
@@ -1639,9 +1671,9 @@ class App extends React.Component {
1639
1671
  multiElement != null &&
1640
1672
  isBindingEnabled(this.state) &&
1641
1673
  isBindingElement(multiElement, false)) {
1642
- maybeBindLinearElement(multiElement, this.state, tupleToCoors(LinearElementEditor.getPointAtIndexGlobalCoordinates(multiElement, -1, elementsMap)), this);
1674
+ maybeBindLinearElement(multiElement, this.state, tupleToCoors(LinearElementEditor.getPointAtIndexGlobalCoordinates(multiElement, -1, nonDeletedElementsMap)), this.scene.getNonDeletedElementsMap());
1643
1675
  }
1644
- this.history.record(this.state, elements);
1676
+ this.store.commit(elementsMap, this.state);
1645
1677
  // Do not notify consumers if we're still loading the scene. Among other
1646
1678
  // potential issues, this fixes a case where the tab isn't focused during
1647
1679
  // init, which would trigger onChange with empty elements, which would then
@@ -1828,6 +1860,26 @@ class App extends React.Component {
1828
1860
  });
1829
1861
  }
1830
1862
  else if (data.text) {
1863
+ if (data.text && isMaybeMermaidDefinition(data.text)) {
1864
+ const api = await import("@excalidraw/mermaid-to-excalidraw");
1865
+ try {
1866
+ const { elements: skeletonElements, files } = await api.parseMermaidToExcalidraw(data.text, {
1867
+ fontSize: DEFAULT_FONT_SIZE,
1868
+ });
1869
+ const elements = convertToExcalidrawElements(skeletonElements, {
1870
+ regenerateIds: true,
1871
+ });
1872
+ this.addElementsFromPasteOrLibrary({
1873
+ elements,
1874
+ files,
1875
+ position: "cursor",
1876
+ });
1877
+ return;
1878
+ }
1879
+ catch (err) {
1880
+ console.warn(`parsing pasted text as mermaid definition failed: ${err.message}`);
1881
+ }
1882
+ }
1831
1883
  const nonEmptyLines = normalizeEOL(data.text)
1832
1884
  .split(/\n+/)
1833
1885
  .map((s) => s.trim())
@@ -1915,7 +1967,7 @@ class App extends React.Component {
1915
1967
  if (opts.files) {
1916
1968
  this.files = { ...this.files, ...opts.files };
1917
1969
  }
1918
- this.history.resumeRecording();
1970
+ this.store.shouldCaptureIncrement();
1919
1971
  const nextElementsToSelect = excludeElementsInFramesFromSelection(newElements);
1920
1972
  this.setState({
1921
1973
  ...this.state,
@@ -2032,27 +2084,46 @@ class App extends React.Component {
2032
2084
  text,
2033
2085
  fontSize: this.state.currentItemFontSize,
2034
2086
  fontFamily: this.state.currentItemFontFamily,
2035
- textAlign: this.state.currentItemTextAlign,
2087
+ textAlign: DEFAULT_TEXT_ALIGN,
2036
2088
  verticalAlign: DEFAULT_VERTICAL_ALIGN,
2037
2089
  locked: false,
2038
2090
  };
2091
+ const fontString = getFontString({
2092
+ fontSize: textElementProps.fontSize,
2093
+ fontFamily: textElementProps.fontFamily,
2094
+ });
2095
+ const lineHeight = getDefaultLineHeight(textElementProps.fontFamily);
2096
+ const [x1, , x2] = getVisibleSceneBounds(this.state);
2097
+ // long texts should not go beyond 800 pixels in width nor should it go below 200 px
2098
+ const maxTextWidth = Math.max(Math.min((x2 - x1) * 0.5, 800), 200);
2039
2099
  const LINE_GAP = 10;
2040
2100
  let currentY = y;
2041
2101
  const lines = isPlainPaste ? [text] : text.split("\n");
2042
2102
  const textElements = lines.reduce((acc, line, idx) => {
2043
- const text = line.trim();
2044
- const lineHeight = getDefaultLineHeight(textElementProps.fontFamily);
2045
- if (text.length) {
2103
+ const originalText = line.trim();
2104
+ if (originalText.length) {
2046
2105
  const topLayerFrame = this.getTopLayerFrameAtSceneCoords({
2047
2106
  x,
2048
2107
  y: currentY,
2049
2108
  });
2109
+ let metrics = measureText(originalText, fontString, lineHeight);
2110
+ const isTextWrapped = metrics.width > maxTextWidth;
2111
+ const text = isTextWrapped
2112
+ ? wrapText(originalText, fontString, maxTextWidth)
2113
+ : originalText;
2114
+ metrics = isTextWrapped
2115
+ ? measureText(text, fontString, lineHeight)
2116
+ : metrics;
2117
+ const startX = x - metrics.width / 2;
2118
+ const startY = currentY - metrics.height / 2;
2050
2119
  const element = newTextElement({
2051
2120
  ...textElementProps,
2052
- x,
2053
- y: currentY,
2121
+ x: startX,
2122
+ y: startY,
2054
2123
  text,
2124
+ originalText,
2055
2125
  lineHeight,
2126
+ autoResize: !isTextWrapped,
2056
2127
  frameId: topLayerFrame ? topLayerFrame.id : null,
2057
2128
  });
2058
2129
  acc.push(element);
@@ -2089,7 +2160,7 @@ class App extends React.Component {
2089
2160
  });
2090
2161
  PLAIN_PASTE_TOAST_SHOWN = true;
2091
2162
  }
2092
- this.history.resumeRecording();
2163
+ this.store.shouldCaptureIncrement();
2093
2164
  }
2094
2165
  setAppState = (state, callback) => {
2095
2166
  this.setState(state, callback);
@@ -2271,25 +2342,49 @@ class App extends React.Component {
2271
2342
  ShapeCache.delete(element);
2272
2343
  }
2273
2344
  });
2274
- this.scene.informMutation();
2345
+ this.scene.triggerUpdate();
2275
2346
  this.addNewImagesToImageCache();
2276
2347
  });
2277
2348
  updateScene = withBatchedUpdates((sceneData) => {
2278
- if (sceneData.commitToHistory) {
2279
- this.history.resumeRecording();
2349
+ const nextElements = syncInvalidIndices(sceneData.elements ?? []);
2350
+ if (sceneData.storeAction && sceneData.storeAction !== StoreAction.NONE) {
2351
+ const prevCommittedAppState = this.store.snapshot.appState;
2352
+ const prevCommittedElements = this.store.snapshot.elements;
2353
+ const nextCommittedAppState = sceneData.appState
2354
+ ? Object.assign({}, prevCommittedAppState, sceneData.appState) // new instance, with partial appstate applied to previously captured one, including hidden prop inside `prevCommittedAppState`
2355
+ : prevCommittedAppState;
2356
+ const nextCommittedElements = sceneData.elements
2357
+ ? this.store.filterUncomittedElements(this.scene.getElementsMapIncludingDeleted(), // Only used to detect uncomitted local elements
2358
+ arrayToMap(nextElements))
2359
+ : prevCommittedElements;
2360
+ // 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
2361
+ // do NOT schedule store actions (execute after re-render), as it might cause unexpected concurrency issues if not handled well
2362
+ if (sceneData.storeAction === StoreAction.CAPTURE) {
2363
+ this.store.captureIncrement(nextCommittedElements, nextCommittedAppState);
2364
+ }
2365
+ else if (sceneData.storeAction === StoreAction.UPDATE) {
2366
+ this.store.updateSnapshot(nextCommittedElements, nextCommittedAppState);
2367
+ }
2280
2368
  }
2281
2369
  if (sceneData.appState) {
2282
2370
  this.setState(sceneData.appState);
2283
2371
  }
2284
2372
  if (sceneData.elements) {
2285
- this.scene.replaceAllElements(sceneData.elements);
2373
+ this.scene.replaceAllElements(nextElements);
2286
2374
  }
2287
2375
  if (sceneData.collaborators) {
2288
2376
  this.setState({ collaborators: sceneData.collaborators });
2289
2377
  }
2290
2378
  });
2291
- onSceneUpdated = () => {
2292
- this.setState({});
2379
+ triggerRender = (
2380
+ /** force always re-renders canvas even if no change */
2381
+ force) => {
2382
+ if (force === true) {
2383
+ this.scene.triggerUpdate();
2384
+ }
2385
+ else {
2386
+ this.setState({});
2387
+ }
2293
2388
  };
2294
2389
  /**
2295
2390
  * @returns whether the menu was toggled on or off
@@ -2456,7 +2551,9 @@ class App extends React.Component {
2456
2551
  simultaneouslyUpdated: selectedElements,
2457
2552
  });
2458
2553
  });
2459
- this.maybeSuggestBindingForAll(selectedElements);
2554
+ this.setState({
2555
+ suggestedBindings: getSuggestedBindingsForArrows(selectedElements, this.scene.getNonDeletedElementsMap()),
2556
+ });
2460
2557
  event.preventDefault();
2461
2558
  }
2462
2559
  else if (event.key === KEYS.ENTER) {
@@ -2468,7 +2565,7 @@ class App extends React.Component {
2468
2565
  if (!this.state.editingLinearElement ||
2469
2566
  this.state.editingLinearElement.elementId !==
2470
2567
  selectedElements[0].id) {
2471
- this.history.resumeRecording();
2568
+ this.store.shouldCaptureIncrement();
2472
2569
  this.setState({
2473
2570
  editingLinearElement: new LinearElementEditor(selectedElement),
2474
2571
  });
@@ -2594,11 +2691,7 @@ class App extends React.Component {
2594
2691
  this.setState({ isBindingEnabled: true });
2595
2692
  }
2596
2693
  if (isArrowKey(event.key)) {
2597
- const selectedElements = this.scene.getSelectedElements(this.state);
2598
- const elementsMap = this.scene.getNonDeletedElementsMap();
2599
- isBindingEnabled(this.state)
2600
- ? bindOrUnbindSelectedElements(selectedElements, this)
2601
- : unbindLinearElements(selectedElements, elementsMap);
2694
+ bindOrUnbindLinearElements(this.scene.getSelectedElements(this.state).filter(isLinearElement), this.scene.getNonDeletedElementsMap(), isBindingEnabled(this.state), this.state.selectedLinearElement?.selectedPointsIndices ?? []);
2602
2695
  this.setState({ suggestedBindings: [] });
2603
2696
  }
2604
2697
  });
@@ -2636,6 +2729,9 @@ class App extends React.Component {
2636
2729
  originSnapOffset: null,
2637
2730
  activeEmbeddable: null,
2638
2731
  };
2732
+ if (nextActiveTool.type === "freedraw") {
2733
+ this.store.shouldCaptureIncrement();
2734
+ }
2639
2735
  if (nextActiveTool.type !== "selection") {
2640
2736
  return {
2641
2737
  ...prevState,
@@ -2733,15 +2829,16 @@ class App extends React.Component {
2733
2829
  });
2734
2830
  handleTextWysiwyg(element, { isExistingElement = false, }) {
2735
2831
  const elementsMap = this.scene.getElementsMapIncludingDeleted();
2736
- const updateElement = (text, originalText, isDeleted) => {
2832
+ const updateElement = (nextOriginalText, isDeleted) => {
2737
2833
  this.scene.replaceAllElements([
2738
2834
  // Not sure why we include deleted elements as well hence using deleted elements map
2739
2835
  ...this.scene.getElementsIncludingDeleted().map((_element) => {
2740
2836
  if (_element.id === element.id && isTextElement(_element)) {
2741
- return updateTextElement(_element, getContainerElement(_element, elementsMap), elementsMap, {
2742
- text,
2743
- isDeleted,
2744
- originalText,
2837
+ return newElementWith(_element, {
2838
+ originalText: nextOriginalText,
2839
+ isDeleted: isDeleted ?? _element.isDeleted,
2840
+ // returns (wrapped) text and new dimensions
2841
+ ...refreshTextDimensions(_element, getContainerElement(_element, elementsMap), elementsMap, nextOriginalText),
2745
2842
  });
2746
2843
  }
2747
2844
  return _element;
@@ -2761,15 +2858,15 @@ class App extends React.Component {
2761
2858
  viewportY - this.state.offsetTop,
2762
2859
  ];
2763
2860
  },
2764
- onChange: withBatchedUpdates((text) => {
2765
- updateElement(text, text, false);
2861
+ onChange: withBatchedUpdates((nextOriginalText) => {
2862
+ updateElement(nextOriginalText, false);
2766
2863
  if (isNonDeletedElement(element)) {
2767
2864
  updateBoundElements(element, elementsMap);
2768
2865
  }
2769
2866
  }),
2770
- onSubmit: withBatchedUpdates(({ text, viaKeyboard, originalText }) => {
2771
- const isDeleted = !text.trim();
2772
- updateElement(text, originalText, isDeleted);
2867
+ onSubmit: withBatchedUpdates(({ viaKeyboard, nextOriginalText }) => {
2868
+ const isDeleted = !nextOriginalText.trim();
2869
+ updateElement(nextOriginalText, isDeleted);
2773
2870
  // select the created text element only if submitting via keyboard
2774
2871
  // (when submitting via click it should act as signal to deselect)
2775
2872
  if (!isDeleted && viaKeyboard) {
@@ -2789,7 +2886,7 @@ class App extends React.Component {
2789
2886
  ]);
2790
2887
  }
2791
2888
  if (!isDeleted || isExistingElement) {
2792
- this.history.resumeRecording();
2889
+ this.store.shouldCaptureIncrement();
2793
2890
  }
2794
2891
  this.setState({
2795
2892
  draggingElement: null,
@@ -2803,12 +2900,17 @@ class App extends React.Component {
2803
2900
  element,
2804
2901
  excalidrawContainer: this.excalidrawContainerRef.current,
2805
2902
  app: this,
2903
+ // when text is selected, it's hard (at least on iOS) to re-position the
2904
+ // caret (i.e. deselect). There's not much use for always selecting
2905
+ // the text on edit anyway (and users can select-all from contextmenu
2906
+ // if needed)
2907
+ autoSelect: !this.device.isTouchScreen,
2806
2908
  });
2807
2909
  // deselect all other elements when inserting text
2808
2910
  this.deselectElements();
2809
2911
  // do an initial update to re-initialize element position since we were
2810
2912
  // modifying element's x/y for sake of editor (case: syncing to remote)
2811
- updateElement(element.text, element.originalText, false);
2913
+ updateElement(element.originalText, false);
2812
2914
  }
2813
2915
  deselectElements() {
2814
2916
  this.setState({
@@ -2827,54 +2929,18 @@ class App extends React.Component {
2827
2929
  }
2828
2930
  return null;
2829
2931
  }
2830
- /**
2831
- * get the pure geometric shape of an excalidraw element
2832
- * which is then used for hit detection
2833
- */
2834
- getElementShape(element) {
2835
- switch (element.type) {
2836
- case "rectangle":
2837
- case "diamond":
2838
- case "frame":
2839
- case "magicframe":
2840
- case "embeddable":
2841
- case "image":
2842
- case "iframe":
2843
- case "text":
2844
- case "selection":
2845
- return getPolygonShape(element);
2846
- case "arrow":
2847
- case "line": {
2848
- const roughShape = ShapeCache.get(element)?.[0] ??
2849
- ShapeCache.generateElementShape(element, null)[0];
2850
- const [, , , , cx, cy] = getElementAbsoluteCoords(element, this.scene.getNonDeletedElementsMap());
2851
- return shouldTestInside(element)
2852
- ? getClosedCurveShape(element, roughShape, [element.x, element.y], element.angle, [cx, cy])
2853
- : getCurveShape(roughShape, [element.x, element.y], element.angle, [
2854
- cx,
2855
- cy,
2856
- ]);
2857
- }
2858
- case "ellipse":
2859
- return getEllipseShape(element);
2860
- case "freedraw": {
2861
- const [, , , , cx, cy] = getElementAbsoluteCoords(element, this.scene.getNonDeletedElementsMap());
2862
- return getFreedrawShape(element, [cx, cy], shouldTestInside(element));
2863
- }
2864
- }
2865
- }
2866
2932
  getBoundTextShape(element) {
2867
2933
  const boundTextElement = getBoundTextElement(element, this.scene.getNonDeletedElementsMap());
2868
2934
  if (boundTextElement) {
2869
2935
  if (element.type === "arrow") {
2870
- return this.getElementShape({
2936
+ return getElementShape({
2871
2937
  ...boundTextElement,
2872
2938
  // arrow's bound text accurate position is not stored in the element's property
2873
2939
  // but rather calculated and returned from the following static method
2874
2940
  ...LinearElementEditor.getBoundTextElementPosition(element, boundTextElement, this.scene.getNonDeletedElementsMap()),
2875
- });
2941
+ }, this.scene.getNonDeletedElementsMap());
2876
2942
  }
2877
- return this.getElementShape(boundTextElement);
2943
+ return getElementShape(boundTextElement, this.scene.getNonDeletedElementsMap());
2878
2944
  }
2879
2945
  return null;
2880
2946
  }
@@ -2891,7 +2957,18 @@ class App extends React.Component {
2891
2957
  const elementWithHighestZIndex = allHitElements[allHitElements.length - 1];
2892
2958
  // If we're hitting element with highest z-index only on its bounding box
2893
2959
  // while also hitting other element figure, the latter should be considered.
2894
- return isPointInShape([x, y], this.getElementShape(elementWithHighestZIndex))
2960
+ return hitElementItself({
2961
+ x,
2962
+ y,
2963
+ element: elementWithHighestZIndex,
2964
+ shape: getElementShape(elementWithHighestZIndex, this.scene.getNonDeletedElementsMap()),
2965
+ // when overlapping, we would like to be more precise
2966
+ // this also avoids the need to update past tests
2967
+ threshold: this.getElementHitThreshold() / 2,
2968
+ frameNameBound: isFrameLikeElement(elementWithHighestZIndex)
2969
+ ? this.frameNameBoundsCache.get(elementWithHighestZIndex)
2970
+ : null,
2971
+ })
2895
2972
  ? elementWithHighestZIndex
2896
2973
  : allHitElements[allHitElements.length - 2];
2897
2974
  }
@@ -2934,15 +3011,16 @@ class App extends React.Component {
2934
3011
  .concat(iframeLikes);
2935
3012
  return elements;
2936
3013
  }
2937
- getHitThreshold() {
2938
- return 10 / this.state.zoom.value;
3014
+ getElementHitThreshold() {
3015
+ return DEFAULT_COLLISION_THRESHOLD / this.state.zoom.value;
2939
3016
  }
2940
3017
  hitElement(x, y, element, considerBoundingBox = true) {
2941
3018
  // if the element is selected, then hit test is done against its bounding box
2942
3019
  if (considerBoundingBox &&
2943
3020
  this.state.selectedElementIds[element.id] &&
2944
3021
  shouldShowBoundingBox([element], this.state)) {
2945
- return hitElementBoundingBox(x, y, element, this.scene.getNonDeletedElementsMap(), this.getHitThreshold());
3022
+ const selectionShape = getSelectionBoxShape(element, this.scene.getNonDeletedElementsMap(), this.getElementHitThreshold());
3023
+ return isPointInShape([x, y], selectionShape);
2946
3024
  }
2947
3025
  // take bound text element into consideration for hit collision as well
2948
3026
  const hitBoundTextOfElement = hitElementBoundText(x, y, this.getBoundTextShape(element));
@@ -2953,8 +3031,8 @@ class App extends React.Component {
2953
3031
  x,
2954
3032
  y,
2955
3033
  element,
2956
- shape: this.getElementShape(element),
2957
- threshold: this.getHitThreshold(),
3034
+ shape: getElementShape(element, this.scene.getNonDeletedElementsMap()),
3035
+ threshold: this.getElementHitThreshold(),
2958
3036
  frameNameBound: isFrameLikeElement(element)
2959
3037
  ? this.frameNameBoundsCache.get(element)
2960
3038
  : null,
@@ -2980,8 +3058,8 @@ class App extends React.Component {
2980
3058
  x,
2981
3059
  y,
2982
3060
  element: elements[index],
2983
- shape: this.getElementShape(elements[index]),
2984
- threshold: this.getHitThreshold(),
3061
+ shape: getElementShape(elements[index], this.scene.getNonDeletedElementsMap()),
3062
+ threshold: this.getElementHitThreshold(),
2985
3063
  })) {
2986
3064
  hitElement = elements[index];
2987
3065
  break;
@@ -2993,7 +3071,7 @@ class App extends React.Component {
2993
3071
  }
2994
3072
  return isTextBindableContainer(hitElement, false) ? hitElement : null;
2995
3073
  }
2996
- startTextEditing = ({ sceneX, sceneY, insertAtParentCenter = true, container, }) => {
3074
+ startTextEditing = ({ sceneX, sceneY, insertAtParentCenter = true, container, autoEdit = true, }) => {
2997
3075
  let shouldBindToContainer = false;
2998
3076
  let parentCenterPosition = insertAtParentCenter &&
2999
3077
  this.getTextWysiwygSnappedToCenterPosition(sceneX, sceneY, this.state, container);
@@ -3094,12 +3172,17 @@ class App extends React.Component {
3094
3172
  this.scene.insertElement(element);
3095
3173
  }
3096
3174
  }
3097
- this.setState({
3098
- editingElement: element,
3099
- });
3100
- this.handleTextWysiwyg(element, {
3101
- isExistingElement: !!existingTextElement,
3102
- });
3175
+ if (autoEdit || existingTextElement || container) {
3176
+ this.handleTextWysiwyg(element, {
3177
+ isExistingElement: !!existingTextElement,
3178
+ });
3179
+ }
3180
+ else {
3181
+ this.setState({
3182
+ draggingElement: element,
3183
+ multiElement: null,
3184
+ });
3185
+ }
3103
3186
  };
3104
3187
  handleCanvasDoubleClick = (event) => {
3105
3188
  // case: double-clicking with arrow/line tool selected would both create
@@ -3116,7 +3199,7 @@ class App extends React.Component {
3116
3199
  if (event[KEYS.CTRL_OR_CMD] &&
3117
3200
  (!this.state.editingLinearElement ||
3118
3201
  this.state.editingLinearElement.elementId !== selectedElements[0].id)) {
3119
- this.history.resumeRecording();
3202
+ this.store.shouldCaptureIncrement();
3120
3203
  this.setState({
3121
3204
  editingLinearElement: new LinearElementEditor(selectedElements[0]),
3122
3205
  });
@@ -3131,6 +3214,7 @@ class App extends React.Component {
3131
3214
  const selectedGroupId = hitElement &&
3132
3215
  getSelectedGroupIdForElement(hitElement, this.state.selectedGroupIds);
3133
3216
  if (selectedGroupId) {
3217
+ this.store.shouldCaptureIncrement();
3134
3218
  this.setState((prevState) => ({
3135
3219
  ...prevState,
3136
3220
  ...selectGroupsForSelectedElements({
@@ -3158,8 +3242,8 @@ class App extends React.Component {
3158
3242
  x: sceneX,
3159
3243
  y: sceneY,
3160
3244
  element: container,
3161
- shape: this.getElementShape(container),
3162
- threshold: this.getHitThreshold(),
3245
+ shape: getElementShape(container, this.scene.getNonDeletedElementsMap()),
3246
+ threshold: this.getElementHitThreshold(),
3163
3247
  })) {
3164
3248
  const midPoint = getContainerCenter(container, this.state, this.scene.getNonDeletedElementsMap());
3165
3249
  sceneX = midPoint.x;
@@ -3265,8 +3349,11 @@ class App extends React.Component {
3265
3349
  }, state);
3266
3350
  this.translateCanvas({
3267
3351
  zoom: zoomState.zoom,
3268
- scrollX: zoomState.scrollX + deltaX / nextZoom,
3269
- scrollY: zoomState.scrollY + deltaY / nextZoom,
3352
+ // 2x multiplier is just a magic number that makes this work correctly
3353
+ // on touchscreen devices (note: if we get report that panning is slower/faster
3354
+ // than actual movement, consider swapping with devicePixelRatio)
3355
+ scrollX: zoomState.scrollX + 2 * (deltaX / nextZoom),
3356
+ scrollY: zoomState.scrollY + 2 * (deltaY / nextZoom),
3270
3357
  shouldCacheIgnoreZoom: true,
3271
3358
  });
3272
3359
  });
@@ -3431,15 +3518,23 @@ class App extends React.Component {
3431
3518
  if (selectedElements.length === 1 &&
3432
3519
  !isOverScrollBar &&
3433
3520
  !this.state.editingLinearElement) {
3434
- const elementWithTransformHandleType = getElementWithTransformHandleType(elements, this.state, scenePointerX, scenePointerY, this.state.zoom, event.pointerType, this.scene.getNonDeletedElementsMap());
3435
- if (elementWithTransformHandleType &&
3436
- elementWithTransformHandleType.transformHandleType) {
3437
- setCursor(this.interactiveCanvas, getCursorForResizingElement(elementWithTransformHandleType));
3438
- return;
3521
+ // for linear elements, we'd like to prioritize point dragging over edge resizing
3522
+ // therefore, we update and check hovered point index first
3523
+ if (this.state.selectedLinearElement) {
3524
+ this.handleHoverSelectedLinearElement(this.state.selectedLinearElement, scenePointerX, scenePointerY);
3525
+ }
3526
+ if (!this.state.selectedLinearElement ||
3527
+ this.state.selectedLinearElement.hoverPointIndex === -1) {
3528
+ const elementWithTransformHandleType = getElementWithTransformHandleType(elements, this.state, scenePointerX, scenePointerY, this.state.zoom, event.pointerType, this.scene.getNonDeletedElementsMap(), this.device);
3529
+ if (elementWithTransformHandleType &&
3530
+ elementWithTransformHandleType.transformHandleType) {
3531
+ setCursor(this.interactiveCanvas, getCursorForResizingElement(elementWithTransformHandleType));
3532
+ return;
3533
+ }
3439
3534
  }
3440
3535
  }
3441
3536
  else if (selectedElements.length > 1 && !isOverScrollBar) {
3442
- const transformHandleType = getTransformHandleTypeFromCoords(getCommonBounds(selectedElements), scenePointerX, scenePointerY, this.state.zoom, event.pointerType);
3537
+ const transformHandleType = getTransformHandleTypeFromCoords(getCommonBounds(selectedElements), scenePointerX, scenePointerY, this.state.zoom, event.pointerType, this.device);
3443
3538
  if (transformHandleType) {
3444
3539
  setCursor(this.interactiveCanvas, getCursorForResizingElement({
3445
3540
  transformHandleType,
@@ -3543,7 +3638,7 @@ class App extends React.Component {
3543
3638
  }
3544
3639
  };
3545
3640
  const distance = distance2d(pointerDownState.lastCoords.x, pointerDownState.lastCoords.y, scenePointer.x, scenePointer.y);
3546
- const threshold = this.getHitThreshold();
3641
+ const threshold = this.getElementHitThreshold();
3547
3642
  const point = { ...pointerDownState.lastCoords };
3548
3643
  let samplingInterval = 0;
3549
3644
  while (samplingInterval <= distance) {
@@ -3579,7 +3674,7 @@ class App extends React.Component {
3579
3674
  }
3580
3675
  }
3581
3676
  this.elementsPendingErasure = new Set(this.elementsPendingErasure);
3582
- this.onSceneUpdated();
3677
+ this.triggerRender();
3583
3678
  }
3584
3679
  };
3585
3680
  // set touch moving for mobile context menu
@@ -3599,7 +3694,7 @@ class App extends React.Component {
3599
3694
  x: scenePointerX,
3600
3695
  y: scenePointerY,
3601
3696
  element,
3602
- shape: this.getElementShape(element),
3697
+ shape: getElementShape(element, this.scene.getNonDeletedElementsMap()),
3603
3698
  })) {
3604
3699
  hoverPointIndex = LinearElementEditor.getPointIndexUnderCursor(element, elementsMap, this.state.zoom, scenePointerX, scenePointerY);
3605
3700
  segmentMidPointHoveredCoords =
@@ -3607,7 +3702,7 @@ class App extends React.Component {
3607
3702
  if (hoverPointIndex >= 0 || segmentMidPointHoveredCoords) {
3608
3703
  setCursor(this.interactiveCanvas, CURSOR_TYPE.POINTER);
3609
3704
  }
3610
- else {
3705
+ else if (this.hitElement(scenePointerX, scenePointerY, element)) {
3611
3706
  setCursor(this.interactiveCanvas, CURSOR_TYPE.MOVE);
3612
3707
  }
3613
3708
  }
@@ -3678,6 +3773,7 @@ class App extends React.Component {
3678
3773
  return obj;
3679
3774
  }, {}), this.state),
3680
3775
  },
3776
+ storeAction: StoreAction.UPDATE,
3681
3777
  });
3682
3778
  return;
3683
3779
  }
@@ -3789,7 +3885,6 @@ class App extends React.Component {
3789
3885
  }
3790
3886
  if (this.state.activeTool.type === "text") {
3791
3887
  this.handleTextOnPointerDown(event, pointerDownState);
3792
- return;
3793
3888
  }
3794
3889
  else if (this.state.activeTool.type === "arrow" ||
3795
3890
  this.state.activeTool.type === "line") {
@@ -4117,8 +4212,11 @@ class App extends React.Component {
4117
4212
  const elements = this.scene.getNonDeletedElements();
4118
4213
  const elementsMap = this.scene.getNonDeletedElementsMap();
4119
4214
  const selectedElements = this.scene.getSelectedElements(this.state);
4120
- if (selectedElements.length === 1 && !this.state.editingLinearElement) {
4121
- const elementWithTransformHandleType = getElementWithTransformHandleType(elements, this.state, pointerDownState.origin.x, pointerDownState.origin.y, this.state.zoom, event.pointerType, this.scene.getNonDeletedElementsMap());
4215
+ if (selectedElements.length === 1 &&
4216
+ !this.state.editingLinearElement &&
4217
+ !(this.state.selectedLinearElement &&
4218
+ this.state.selectedLinearElement.hoverPointIndex !== -1)) {
4219
+ const elementWithTransformHandleType = getElementWithTransformHandleType(elements, this.state, pointerDownState.origin.x, pointerDownState.origin.y, this.state.zoom, event.pointerType, this.scene.getNonDeletedElementsMap(), this.device);
4122
4220
  if (elementWithTransformHandleType != null) {
4123
4221
  this.setState({
4124
4222
  resizingElement: elementWithTransformHandleType.element,
@@ -4128,7 +4226,7 @@ class App extends React.Component {
4128
4226
  }
4129
4227
  }
4130
4228
  else if (selectedElements.length > 1) {
4131
- pointerDownState.resize.handleType = getTransformHandleTypeFromCoords(getCommonBounds(selectedElements), pointerDownState.origin.x, pointerDownState.origin.y, this.state.zoom, event.pointerType);
4229
+ pointerDownState.resize.handleType = getTransformHandleTypeFromCoords(getCommonBounds(selectedElements), pointerDownState.origin.x, pointerDownState.origin.y, this.state.zoom, event.pointerType, this.device);
4132
4230
  }
4133
4231
  if (pointerDownState.resize.handleType) {
4134
4232
  pointerDownState.resize.isResizing = true;
@@ -4142,7 +4240,7 @@ class App extends React.Component {
4142
4240
  else {
4143
4241
  if (this.state.selectedLinearElement) {
4144
4242
  const linearElementEditor = this.state.editingLinearElement || this.state.selectedLinearElement;
4145
- const ret = LinearElementEditor.handlePointerDown(event, this.state, this.history, pointerDownState.origin, linearElementEditor, this);
4243
+ const ret = LinearElementEditor.handlePointerDown(event, this.state, this.store, pointerDownState.origin, linearElementEditor, this);
4146
4244
  if (ret.hitElement) {
4147
4245
  pointerDownState.hit.element = ret.hitElement;
4148
4246
  }
@@ -4303,7 +4401,7 @@ class App extends React.Component {
4303
4401
  return false;
4304
4402
  }
4305
4403
  // How many pixels off the shape boundary we still consider a hit
4306
- const threshold = this.getHitThreshold();
4404
+ const threshold = this.getElementHitThreshold();
4307
4405
  const [x1, y1, x2, y2] = getCommonBounds(selectedElements);
4308
4406
  return (point.x > x1 - threshold &&
4309
4407
  point.x < x2 + threshold &&
@@ -4334,6 +4432,7 @@ class App extends React.Component {
4334
4432
  sceneY,
4335
4433
  insertAtParentCenter: !event.altKey,
4336
4434
  container,
4435
+ autoEdit: false,
4337
4436
  });
4338
4437
  resetCursor(this.interactiveCanvas);
4339
4438
  if (!this.state.activeTool.locked) {
@@ -4381,7 +4480,7 @@ class App extends React.Component {
4381
4480
  points: [[0, 0]],
4382
4481
  pressures,
4383
4482
  });
4384
- const boundElement = getHoveredElementForBinding(pointerDownState.origin, this);
4483
+ const boundElement = getHoveredElementForBinding(pointerDownState.origin, this.scene.getNonDeletedElementsMap());
4385
4484
  this.scene.insertElement(element);
4386
4485
  this.setState({
4387
4486
  draggingElement: element,
@@ -4553,7 +4652,7 @@ class App extends React.Component {
4553
4652
  mutateElement(element, {
4554
4653
  points: [...element.points, [0, 0]],
4555
4654
  });
4556
- const boundElement = getHoveredElementForBinding(pointerDownState.origin, this);
4655
+ const boundElement = getHoveredElementForBinding(pointerDownState.origin, this.scene.getNonDeletedElementsMap());
4557
4656
  this.scene.insertElement(element);
4558
4657
  this.setState({
4559
4658
  draggingElement: element,
@@ -4850,7 +4949,9 @@ class App extends React.Component {
4850
4949
  // able to select and interact with the text input
4851
4950
  !this.state.editingFrame &&
4852
4951
  dragSelectedElements(pointerDownState, selectedElements, dragOffset, this.state, this.scene, snapOffset, event[KEYS.CTRL_OR_CMD] ? null : this.state.gridSize);
4853
- this.maybeSuggestBindingForAll(selectedElements);
4952
+ this.setState({
4953
+ suggestedBindings: getSuggestedBindingsForArrows(selectedElements, this.scene.getNonDeletedElementsMap()),
4954
+ });
4854
4955
  // We duplicate the selected element if alt is pressed on pointer move
4855
4956
  if (event.altKey && !pointerDownState.hit.hasBeenDuplicated) {
4856
4957
  // Move the currently selected elements to the top of the z index stack, and
@@ -5174,7 +5275,7 @@ class App extends React.Component {
5174
5275
  }
5175
5276
  if (isLinearElement(draggingElement)) {
5176
5277
  if (draggingElement.points.length > 1) {
5177
- this.history.resumeRecording();
5278
+ this.store.shouldCaptureIncrement();
5178
5279
  }
5179
5280
  const pointerCoords = viewportCoordsToSceneCoords(childEvent, this.state);
5180
5281
  if (!pointerDownState.drag.hasOccurred &&
@@ -5197,7 +5298,7 @@ class App extends React.Component {
5197
5298
  else if (pointerDownState.drag.hasOccurred && !multiElement) {
5198
5299
  if (isBindingEnabled(this.state) &&
5199
5300
  isBindingElement(draggingElement, false)) {
5200
- maybeBindLinearElement(draggingElement, this.state, pointerCoords, this);
5301
+ maybeBindLinearElement(draggingElement, this.state, pointerCoords, this.scene.getNonDeletedElementsMap());
5201
5302
  }
5202
5303
  this.setState({ suggestedBindings: [], startBoundElement: null });
5203
5304
  if (!activeTool.locked) {
@@ -5222,15 +5323,34 @@ class App extends React.Component {
5222
5323
  }
5223
5324
  return;
5224
5325
  }
5326
+ if (isTextElement(draggingElement)) {
5327
+ const minWidth = getMinTextElementWidth(getFontString({
5328
+ fontSize: draggingElement.fontSize,
5329
+ fontFamily: draggingElement.fontFamily,
5330
+ }), draggingElement.lineHeight);
5331
+ if (draggingElement.width < minWidth) {
5332
+ mutateElement(draggingElement, {
5333
+ autoResize: true,
5334
+ });
5335
+ }
5336
+ this.resetCursor();
5337
+ this.handleTextWysiwyg(draggingElement, {
5338
+ isExistingElement: true,
5339
+ });
5340
+ }
5225
5341
  if (activeTool.type !== "selection" &&
5226
5342
  draggingElement &&
5227
5343
  isInvisiblySmallElement(draggingElement)) {
5228
5344
  // remove invisible element which was added in onPointerDown
5229
- this.scene.replaceAllElements(this.scene
5230
- .getElementsIncludingDeleted()
5231
- .filter((el) => el.id !== draggingElement.id));
5232
- this.setState({
5233
- draggingElement: null,
5345
+ // update the store snapshot, so that invisible elements are not captured by the store
5346
+ this.updateScene({
5347
+ elements: this.scene
5348
+ .getElementsIncludingDeleted()
5349
+ .filter((el) => el.id !== draggingElement.id),
5350
+ appState: {
5351
+ draggingElement: null,
5352
+ },
5353
+ storeAction: StoreAction.UPDATE,
5234
5354
  });
5235
5355
  return;
5236
5356
  }
@@ -5253,7 +5373,7 @@ class App extends React.Component {
5253
5373
  groupIds: [],
5254
5374
  });
5255
5375
  removeElementsFromFrame([linearElement], this.scene.getNonDeletedElementsMap());
5256
- this.scene.informMutation();
5376
+ this.scene.triggerUpdate();
5257
5377
  }
5258
5378
  }
5259
5379
  }
@@ -5311,12 +5431,16 @@ class App extends React.Component {
5311
5431
  mutateElement(draggingElement, getNormalizedDimensions(draggingElement));
5312
5432
  }
5313
5433
  if (resizingElement) {
5314
- this.history.resumeRecording();
5434
+ this.store.shouldCaptureIncrement();
5315
5435
  }
5316
5436
  if (resizingElement && isInvisiblySmallElement(resizingElement)) {
5317
- this.scene.replaceAllElements(this.scene
5318
- .getElementsIncludingDeleted()
5319
- .filter((el) => el.id !== resizingElement.id));
5437
+ // update the store snapshot, so that invisible elements are not captured by the store
5438
+ this.updateScene({
5439
+ elements: this.scene
5440
+ .getElementsIncludingDeleted()
5441
+ .filter((el) => el.id !== resizingElement.id),
5442
+ storeAction: StoreAction.UPDATE,
5443
+ });
5320
5444
  }
5321
5445
  // handle frame membership for resizing frames and/or selected elements
5322
5446
  if (pointerDownState.resize.isResizing) {
@@ -5482,8 +5606,8 @@ class App extends React.Component {
5482
5606
  x: pointerDownState.origin.x,
5483
5607
  y: pointerDownState.origin.y,
5484
5608
  element: hitElement,
5485
- shape: this.getElementShape(hitElement),
5486
- threshold: this.getHitThreshold(),
5609
+ shape: getElementShape(hitElement, this.scene.getNonDeletedElementsMap()),
5610
+ threshold: this.getElementHitThreshold(),
5487
5611
  frameNameBound: isFrameLikeElement(hitElement)
5488
5612
  ? this.frameNameBoundsCache.get(hitElement)
5489
5613
  : null,
@@ -5521,13 +5645,17 @@ class App extends React.Component {
5521
5645
  }));
5522
5646
  }
5523
5647
  if (activeTool.type !== "selection" ||
5524
- isSomeElementSelected(this.scene.getNonDeletedElements(), this.state)) {
5525
- this.history.resumeRecording();
5648
+ isSomeElementSelected(this.scene.getNonDeletedElements(), this.state) ||
5649
+ !isShallowEqual(this.state.previousSelectedElementIds, this.state.selectedElementIds)) {
5650
+ this.store.shouldCaptureIncrement();
5526
5651
  }
5527
5652
  if (pointerDownState.drag.hasOccurred || isResizing || isRotating) {
5528
- isBindingEnabled(this.state)
5529
- ? bindOrUnbindSelectedElements(this.scene.getSelectedElements(this.state), this)
5530
- : unbindLinearElements(this.scene.getNonDeletedElements(), elementsMap);
5653
+ // We only allow binding via linear elements, specifically via dragging
5654
+ // the endpoints ("start" or "end").
5655
+ const linearElements = this.scene
5656
+ .getSelectedElements(this.state)
5657
+ .filter(isLinearElement);
5658
+ bindOrUnbindLinearElements(linearElements, this.scene.getNonDeletedElementsMap(), isBindingEnabled(this.state), this.state.selectedLinearElement?.selectedPointsIndices ?? []);
5531
5659
  }
5532
5660
  if (activeTool.type === "laser") {
5533
5661
  this.laserTrails.endPath();
@@ -5562,7 +5690,7 @@ class App extends React.Component {
5562
5690
  }
5563
5691
  restoreReadyToEraseElements = () => {
5564
5692
  this.elementsPendingErasure = new Set();
5565
- this.onSceneUpdated();
5693
+ this.triggerRender();
5566
5694
  };
5567
5695
  eraseElements = () => {
5568
5696
  let didChange = false;
@@ -5578,7 +5706,7 @@ class App extends React.Component {
5578
5706
  });
5579
5707
  this.elementsPendingErasure = new Set();
5580
5708
  if (didChange) {
5581
- this.history.resumeRecording();
5709
+ this.store.shouldCaptureIncrement();
5582
5710
  this.scene.replaceAllElements(elements);
5583
5711
  }
5584
5712
  };
@@ -5854,7 +5982,7 @@ class App extends React.Component {
5854
5982
  if (uncachedImageElements.length) {
5855
5983
  const { updatedFiles } = await this.updateImageCache(uncachedImageElements, files);
5856
5984
  if (updatedFiles.size) {
5857
- this.scene.informMutation();
5985
+ this.scene.triggerUpdate();
5858
5986
  }
5859
5987
  }
5860
5988
  };
@@ -5870,7 +5998,7 @@ class App extends React.Component {
5870
5998
  }
5871
5999
  };
5872
6000
  maybeSuggestBindingAtCursor = (pointerCoords) => {
5873
- const hoveredBindableElement = getHoveredElementForBinding(pointerCoords, this);
6001
+ const hoveredBindableElement = getHoveredElementForBinding(pointerCoords, this.scene.getNonDeletedElementsMap());
5874
6002
  this.setState({
5875
6003
  suggestedBindings: hoveredBindableElement != null ? [hoveredBindableElement] : [],
5876
6004
  });
@@ -5885,7 +6013,7 @@ class App extends React.Component {
5885
6013
  return;
5886
6014
  }
5887
6015
  const suggestedBindings = pointerCoords.reduce((acc, coords) => {
5888
- const hoveredBindableElement = getHoveredElementForBinding(coords, this);
6016
+ const hoveredBindableElement = getHoveredElementForBinding(coords, this.scene.getNonDeletedElementsMap());
5889
6017
  if (hoveredBindableElement != null &&
5890
6018
  !isLinearElementSimpleAndAlreadyBound(linearElement, oppositeBindingBoundElement?.id, hoveredBindableElement)) {
5891
6019
  acc.push(hoveredBindableElement);
@@ -5894,13 +6022,6 @@ class App extends React.Component {
5894
6022
  }, []);
5895
6023
  this.setState({ suggestedBindings });
5896
6024
  };
5897
- maybeSuggestBindingForAll(selectedElements) {
5898
- if (selectedElements.length > 50) {
5899
- return;
5900
- }
5901
- const suggestedBindings = getEligibleElementsForBinding(selectedElements, this);
5902
- this.setState({ suggestedBindings });
5903
- }
5904
6025
  clearSelection(hitElement) {
5905
6026
  this.setState((prevState) => ({
5906
6027
  selectedElementIds: makeNextSelectedElementIds({}, prevState),
@@ -5960,7 +6081,7 @@ class App extends React.Component {
5960
6081
  isLoading: false,
5961
6082
  },
5962
6083
  replaceFiles: true,
5963
- commitToHistory: true,
6084
+ storeAction: StoreAction.CAPTURE,
5964
6085
  });
5965
6086
  return;
5966
6087
  }
@@ -6028,9 +6149,10 @@ class App extends React.Component {
6028
6149
  loadFileToCanvas = async (file, fileHandle) => {
6029
6150
  file = await normalizeFile(file);
6030
6151
  try {
6152
+ const elements = this.scene.getElementsIncludingDeleted();
6031
6153
  let ret;
6032
6154
  try {
6033
- ret = await loadSceneOrLibraryFromBlob(file, this.state, this.scene.getElementsIncludingDeleted(), fileHandle);
6155
+ ret = await loadSceneOrLibraryFromBlob(file, this.state, elements, fileHandle);
6034
6156
  }
6035
6157
  catch (error) {
6036
6158
  const imageSceneDataError = error instanceof ImageSceneDataError;
@@ -6055,6 +6177,10 @@ class App extends React.Component {
6055
6177
  return;
6056
6178
  }
6057
6179
  if (ret.type === MIME_TYPES.excalidraw) {
6180
+ // restore the fractional indices by mutating elements
6181
+ syncInvalidIndices(elements.concat(ret.data.elements));
6182
+ // update the store snapshot for old elements, otherwise we would end up with duplicated fractional indices on undo
6183
+ this.store.updateSnapshot(arrayToMap(elements), this.state);
6058
6184
  this.setState({ isLoading: true });
6059
6185
  this.syncActionResult({
6060
6186
  ...ret.data,
@@ -6063,7 +6189,7 @@ class App extends React.Component {
6063
6189
  isLoading: false,
6064
6190
  },
6065
6191
  replaceFiles: true,
6066
- commitToHistory: true,
6192
+ storeAction: StoreAction.CAPTURE,
6067
6193
  });
6068
6194
  }
6069
6195
  else if (ret.type === MIME_TYPES.excalidrawlib) {
@@ -6135,7 +6261,7 @@ class App extends React.Component {
6135
6261
  }
6136
6262
  if (draggingElement.type === "selection" &&
6137
6263
  this.state.activeTool.type !== "eraser") {
6138
- 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));
6264
+ 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);
6139
6265
  }
6140
6266
  else {
6141
6267
  let [gridX, gridY] = getGridPoint(pointerCoords.x, pointerCoords.y, event[KEYS.CTRL_OR_CMD] ? null : this.state.gridSize);
@@ -6161,8 +6287,7 @@ class App extends React.Component {
6161
6287
  });
6162
6288
  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)
6163
6289
  ? !shouldMaintainAspectRatio(event)
6164
- : shouldMaintainAspectRatio(event), shouldResizeFromCenter(event), aspectRatio, this.state.originSnapOffset);
6165
- this.maybeSuggestBindingForAll([draggingElement]);
6290
+ : shouldMaintainAspectRatio(event), shouldResizeFromCenter(event), this.state.zoom.value, aspectRatio, this.state.originSnapOffset);
6166
6291
  // highlight elements that are to be added to frames on frames creation
6167
6292
  if (this.state.activeTool.type === TOOL_TYPE.frame ||
6168
6293
  this.state.activeTool.type === TOOL_TYPE.magicframe) {
@@ -6216,16 +6341,17 @@ class App extends React.Component {
6216
6341
  snapLines,
6217
6342
  });
6218
6343
  }
6219
- if (transformElements(pointerDownState.originalElements, transformHandleType, selectedElements, this.scene.getElementsMapIncludingDeleted(), shouldRotateWithDiscreteAngle(event), shouldResizeFromCenter(event), selectedElements.length === 1 && isImageElement(selectedElements[0])
6344
+ if (transformElements(pointerDownState.originalElements, transformHandleType, selectedElements, this.scene.getElementsMapIncludingDeleted(), shouldRotateWithDiscreteAngle(event), shouldResizeFromCenter(event), selectedElements.some((element) => isImageElement(element))
6220
6345
  ? !shouldMaintainAspectRatio(event)
6221
6346
  : shouldMaintainAspectRatio(event), resizeX, resizeY, pointerDownState.resize.center.x, pointerDownState.resize.center.y)) {
6222
- this.maybeSuggestBindingForAll(selectedElements);
6347
+ const suggestedBindings = getSuggestedBindingsForArrows(selectedElements, this.scene.getNonDeletedElementsMap());
6223
6348
  const elementsToHighlight = new Set();
6224
6349
  selectedFrames.forEach((frame) => {
6225
6350
  getElementsInResizingFrame(this.scene.getNonDeletedElements(), frame, this.state, this.scene.getNonDeletedElementsMap()).forEach((element) => elementsToHighlight.add(element));
6226
6351
  });
6227
6352
  this.setState({
6228
6353
  elementsToHighlight: [...elementsToHighlight],
6354
+ suggestedBindings,
6229
6355
  });
6230
6356
  return true;
6231
6357
  }
@@ -6270,6 +6396,7 @@ class App extends React.Component {
6270
6396
  return [actionCopy, ...options];
6271
6397
  }
6272
6398
  return [
6399
+ CONTEXT_MENU_SEPARATOR,
6273
6400
  actionCut,
6274
6401
  actionCopy,
6275
6402
  actionPaste,
@@ -6282,6 +6409,7 @@ class App extends React.Component {
6282
6409
  actionPasteStyles,
6283
6410
  CONTEXT_MENU_SEPARATOR,
6284
6411
  actionGroup,
6412
+ actionTextAutoResize,
6285
6413
  actionUnbindText,
6286
6414
  actionBindText,
6287
6415
  actionWrapTextInContainer,