@dwelle/excalidraw 0.5.0-da1c822 → 0.5.0-e8bcd96

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 (462) hide show
  1. package/CHANGELOG.md +13 -2
  2. package/dist/browser/dev/excalidraw-assets-dev/{blockDiagram-91b80b7a-RHODGCTM.js → blockDiagram-91b80b7a-SWMOP5PL.js} +6 -6
  3. package/dist/browser/dev/excalidraw-assets-dev/{c4Diagram-b2a90758-W7NCR7LR.js → c4Diagram-b2a90758-N33A4OZ7.js} +4 -4
  4. package/dist/browser/dev/excalidraw-assets-dev/{chunk-TKRIVTWP.js → chunk-3XV32LTV.js} +3 -3
  5. package/dist/browser/dev/excalidraw-assets-dev/{chunk-B2MHJWXZ.js → chunk-CLMTS5EY.js} +2 -2
  6. package/dist/browser/dev/excalidraw-assets-dev/{chunk-QFS4M5OJ.js → chunk-DIDQ2KEW.js} +3 -3
  7. package/dist/browser/dev/excalidraw-assets-dev/{chunk-5747M6KP.js → chunk-G3PHSEXY.js} +3 -3
  8. package/dist/browser/dev/excalidraw-assets-dev/{chunk-PPHFJLL7.js → chunk-HCMMCBMX.js} +4 -4
  9. package/dist/browser/dev/excalidraw-assets-dev/{chunk-DQOPSCYA.js → chunk-K5QPOXOQ.js} +3 -3
  10. package/dist/browser/dev/excalidraw-assets-dev/{chunk-52OGG53V.js → chunk-KMSH7QAI.js} +3 -3
  11. package/dist/browser/dev/excalidraw-assets-dev/{chunk-SLLUETBM.js → chunk-TVSGJBCZ.js} +7 -7
  12. package/dist/browser/dev/excalidraw-assets-dev/{chunk-GPOYIZPX.js → chunk-UEFQKRSO.js} +28 -28
  13. package/dist/browser/dev/excalidraw-assets-dev/chunk-UEFQKRSO.js.map +7 -0
  14. package/dist/browser/dev/excalidraw-assets-dev/{chunk-BESQLMCW.js → chunk-UONPRRXT.js} +5 -5
  15. package/dist/browser/dev/excalidraw-assets-dev/{chunk-UETNA2WX.js → chunk-V6ITT7XZ.js} +7397 -5320
  16. package/dist/browser/dev/excalidraw-assets-dev/chunk-V6ITT7XZ.js.map +7 -0
  17. package/dist/browser/dev/excalidraw-assets-dev/{chunk-USLWOHUZ.js → chunk-VU32GUMX.js} +4 -4
  18. package/dist/browser/dev/excalidraw-assets-dev/{chunk-GF7VCOUM.js → chunk-WQNNVZHO.js} +3 -3
  19. package/dist/browser/dev/excalidraw-assets-dev/{chunk-GCA4S2OA.js → chunk-WXRCMPEJ.js} +3 -3
  20. package/dist/browser/dev/excalidraw-assets-dev/{chunk-J5HRUYQR.js → chunk-YGAE3YWH.js} +6 -4
  21. package/dist/browser/dev/excalidraw-assets-dev/chunk-YGAE3YWH.js.map +7 -0
  22. package/dist/browser/dev/excalidraw-assets-dev/{classDiagram-30eddba6-GJGBT4TV.js → classDiagram-30eddba6-HGXEWQY2.js} +6 -6
  23. package/dist/browser/dev/excalidraw-assets-dev/{classDiagram-v2-f2df5561-LYWTIPJA.js → classDiagram-v2-f2df5561-ANW5DGKP.js} +9 -9
  24. package/dist/browser/dev/excalidraw-assets-dev/{directory-open-01563666-UREMLRIT.js → directory-open-01563666-67XPRP2W.js} +2 -2
  25. package/dist/browser/dev/excalidraw-assets-dev/{directory-open-4ed118d0-UN3BUDZZ.js → directory-open-4ed118d0-TZOVUMX3.js} +2 -2
  26. package/dist/browser/dev/excalidraw-assets-dev/dist-JWLY7ZTC.js +10 -0
  27. package/dist/browser/dev/excalidraw-assets-dev/{en-UW5C5KGW.js → en-RSUSLGPV.js} +2 -2
  28. package/dist/browser/dev/excalidraw-assets-dev/{erDiagram-47591fe2-Z7U2XW2Y.js → erDiagram-47591fe2-HB4S6KST.js} +5 -5
  29. package/dist/browser/dev/excalidraw-assets-dev/{file-open-002ab408-4QG336MG.js → file-open-002ab408-ODQEDP24.js} +2 -2
  30. package/dist/browser/dev/excalidraw-assets-dev/{file-open-7c801643-3QI4ICCL.js → file-open-7c801643-RPLD6WZI.js} +2 -2
  31. package/dist/browser/dev/excalidraw-assets-dev/{file-save-3189631c-TNNERCWV.js → file-save-3189631c-63VHNBWZ.js} +2 -2
  32. package/dist/browser/dev/excalidraw-assets-dev/{file-save-745eba88-JFMH565P.js → file-save-745eba88-SJSX6XSD.js} +2 -2
  33. package/dist/browser/dev/excalidraw-assets-dev/{flowDiagram-5540d9b9-PARVG263.js → flowDiagram-5540d9b9-4QMRNUIV.js} +10 -10
  34. package/dist/browser/dev/excalidraw-assets-dev/{flowDiagram-v2-3b53844e-ZJOPVRMB.js → flowDiagram-v2-3b53844e-EH5O3NBM.js} +10 -10
  35. package/dist/browser/dev/excalidraw-assets-dev/{flowchart-elk-definition-5fe447d6-ULPNBSZX.js → flowchart-elk-definition-5fe447d6-7HGYBXUA.js} +6 -6
  36. package/dist/browser/dev/excalidraw-assets-dev/{ganttDiagram-9a3bba1f-ESSYVTJ4.js → ganttDiagram-9a3bba1f-V5WA3IP4.js} +3 -3
  37. package/dist/browser/dev/excalidraw-assets-dev/{gitGraphDiagram-96e6b4ee-6V6VVNNP.js → gitGraphDiagram-96e6b4ee-6JA3Z4O2.js} +3 -3
  38. package/dist/browser/dev/excalidraw-assets-dev/{image-3LTGFHLF.js → image-GHNRJPTS.js} +6 -6
  39. package/dist/browser/dev/excalidraw-assets-dev/{image-ZNQQXS62.css → image-JYKIJPJC.css} +49 -29
  40. package/dist/browser/dev/excalidraw-assets-dev/image-JYKIJPJC.css.map +7 -0
  41. package/dist/browser/dev/excalidraw-assets-dev/{image-blob-reduce.esm-KTX27DAY.js → image-blob-reduce.esm-QYPUYIZK.js} +2 -2
  42. package/dist/browser/dev/excalidraw-assets-dev/{infoDiagram-bcd20f53-I22FLFX3.js → infoDiagram-bcd20f53-24MBINO2.js} +3 -3
  43. package/dist/browser/dev/excalidraw-assets-dev/{journeyDiagram-4fe6b3dc-WAO6F52C.js → journeyDiagram-4fe6b3dc-KJ4YYJII.js} +4 -4
  44. package/dist/browser/dev/excalidraw-assets-dev/{katex-NWA2YFOP.js → katex-INYZI6LE.js} +2 -2
  45. package/dist/browser/dev/excalidraw-assets-dev/{mindmap-definition-f354de21-K74IKX4Y.js → mindmap-definition-f354de21-VZEH45PD.js} +4 -4
  46. package/dist/browser/dev/excalidraw-assets-dev/{pica-3TH2EGXR.js → pica-YQGHCBVI.js} +2 -2
  47. package/dist/browser/dev/excalidraw-assets-dev/{pieDiagram-79897490-DOB2LVE5.js → pieDiagram-79897490-Z2LCRKGQ.js} +3 -3
  48. package/dist/browser/dev/excalidraw-assets-dev/{quadrantDiagram-62f64e94-MJV2X7WI.js → quadrantDiagram-62f64e94-J3AFAFGX.js} +3 -3
  49. package/dist/browser/dev/excalidraw-assets-dev/{requirementDiagram-05bf5f74-H4YM3XN7.js → requirementDiagram-05bf5f74-M474HB6I.js} +5 -5
  50. package/dist/browser/dev/excalidraw-assets-dev/{roundRect-4S3QV2NZ.js → roundRect-ZCXXTYZ4.js} +2 -2
  51. package/dist/browser/dev/excalidraw-assets-dev/{sankeyDiagram-97764748-7X74ABAN.js → sankeyDiagram-97764748-TNQP5HMX.js} +3 -3
  52. package/dist/browser/dev/excalidraw-assets-dev/{sequenceDiagram-acc0e65c-PPDIJFQP.js → sequenceDiagram-acc0e65c-3NIA26ZM.js} +4 -4
  53. package/dist/browser/dev/excalidraw-assets-dev/{stateDiagram-0ff1cf1a-JVBR7N35.js → stateDiagram-0ff1cf1a-V6UXRWCT.js} +6 -6
  54. package/dist/browser/dev/excalidraw-assets-dev/{stateDiagram-v2-9a9d610d-QYAJLQJH.js → stateDiagram-v2-9a9d610d-7LTZXINB.js} +9 -9
  55. package/dist/browser/dev/excalidraw-assets-dev/{timeline-definition-fea2a41d-GL7U3WDB.js → timeline-definition-fea2a41d-X4VGA6IX.js} +3 -3
  56. package/dist/browser/dev/excalidraw-assets-dev/{xychartDiagram-ab372869-4U4JE4TW.js → xychartDiagram-ab372869-UQCQVK6J.js} +4 -4
  57. package/dist/browser/dev/index.css +48 -28
  58. package/dist/browser/dev/index.css.map +2 -2
  59. package/dist/browser/dev/index.js +9 -5
  60. package/dist/browser/prod/excalidraw-assets/{blockDiagram-91b80b7a-BO7MW3VX.js → blockDiagram-91b80b7a-2ADOK2UH.js} +1 -1
  61. package/dist/browser/prod/excalidraw-assets/{c4Diagram-b2a90758-VCUPBVHR.js → c4Diagram-b2a90758-XJ3HR543.js} +1 -1
  62. package/dist/browser/prod/excalidraw-assets/{chunk-VXFFPRP2.js → chunk-4X2EVGJW.js} +1 -1
  63. package/dist/browser/prod/excalidraw-assets/{chunk-5PWM36DG.js → chunk-5ARJLPSL.js} +1 -1
  64. package/dist/browser/prod/excalidraw-assets/{chunk-B7CDQVNY.js → chunk-6RDIDVV6.js} +21 -21
  65. package/dist/browser/prod/excalidraw-assets/chunk-AWDUHWKA.js +269 -0
  66. package/dist/browser/prod/excalidraw-assets/{chunk-V7HUISEN.js → chunk-COMJOADH.js} +1 -1
  67. package/dist/browser/prod/excalidraw-assets/{chunk-NM5B2RBP.js → chunk-DHU3NMWJ.js} +1 -1
  68. package/dist/browser/prod/excalidraw-assets/{chunk-4JYQ3563.js → chunk-FKEWZS6G.js} +1 -1
  69. package/dist/browser/prod/excalidraw-assets/{chunk-3VCRCP5J.js → chunk-GID7HY42.js} +1 -1
  70. package/dist/browser/prod/excalidraw-assets/{chunk-7UJZVYSR.js → chunk-H4K7WCAG.js} +1 -1
  71. package/dist/browser/prod/excalidraw-assets/{chunk-3HZHH3PT.js → chunk-PDA7IERE.js} +1 -1
  72. package/dist/browser/prod/excalidraw-assets/{chunk-O77Z7CWL.js → chunk-SCYMUHNO.js} +1 -1
  73. package/dist/browser/prod/excalidraw-assets/{chunk-QLNFR4AJ.js → chunk-SCZE4QLN.js} +2 -2
  74. package/dist/browser/prod/excalidraw-assets/{chunk-HPA5W5VE.js → chunk-Y4AVKYKK.js} +1 -1
  75. package/dist/browser/prod/excalidraw-assets/{chunk-CVEF66PS.js → chunk-YFHFEESB.js} +1 -1
  76. package/dist/browser/prod/excalidraw-assets/{chunk-22FVL4I7.js → chunk-Z4B7QXT2.js} +1 -1
  77. package/dist/browser/prod/excalidraw-assets/{classDiagram-30eddba6-VXGNM3LI.js → classDiagram-30eddba6-RQ6VHNNF.js} +1 -1
  78. package/dist/browser/prod/excalidraw-assets/{classDiagram-v2-f2df5561-YALTASVE.js → classDiagram-v2-f2df5561-TL3XYHL6.js} +1 -1
  79. package/dist/browser/prod/excalidraw-assets/{directory-open-01563666-JWXY2QSC.js → directory-open-01563666-ORBUXLUB.js} +1 -1
  80. package/dist/browser/prod/excalidraw-assets/{directory-open-4ed118d0-6AL5X37W.js → directory-open-4ed118d0-HRBZ4CD4.js} +1 -1
  81. package/dist/browser/prod/excalidraw-assets/dist-IRBESAGJ.js +1 -0
  82. package/dist/browser/prod/excalidraw-assets/{en-CPU3UVKT.js → en-SOC7FEW5.js} +1 -1
  83. package/dist/browser/prod/excalidraw-assets/{erDiagram-47591fe2-GKYANCN7.js → erDiagram-47591fe2-PBCROW3M.js} +1 -1
  84. package/dist/browser/prod/excalidraw-assets/{file-open-002ab408-3EPJOH45.js → file-open-002ab408-SRGK55ER.js} +1 -1
  85. package/dist/browser/prod/excalidraw-assets/{file-open-7c801643-QIP6HK4D.js → file-open-7c801643-IAPRROWG.js} +1 -1
  86. package/dist/browser/prod/excalidraw-assets/{file-save-3189631c-4TQJBQCS.js → file-save-3189631c-LO2KPJNL.js} +1 -1
  87. package/dist/browser/prod/excalidraw-assets/{file-save-745eba88-C4L3ZGCC.js → file-save-745eba88-2DRIRHNX.js} +1 -1
  88. package/dist/browser/prod/excalidraw-assets/{flowDiagram-5540d9b9-QBRW5SLP.js → flowDiagram-5540d9b9-6MWFBLXS.js} +1 -1
  89. package/dist/browser/prod/excalidraw-assets/flowDiagram-v2-3b53844e-CD6XHMHV.js +1 -0
  90. package/dist/browser/prod/excalidraw-assets/{flowchart-elk-definition-5fe447d6-YYO2EYKS.js → flowchart-elk-definition-5fe447d6-4UPGJKHJ.js} +1 -1
  91. package/dist/browser/prod/excalidraw-assets/{ganttDiagram-9a3bba1f-3B2DUUUQ.js → ganttDiagram-9a3bba1f-PDRTJQZH.js} +1 -1
  92. package/dist/browser/prod/excalidraw-assets/{gitGraphDiagram-96e6b4ee-G6CKXXWQ.js → gitGraphDiagram-96e6b4ee-3J3YSPOQ.js} +1 -1
  93. package/dist/browser/prod/excalidraw-assets/image-U235TWVW.css +1 -0
  94. package/dist/browser/prod/excalidraw-assets/image-ZYZR4L6P.js +1 -0
  95. package/dist/browser/prod/excalidraw-assets/{image-blob-reduce.esm-5DTGAOOI.js → image-blob-reduce.esm-XVCS6NNL.js} +1 -1
  96. package/dist/browser/prod/excalidraw-assets/{infoDiagram-bcd20f53-WJTZJERL.js → infoDiagram-bcd20f53-DVJQEG4I.js} +1 -1
  97. package/dist/browser/prod/excalidraw-assets/{journeyDiagram-4fe6b3dc-JF22KXXQ.js → journeyDiagram-4fe6b3dc-ASSTFADN.js} +1 -1
  98. package/dist/browser/prod/excalidraw-assets/{katex-N6R5DPQX.js → katex-RDNZD65H.js} +1 -1
  99. package/dist/browser/prod/excalidraw-assets/{mindmap-definition-f354de21-7SH5STU3.js → mindmap-definition-f354de21-4Y6OYM5B.js} +1 -1
  100. package/dist/browser/prod/excalidraw-assets/{pica-KWHN2PJ6.js → pica-P43LGTW6.js} +1 -1
  101. package/dist/browser/prod/excalidraw-assets/{pieDiagram-79897490-5O5EBEQB.js → pieDiagram-79897490-XJXBVFLX.js} +1 -1
  102. package/dist/browser/prod/excalidraw-assets/{quadrantDiagram-62f64e94-JTY6WOKB.js → quadrantDiagram-62f64e94-PC5DTCKV.js} +1 -1
  103. package/dist/browser/prod/excalidraw-assets/{requirementDiagram-05bf5f74-TSFQFY5X.js → requirementDiagram-05bf5f74-ILVOGHRN.js} +1 -1
  104. package/dist/browser/prod/excalidraw-assets/{roundRect-PUCZURYS.js → roundRect-HU3IUMCJ.js} +1 -1
  105. package/dist/browser/prod/excalidraw-assets/{sankeyDiagram-97764748-7G2R6W67.js → sankeyDiagram-97764748-SC5VBCT5.js} +1 -1
  106. package/dist/browser/prod/excalidraw-assets/{sequenceDiagram-acc0e65c-CTANNZCO.js → sequenceDiagram-acc0e65c-MFG2JCTS.js} +1 -1
  107. package/dist/browser/prod/excalidraw-assets/{stateDiagram-0ff1cf1a-I5COLKZ4.js → stateDiagram-0ff1cf1a-2HXG5RCM.js} +1 -1
  108. package/dist/browser/prod/excalidraw-assets/{stateDiagram-v2-9a9d610d-IIHI3AJN.js → stateDiagram-v2-9a9d610d-PKXRQ3RV.js} +1 -1
  109. package/dist/browser/prod/excalidraw-assets/{timeline-definition-fea2a41d-CXTGKWI4.js → timeline-definition-fea2a41d-LOYYYOFB.js} +1 -1
  110. package/dist/browser/prod/excalidraw-assets/{xychartDiagram-ab372869-QZGPPHJP.js → xychartDiagram-ab372869-LYHM7ECI.js} +1 -1
  111. package/dist/browser/prod/index.css +1 -1
  112. package/dist/browser/prod/index.js +1 -1
  113. package/dist/dev/{en-R7FEFJGC.json → en-GM5O55AO.json} +5 -3
  114. package/dist/dev/index.css +48 -28
  115. package/dist/dev/index.css.map +2 -2
  116. package/dist/dev/index.js +5324 -3292
  117. package/dist/dev/index.js.map +4 -4
  118. package/dist/excalidraw/actions/actionAddToLibrary.d.ts +4 -4
  119. package/dist/excalidraw/actions/actionAddToLibrary.js +4 -3
  120. package/dist/excalidraw/actions/actionAlign.d.ts +22 -22
  121. package/dist/excalidraw/actions/actionAlign.js +7 -6
  122. package/dist/excalidraw/actions/actionBoundText.d.ts +10 -10
  123. package/dist/excalidraw/actions/actionBoundText.js +11 -5
  124. package/dist/excalidraw/actions/actionCanvas.d.ts +52 -52
  125. package/dist/excalidraw/actions/actionCanvas.js +16 -13
  126. package/dist/excalidraw/actions/actionClipboard.d.ts +24 -24
  127. package/dist/excalidraw/actions/actionClipboard.js +14 -13
  128. package/dist/excalidraw/actions/actionDeleteSelected.d.ts +10 -10
  129. package/dist/excalidraw/actions/actionDeleteSelected.js +6 -3
  130. package/dist/excalidraw/actions/actionDistribute.d.ts +10 -10
  131. package/dist/excalidraw/actions/actionDistribute.js +3 -2
  132. package/dist/excalidraw/actions/actionDuplicateSelection.d.ts +7 -8
  133. package/dist/excalidraw/actions/actionDuplicateSelection.js +7 -3
  134. package/dist/excalidraw/actions/actionElementLock.d.ts +9 -9
  135. package/dist/excalidraw/actions/actionElementLock.js +3 -2
  136. package/dist/excalidraw/actions/actionExport.d.ts +37 -37
  137. package/dist/excalidraw/actions/actionExport.js +15 -11
  138. package/dist/excalidraw/actions/actionFinalize.d.ts +9 -9
  139. package/dist/excalidraw/actions/actionFinalize.js +9 -5
  140. package/dist/excalidraw/actions/actionFlip.d.ts +10 -10
  141. package/dist/excalidraw/actions/actionFlip.js +12 -12
  142. package/dist/excalidraw/actions/actionFrame.d.ts +16 -171
  143. package/dist/excalidraw/actions/actionFrame.js +7 -6
  144. package/dist/excalidraw/actions/actionGroup.d.ts +12 -322
  145. package/dist/excalidraw/actions/actionGroup.js +9 -11
  146. package/dist/excalidraw/actions/actionHistory.d.ts +4 -3
  147. package/dist/excalidraw/actions/actionHistory.js +27 -28
  148. package/dist/excalidraw/actions/actionLinearEditor.d.ts +6 -4
  149. package/dist/excalidraw/actions/actionLinearEditor.js +21 -5
  150. package/dist/excalidraw/actions/actionLink.d.ts +5 -5
  151. package/dist/excalidraw/actions/actionLink.js +2 -1
  152. package/dist/excalidraw/actions/actionMenu.d.ts +8 -8
  153. package/dist/excalidraw/actions/actionMenu.js +4 -3
  154. package/dist/excalidraw/actions/actionNavigate.d.ts +4 -4
  155. package/dist/excalidraw/actions/actionNavigate.js +3 -2
  156. package/dist/excalidraw/actions/actionProperties.d.ts +34 -34
  157. package/dist/excalidraw/actions/actionProperties.js +19 -14
  158. package/dist/excalidraw/actions/actionSelectAll.d.ts +5 -5
  159. package/dist/excalidraw/actions/actionSelectAll.js +2 -1
  160. package/dist/excalidraw/actions/actionStyles.d.ts +9 -12
  161. package/dist/excalidraw/actions/actionStyles.js +4 -3
  162. package/dist/excalidraw/actions/actionTextAutoResize.d.ts +17 -0
  163. package/dist/excalidraw/actions/actionTextAutoResize.js +38 -0
  164. package/dist/excalidraw/actions/actionToggleGridMode.d.ts +7 -5
  165. package/dist/excalidraw/actions/actionToggleGridMode.js +6 -2
  166. package/dist/excalidraw/actions/actionToggleObjectsSnapMode.d.ts +4 -4
  167. package/dist/excalidraw/actions/actionToggleObjectsSnapMode.js +2 -1
  168. package/dist/excalidraw/actions/actionToggleStats.d.ts +4 -4
  169. package/dist/excalidraw/actions/actionToggleStats.js +2 -1
  170. package/dist/excalidraw/actions/actionToggleViewMode.d.ts +4 -4
  171. package/dist/excalidraw/actions/actionToggleViewMode.js +2 -1
  172. package/dist/excalidraw/actions/actionToggleZenMode.d.ts +4 -4
  173. package/dist/excalidraw/actions/actionToggleZenMode.js +2 -1
  174. package/dist/excalidraw/actions/actionZindex.d.ts +23 -19
  175. package/dist/excalidraw/actions/actionZindex.js +9 -4
  176. package/dist/excalidraw/actions/manager.d.ts +5 -5
  177. package/dist/excalidraw/actions/register.d.ts +1 -1
  178. package/dist/excalidraw/actions/shortcuts.d.ts +2 -2
  179. package/dist/excalidraw/actions/types.d.ts +8 -8
  180. package/dist/excalidraw/align.d.ts +1 -1
  181. package/dist/excalidraw/animated-trail.d.ts +2 -2
  182. package/dist/excalidraw/appState.d.ts +6 -6
  183. package/dist/excalidraw/change.d.ts +191 -0
  184. package/dist/excalidraw/change.js +894 -0
  185. package/dist/excalidraw/charts.d.ts +1 -1
  186. package/dist/excalidraw/clients.d.ts +2 -2
  187. package/dist/excalidraw/clients.js +1 -1
  188. package/dist/excalidraw/clipboard.d.ts +3 -3
  189. package/dist/excalidraw/colors.d.ts +1 -1
  190. package/dist/excalidraw/components/Actions.d.ts +3 -3
  191. package/dist/excalidraw/components/Actions.js +8 -5
  192. package/dist/excalidraw/components/App.d.ts +28 -14
  193. package/dist/excalidraw/components/App.js +385 -177
  194. package/dist/excalidraw/components/ColorPicker/ColorInput.d.ts +1 -1
  195. package/dist/excalidraw/components/ColorPicker/ColorInput.js +1 -1
  196. package/dist/excalidraw/components/ColorPicker/ColorPicker.d.ts +4 -4
  197. package/dist/excalidraw/components/ColorPicker/ColorPicker.js +1 -1
  198. package/dist/excalidraw/components/ColorPicker/Picker.d.ts +3 -3
  199. package/dist/excalidraw/components/ColorPicker/PickerColorList.d.ts +1 -1
  200. package/dist/excalidraw/components/ColorPicker/PickerHeading.d.ts +1 -1
  201. package/dist/excalidraw/components/ColorPicker/ShadeList.d.ts +1 -1
  202. package/dist/excalidraw/components/ColorPicker/TopPicks.d.ts +1 -1
  203. package/dist/excalidraw/components/ColorPicker/colorPickerUtils.d.ts +2 -2
  204. package/dist/excalidraw/components/ColorPicker/colorPickerUtils.js +1 -1
  205. package/dist/excalidraw/components/ColorPicker/keyboardNavHandlers.d.ts +2 -2
  206. package/dist/excalidraw/components/ColorPicker/keyboardNavHandlers.js +1 -1
  207. package/dist/excalidraw/components/CommandPalette/CommandPalette.d.ts +1 -1
  208. package/dist/excalidraw/components/CommandPalette/CommandPalette.js +6 -5
  209. package/dist/excalidraw/components/CommandPalette/defaultCommandPaletteItems.d.ts +1 -1
  210. package/dist/excalidraw/components/CommandPalette/types.d.ts +3 -3
  211. package/dist/excalidraw/components/ConfirmDialog.d.ts +1 -1
  212. package/dist/excalidraw/components/ContextMenu.d.ts +2 -2
  213. package/dist/excalidraw/components/ContextMenu.js +1 -1
  214. package/dist/excalidraw/components/DarkModeToggle.d.ts +1 -1
  215. package/dist/excalidraw/components/DefaultSidebar.d.ts +2 -2
  216. package/dist/excalidraw/components/DialogActionButton.d.ts +1 -1
  217. package/dist/excalidraw/components/EyeDropper.d.ts +2 -2
  218. package/dist/excalidraw/components/FollowMode/FollowMode.d.ts +1 -1
  219. package/dist/excalidraw/components/HelpDialog.js +1 -1
  220. package/dist/excalidraw/components/HintViewer.d.ts +1 -1
  221. package/dist/excalidraw/components/ImageExportDialog.d.ts +1 -1
  222. package/dist/excalidraw/components/InitializeApp.d.ts +2 -2
  223. package/dist/excalidraw/components/JSONExportDialog.d.ts +3 -3
  224. package/dist/excalidraw/components/LayerUI.d.ts +4 -4
  225. package/dist/excalidraw/components/LayerUI.js +1 -1
  226. package/dist/excalidraw/components/LibraryMenu.d.ts +2 -2
  227. package/dist/excalidraw/components/LibraryMenuBrowseButton.d.ts +1 -1
  228. package/dist/excalidraw/components/LibraryMenuControlButtons.d.ts +1 -1
  229. package/dist/excalidraw/components/LibraryMenuHeaderContent.d.ts +2 -2
  230. package/dist/excalidraw/components/LibraryMenuItems.d.ts +1 -1
  231. package/dist/excalidraw/components/LibraryMenuSection.d.ts +5 -4
  232. package/dist/excalidraw/components/LibraryUnit.d.ts +2 -2
  233. package/dist/excalidraw/components/LoadingMessage.d.ts +1 -1
  234. package/dist/excalidraw/components/MagicSettings.js +2 -2
  235. package/dist/excalidraw/components/MobileMenu.d.ts +3 -3
  236. package/dist/excalidraw/components/Modal.d.ts +1 -1
  237. package/dist/excalidraw/components/OverwriteConfirm/OverwriteConfirmState.d.ts +1 -1
  238. package/dist/excalidraw/components/PasteChartDialog.d.ts +1 -1
  239. package/dist/excalidraw/components/PublishLibrary.d.ts +1 -1
  240. package/dist/excalidraw/components/SVGLayer.d.ts +1 -1
  241. package/dist/excalidraw/components/Sidebar/Sidebar.d.ts +2 -2
  242. package/dist/excalidraw/components/Sidebar/Sidebar.js +1 -1
  243. package/dist/excalidraw/components/Sidebar/SidebarTab.d.ts +1 -1
  244. package/dist/excalidraw/components/Sidebar/SidebarTabTrigger.d.ts +1 -1
  245. package/dist/excalidraw/components/Sidebar/SidebarTrigger.d.ts +1 -1
  246. package/dist/excalidraw/components/Sidebar/common.d.ts +1 -1
  247. package/dist/excalidraw/components/Stack.d.ts +2 -2
  248. package/dist/excalidraw/components/Stats.d.ts +2 -2
  249. package/dist/excalidraw/components/TTDDialog/MermaidToExcalidraw.d.ts +1 -1
  250. package/dist/excalidraw/components/TTDDialog/TTDDialog.js +2 -2
  251. package/dist/excalidraw/components/TTDDialog/TTDDialogInput.d.ts +1 -1
  252. package/dist/excalidraw/components/TTDDialog/TTDDialogPanel.d.ts +1 -1
  253. package/dist/excalidraw/components/TTDDialog/TTDDialogPanels.d.ts +1 -1
  254. package/dist/excalidraw/components/TTDDialog/TTDDialogTabs.d.ts +1 -1
  255. package/dist/excalidraw/components/TTDDialog/TTDDialogTrigger.d.ts +1 -1
  256. package/dist/excalidraw/components/TTDDialog/common.d.ts +4 -4
  257. package/dist/excalidraw/components/TextField.d.ts +1 -1
  258. package/dist/excalidraw/components/Toast.d.ts +1 -1
  259. package/dist/excalidraw/components/ToolButton.d.ts +4 -2
  260. package/dist/excalidraw/components/ToolButton.js +1 -1
  261. package/dist/excalidraw/components/Trans.d.ts +1 -1
  262. package/dist/excalidraw/components/UserList.d.ts +1 -1
  263. package/dist/excalidraw/components/canvases/InteractiveCanvas.d.ts +3 -2
  264. package/dist/excalidraw/components/canvases/InteractiveCanvas.js +3 -2
  265. package/dist/excalidraw/components/canvases/StaticCanvas.d.ts +2 -2
  266. package/dist/excalidraw/components/canvases/StaticCanvas.js +2 -2
  267. package/dist/excalidraw/components/dropdownMenu/DropdownMenuItem.js +2 -2
  268. package/dist/excalidraw/components/footer/Footer.d.ts +2 -2
  269. package/dist/excalidraw/components/hyperlink/Hyperlink.d.ts +2 -2
  270. package/dist/excalidraw/components/hyperlink/Hyperlink.js +3 -3
  271. package/dist/excalidraw/components/hyperlink/helpers.d.ts +3 -3
  272. package/dist/excalidraw/components/hyperlink/helpers.js +2 -3
  273. package/dist/excalidraw/components/icons.d.ts +4 -2
  274. package/dist/excalidraw/components/icons.js +20 -6
  275. package/dist/excalidraw/components/main-menu/DefaultItems.d.ts +1 -1
  276. package/dist/excalidraw/constants.d.ts +5 -5
  277. package/dist/excalidraw/constants.js +6 -3
  278. package/dist/excalidraw/context/ui-appState.d.ts +1 -1
  279. package/dist/excalidraw/cursor.d.ts +1 -1
  280. package/dist/excalidraw/data/EditorLocalStorage.d.ts +2 -2
  281. package/dist/excalidraw/data/blob.d.ts +5 -5
  282. package/dist/excalidraw/data/filesystem.d.ts +2 -1
  283. package/dist/excalidraw/data/index.d.ts +4 -4
  284. package/dist/excalidraw/data/json.d.ts +3 -3
  285. package/dist/excalidraw/data/library.d.ts +3 -3
  286. package/dist/excalidraw/data/magic.d.ts +3 -3
  287. package/dist/excalidraw/data/reconcile.d.ts +6 -0
  288. package/dist/excalidraw/data/reconcile.js +49 -0
  289. package/dist/excalidraw/data/resave.d.ts +2 -2
  290. package/dist/excalidraw/data/resave.js +1 -1
  291. package/dist/excalidraw/data/restore.d.ts +5 -5
  292. package/dist/excalidraw/data/restore.js +7 -7
  293. package/dist/excalidraw/data/transform.d.ts +4 -4
  294. package/dist/excalidraw/data/transform.js +4 -3
  295. package/dist/excalidraw/data/types.d.ts +3 -3
  296. package/dist/excalidraw/data/url.d.ts +1 -0
  297. package/dist/excalidraw/data/url.js +4 -1
  298. package/dist/excalidraw/element/ElementCanvasButtons.d.ts +1 -1
  299. package/dist/excalidraw/element/binding.d.ts +50 -9
  300. package/dist/excalidraw/element/binding.js +712 -155
  301. package/dist/excalidraw/element/bounds.d.ts +3 -4
  302. package/dist/excalidraw/element/bounds.js +0 -3
  303. package/dist/excalidraw/element/collision.d.ts +14 -19
  304. package/dist/excalidraw/element/collision.js +36 -713
  305. package/dist/excalidraw/element/containerCache.d.ts +1 -1
  306. package/dist/excalidraw/element/dragElements.d.ts +3 -3
  307. package/dist/excalidraw/element/embeddable.d.ts +9 -6
  308. package/dist/excalidraw/element/embeddable.js +88 -27
  309. package/dist/excalidraw/element/image.d.ts +2 -2
  310. package/dist/excalidraw/element/index.d.ts +2 -3
  311. package/dist/excalidraw/element/index.js +1 -2
  312. package/dist/excalidraw/element/linearElementEditor.d.ts +12 -12
  313. package/dist/excalidraw/element/linearElementEditor.js +7 -5
  314. package/dist/excalidraw/element/mutateElement.d.ts +4 -5
  315. package/dist/excalidraw/element/mutateElement.js +5 -3
  316. package/dist/excalidraw/element/newElement.d.ts +4 -9
  317. package/dist/excalidraw/element/newElement.js +17 -14
  318. package/dist/excalidraw/element/resizeElements.d.ts +4 -4
  319. package/dist/excalidraw/element/resizeElements.js +170 -97
  320. package/dist/excalidraw/element/resizeTest.d.ts +7 -7
  321. package/dist/excalidraw/element/resizeTest.js +53 -8
  322. package/dist/excalidraw/element/showSelectedShapeActions.d.ts +2 -2
  323. package/dist/excalidraw/element/sizeHelpers.d.ts +2 -2
  324. package/dist/excalidraw/element/sizeHelpers.js +3 -0
  325. package/dist/excalidraw/element/sortElements.d.ts +1 -1
  326. package/dist/excalidraw/element/textElement.d.ts +5 -6
  327. package/dist/excalidraw/element/textElement.js +13 -37
  328. package/dist/excalidraw/element/textWysiwyg.d.ts +10 -5
  329. package/dist/excalidraw/element/textWysiwyg.js +6 -8
  330. package/dist/excalidraw/element/transformHandles.d.ts +24 -6
  331. package/dist/excalidraw/element/transformHandles.js +22 -11
  332. package/dist/excalidraw/element/typeChecks.d.ts +4 -4
  333. package/dist/excalidraw/element/types.d.ts +30 -10
  334. package/dist/excalidraw/emitter.d.ts +1 -1
  335. package/dist/excalidraw/errors.d.ts +3 -0
  336. package/dist/excalidraw/errors.js +3 -0
  337. package/dist/excalidraw/fractionalIndex.d.ts +40 -0
  338. package/dist/excalidraw/fractionalIndex.js +241 -0
  339. package/dist/excalidraw/frame.d.ts +4 -4
  340. package/dist/excalidraw/gatransforms.d.ts +1 -1
  341. package/dist/excalidraw/gesture.d.ts +1 -1
  342. package/dist/excalidraw/groups.d.ts +5 -3
  343. package/dist/excalidraw/groups.js +17 -0
  344. package/dist/excalidraw/history.d.ts +35 -47
  345. package/dist/excalidraw/history.js +100 -167
  346. package/dist/excalidraw/hooks/useEmitter.d.ts +2 -0
  347. package/dist/excalidraw/hooks/useEmitter.js +13 -0
  348. package/dist/excalidraw/hooks/useLibraryItemSvg.d.ts +1 -1
  349. package/dist/excalidraw/i18n.d.ts +1 -1
  350. package/dist/excalidraw/index.d.ts +3 -1
  351. package/dist/excalidraw/index.js +2 -0
  352. package/dist/excalidraw/jotai.d.ts +1 -1
  353. package/dist/excalidraw/laser-trails.d.ts +3 -2
  354. package/dist/excalidraw/locales/en.json +5 -3
  355. package/dist/excalidraw/math.d.ts +2 -2
  356. package/dist/excalidraw/points.d.ts +1 -1
  357. package/dist/excalidraw/queue.d.ts +1 -1
  358. package/dist/excalidraw/renderer/helpers.d.ts +2 -2
  359. package/dist/excalidraw/renderer/interactiveScene.d.ts +2 -2
  360. package/dist/excalidraw/renderer/interactiveScene.js +8 -7
  361. package/dist/excalidraw/renderer/renderElement.d.ts +3 -3
  362. package/dist/excalidraw/renderer/renderElement.js +2 -2
  363. package/dist/excalidraw/renderer/renderSnaps.d.ts +1 -1
  364. package/dist/excalidraw/renderer/staticScene.d.ts +1 -1
  365. package/dist/excalidraw/renderer/staticScene.js +14 -3
  366. package/dist/excalidraw/renderer/staticSvgScene.d.ts +4 -4
  367. package/dist/excalidraw/renderer/staticSvgScene.js +10 -0
  368. package/dist/excalidraw/scene/Fonts.d.ts +2 -4
  369. package/dist/excalidraw/scene/Fonts.js +6 -12
  370. package/dist/excalidraw/scene/Renderer.d.ts +4 -4
  371. package/dist/excalidraw/scene/Renderer.js +2 -3
  372. package/dist/excalidraw/scene/Scene.d.ts +19 -12
  373. package/dist/excalidraw/scene/Scene.js +44 -23
  374. package/dist/excalidraw/scene/Shape.d.ts +1 -1
  375. package/dist/excalidraw/scene/ShapeCache.d.ts +5 -4
  376. package/dist/excalidraw/scene/comparisons.d.ts +2 -2
  377. package/dist/excalidraw/scene/export.d.ts +3 -3
  378. package/dist/excalidraw/scene/export.js +4 -3
  379. package/dist/excalidraw/scene/scroll.d.ts +2 -2
  380. package/dist/excalidraw/scene/scrollbars.d.ts +3 -3
  381. package/dist/excalidraw/scene/selection.d.ts +2 -2
  382. package/dist/excalidraw/scene/types.d.ts +5 -4
  383. package/dist/excalidraw/scene/zoom.d.ts +1 -1
  384. package/dist/excalidraw/snapping.d.ts +4 -4
  385. package/dist/excalidraw/store.d.ts +99 -0
  386. package/dist/excalidraw/store.js +269 -0
  387. package/dist/excalidraw/types.d.ts +33 -19
  388. package/dist/excalidraw/utils.d.ts +10 -4
  389. package/dist/excalidraw/utils.js +7 -0
  390. package/dist/excalidraw/zindex.d.ts +4 -4
  391. package/dist/excalidraw/zindex.js +9 -13
  392. package/dist/prod/{en-R7FEFJGC.json → en-GM5O55AO.json} +5 -3
  393. package/dist/prod/index.css +1 -1
  394. package/dist/prod/index.js +44 -44
  395. package/dist/utils/bbox.d.ts +2 -2
  396. package/dist/utils/collision.d.ts +4 -0
  397. package/dist/utils/collision.js +48 -0
  398. package/dist/utils/export.d.ts +1 -1
  399. package/dist/utils/geometry/geometry.d.ts +71 -0
  400. package/dist/utils/geometry/geometry.js +674 -0
  401. package/dist/utils/geometry/shape.d.ts +56 -0
  402. package/dist/utils/geometry/shape.js +168 -0
  403. package/dist/utils/withinBounds.d.ts +1 -1
  404. package/history.ts +163 -218
  405. package/package.json +2 -1
  406. package/dist/browser/dev/excalidraw-assets-dev/chunk-GPOYIZPX.js.map +0 -7
  407. package/dist/browser/dev/excalidraw-assets-dev/chunk-J5HRUYQR.js.map +0 -7
  408. package/dist/browser/dev/excalidraw-assets-dev/chunk-UETNA2WX.js.map +0 -7
  409. package/dist/browser/dev/excalidraw-assets-dev/dist-Y7S5GOTG.js +0 -10
  410. package/dist/browser/dev/excalidraw-assets-dev/image-ZNQQXS62.css.map +0 -7
  411. package/dist/browser/prod/excalidraw-assets/chunk-EEN6AFMH.js +0 -269
  412. package/dist/browser/prod/excalidraw-assets/dist-7FHVDAZ2.js +0 -1
  413. package/dist/browser/prod/excalidraw-assets/flowDiagram-v2-3b53844e-CRHRHP7H.js +0 -1
  414. package/dist/browser/prod/excalidraw-assets/image-VXYNPVOG.js +0 -1
  415. package/dist/browser/prod/excalidraw-assets/image-WE6NA2G6.css +0 -1
  416. /package/dist/browser/dev/excalidraw-assets-dev/{blockDiagram-91b80b7a-RHODGCTM.js.map → blockDiagram-91b80b7a-SWMOP5PL.js.map} +0 -0
  417. /package/dist/browser/dev/excalidraw-assets-dev/{c4Diagram-b2a90758-W7NCR7LR.js.map → c4Diagram-b2a90758-N33A4OZ7.js.map} +0 -0
  418. /package/dist/browser/dev/excalidraw-assets-dev/{chunk-TKRIVTWP.js.map → chunk-3XV32LTV.js.map} +0 -0
  419. /package/dist/browser/dev/excalidraw-assets-dev/{chunk-B2MHJWXZ.js.map → chunk-CLMTS5EY.js.map} +0 -0
  420. /package/dist/browser/dev/excalidraw-assets-dev/{chunk-QFS4M5OJ.js.map → chunk-DIDQ2KEW.js.map} +0 -0
  421. /package/dist/browser/dev/excalidraw-assets-dev/{chunk-5747M6KP.js.map → chunk-G3PHSEXY.js.map} +0 -0
  422. /package/dist/browser/dev/excalidraw-assets-dev/{chunk-PPHFJLL7.js.map → chunk-HCMMCBMX.js.map} +0 -0
  423. /package/dist/browser/dev/excalidraw-assets-dev/{chunk-DQOPSCYA.js.map → chunk-K5QPOXOQ.js.map} +0 -0
  424. /package/dist/browser/dev/excalidraw-assets-dev/{chunk-52OGG53V.js.map → chunk-KMSH7QAI.js.map} +0 -0
  425. /package/dist/browser/dev/excalidraw-assets-dev/{chunk-SLLUETBM.js.map → chunk-TVSGJBCZ.js.map} +0 -0
  426. /package/dist/browser/dev/excalidraw-assets-dev/{chunk-BESQLMCW.js.map → chunk-UONPRRXT.js.map} +0 -0
  427. /package/dist/browser/dev/excalidraw-assets-dev/{chunk-USLWOHUZ.js.map → chunk-VU32GUMX.js.map} +0 -0
  428. /package/dist/browser/dev/excalidraw-assets-dev/{chunk-GF7VCOUM.js.map → chunk-WQNNVZHO.js.map} +0 -0
  429. /package/dist/browser/dev/excalidraw-assets-dev/{chunk-GCA4S2OA.js.map → chunk-WXRCMPEJ.js.map} +0 -0
  430. /package/dist/browser/dev/excalidraw-assets-dev/{classDiagram-30eddba6-GJGBT4TV.js.map → classDiagram-30eddba6-HGXEWQY2.js.map} +0 -0
  431. /package/dist/browser/dev/excalidraw-assets-dev/{classDiagram-v2-f2df5561-LYWTIPJA.js.map → classDiagram-v2-f2df5561-ANW5DGKP.js.map} +0 -0
  432. /package/dist/browser/dev/excalidraw-assets-dev/{directory-open-01563666-UREMLRIT.js.map → directory-open-01563666-67XPRP2W.js.map} +0 -0
  433. /package/dist/browser/dev/excalidraw-assets-dev/{directory-open-4ed118d0-UN3BUDZZ.js.map → directory-open-4ed118d0-TZOVUMX3.js.map} +0 -0
  434. /package/dist/browser/dev/excalidraw-assets-dev/{dist-Y7S5GOTG.js.map → dist-JWLY7ZTC.js.map} +0 -0
  435. /package/dist/browser/dev/excalidraw-assets-dev/{en-UW5C5KGW.js.map → en-RSUSLGPV.js.map} +0 -0
  436. /package/dist/browser/dev/excalidraw-assets-dev/{erDiagram-47591fe2-Z7U2XW2Y.js.map → erDiagram-47591fe2-HB4S6KST.js.map} +0 -0
  437. /package/dist/browser/dev/excalidraw-assets-dev/{file-open-002ab408-4QG336MG.js.map → file-open-002ab408-ODQEDP24.js.map} +0 -0
  438. /package/dist/browser/dev/excalidraw-assets-dev/{file-open-7c801643-3QI4ICCL.js.map → file-open-7c801643-RPLD6WZI.js.map} +0 -0
  439. /package/dist/browser/dev/excalidraw-assets-dev/{file-save-3189631c-TNNERCWV.js.map → file-save-3189631c-63VHNBWZ.js.map} +0 -0
  440. /package/dist/browser/dev/excalidraw-assets-dev/{file-save-745eba88-JFMH565P.js.map → file-save-745eba88-SJSX6XSD.js.map} +0 -0
  441. /package/dist/browser/dev/excalidraw-assets-dev/{flowDiagram-5540d9b9-PARVG263.js.map → flowDiagram-5540d9b9-4QMRNUIV.js.map} +0 -0
  442. /package/dist/browser/dev/excalidraw-assets-dev/{flowDiagram-v2-3b53844e-ZJOPVRMB.js.map → flowDiagram-v2-3b53844e-EH5O3NBM.js.map} +0 -0
  443. /package/dist/browser/dev/excalidraw-assets-dev/{flowchart-elk-definition-5fe447d6-ULPNBSZX.js.map → flowchart-elk-definition-5fe447d6-7HGYBXUA.js.map} +0 -0
  444. /package/dist/browser/dev/excalidraw-assets-dev/{ganttDiagram-9a3bba1f-ESSYVTJ4.js.map → ganttDiagram-9a3bba1f-V5WA3IP4.js.map} +0 -0
  445. /package/dist/browser/dev/excalidraw-assets-dev/{gitGraphDiagram-96e6b4ee-6V6VVNNP.js.map → gitGraphDiagram-96e6b4ee-6JA3Z4O2.js.map} +0 -0
  446. /package/dist/browser/dev/excalidraw-assets-dev/{image-3LTGFHLF.js.map → image-GHNRJPTS.js.map} +0 -0
  447. /package/dist/browser/dev/excalidraw-assets-dev/{image-blob-reduce.esm-KTX27DAY.js.map → image-blob-reduce.esm-QYPUYIZK.js.map} +0 -0
  448. /package/dist/browser/dev/excalidraw-assets-dev/{infoDiagram-bcd20f53-I22FLFX3.js.map → infoDiagram-bcd20f53-24MBINO2.js.map} +0 -0
  449. /package/dist/browser/dev/excalidraw-assets-dev/{journeyDiagram-4fe6b3dc-WAO6F52C.js.map → journeyDiagram-4fe6b3dc-KJ4YYJII.js.map} +0 -0
  450. /package/dist/browser/dev/excalidraw-assets-dev/{katex-NWA2YFOP.js.map → katex-INYZI6LE.js.map} +0 -0
  451. /package/dist/browser/dev/excalidraw-assets-dev/{mindmap-definition-f354de21-K74IKX4Y.js.map → mindmap-definition-f354de21-VZEH45PD.js.map} +0 -0
  452. /package/dist/browser/dev/excalidraw-assets-dev/{pica-3TH2EGXR.js.map → pica-YQGHCBVI.js.map} +0 -0
  453. /package/dist/browser/dev/excalidraw-assets-dev/{pieDiagram-79897490-DOB2LVE5.js.map → pieDiagram-79897490-Z2LCRKGQ.js.map} +0 -0
  454. /package/dist/browser/dev/excalidraw-assets-dev/{quadrantDiagram-62f64e94-MJV2X7WI.js.map → quadrantDiagram-62f64e94-J3AFAFGX.js.map} +0 -0
  455. /package/dist/browser/dev/excalidraw-assets-dev/{requirementDiagram-05bf5f74-H4YM3XN7.js.map → requirementDiagram-05bf5f74-M474HB6I.js.map} +0 -0
  456. /package/dist/browser/dev/excalidraw-assets-dev/{roundRect-4S3QV2NZ.js.map → roundRect-ZCXXTYZ4.js.map} +0 -0
  457. /package/dist/browser/dev/excalidraw-assets-dev/{sankeyDiagram-97764748-7X74ABAN.js.map → sankeyDiagram-97764748-TNQP5HMX.js.map} +0 -0
  458. /package/dist/browser/dev/excalidraw-assets-dev/{sequenceDiagram-acc0e65c-PPDIJFQP.js.map → sequenceDiagram-acc0e65c-3NIA26ZM.js.map} +0 -0
  459. /package/dist/browser/dev/excalidraw-assets-dev/{stateDiagram-0ff1cf1a-JVBR7N35.js.map → stateDiagram-0ff1cf1a-V6UXRWCT.js.map} +0 -0
  460. /package/dist/browser/dev/excalidraw-assets-dev/{stateDiagram-v2-9a9d610d-QYAJLQJH.js.map → stateDiagram-v2-9a9d610d-7LTZXINB.js.map} +0 -0
  461. /package/dist/browser/dev/excalidraw-assets-dev/{timeline-definition-fea2a41d-GL7U3WDB.js.map → timeline-definition-fea2a41d-X4VGA6IX.js.map} +0 -0
  462. /package/dist/browser/dev/excalidraw-assets-dev/{xychartDiagram-ab372869-4U4JE4TW.js.map → xychartDiagram-ab372869-UQCQVK6J.js.map} +0 -0
@@ -10,32 +10,34 @@ import { ActionManager } from "../actions/manager";
10
10
  import { actions } from "../actions/register";
11
11
  import { trackEvent } from "../analytics";
12
12
  import { getDefaultAppState, isEraserActive, isHandToolActive, } from "../appState";
13
- import { copyTextToSystemClipboard, parseClipboard, } 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 { 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, } from "../constants";
15
15
  import { exportAsImage, loadFromBlob } from "../data";
16
16
  import Library, { distributeLibraryItemsOnSquareGrid } from "../data/library";
17
17
  import { restore, restoreElements } from "../data/restore";
18
- import { dragNewElement, dragSelectedElements, duplicateElement, getCommonBounds, getCursorForResizingElement, getDragOffsetXY, getElementWithTransformHandleType, getNormalizedDimensions, getResizeArrowDirection, getResizeOffsetXY, getLockedLinearCursorAlignSize, getTransformHandleTypeFromCoords, hitTest, isHittingElementBoundingBoxWithoutHittingElement, isInvisiblySmallElement, isNonDeletedElement, isTextElement, newElement, newLinearElement, newTextElement, newImageElement, transformElements, updateTextElement, redrawTextBoundingBox, } from "../element";
19
- import { bindOrUnbindLinearElement, bindOrUnbindSelectedElements, fixBindingsAfterDeletion, fixBindingsAfterDuplication, getEligibleElementsForBinding, getHoveredElementForBinding, isBindingEnabled, isLinearElementSimpleAndAlreadyBound, maybeBindLinearElement, shouldEnableBindingForPointerEvent, unbindLinearElements, updateBoundElements, } from "../element/binding";
18
+ import { dragNewElement, dragSelectedElements, duplicateElement, getCommonBounds, getCursorForResizingElement, getDragOffsetXY, getElementWithTransformHandleType, getNormalizedDimensions, getResizeArrowDirection, getResizeOffsetXY, getLockedLinearCursorAlignSize, getTransformHandleTypeFromCoords, isInvisiblySmallElement, isNonDeletedElement, isTextElement, newElement, newLinearElement, newTextElement, newImageElement, transformElements, refreshTextDimensions, redrawTextBoundingBox, getElementAbsoluteCoords, } from "../element";
19
+ import { bindOrUnbindLinearElement, bindOrUnbindLinearElements, fixBindingsAfterDeletion, fixBindingsAfterDuplication, getHoveredElementForBinding, isBindingEnabled, isLinearElementSimpleAndAlreadyBound, maybeBindLinearElement, shouldEnableBindingForPointerEvent, updateBoundElements, getSuggestedBindingsForArrows, } from "../element/binding";
20
20
  import { LinearElementEditor } from "../element/linearElementEditor";
21
21
  import { mutateElement, newElementWith } from "../element/mutateElement";
22
22
  import { deepCopyElement, duplicateElements, newFrameElement, newFreeDrawElement, newEmbeddableElement, newMagicFrameElement, newIframeElement, } from "../element/newElement";
23
- import { hasBoundTextElement, isArrowElement, isBindingElement, isBindingElementType, isBoundToContainer, isFrameLikeElement, isImageElement, isEmbeddableElement, isInitializedImageElement, isLinearElement, isLinearElementType, isUsingAdaptiveRadius, isFrameElement, isIframeElement, isIframeLikeElement, isMagicFrameElement, } from "../element/typeChecks";
23
+ import { hasBoundTextElement, isArrowElement, isBindingElement, isBindingElementType, isBoundToContainer, isFrameLikeElement, isImageElement, isEmbeddableElement, isInitializedImageElement, isLinearElement, isLinearElementType, isUsingAdaptiveRadius, isFrameElement, isIframeElement, isIframeLikeElement, isMagicFrameElement, isTextBindableContainer, } from "../element/typeChecks";
24
24
  import { getCenter, getDistance } from "../gesture";
25
25
  import { editGroupForSelectedElement, getElementsInGroup, getSelectedGroupIdForElement, getSelectedGroupIds, isElementInGroup, isSelectedViaGroup, selectGroupsForSelectedElements, } from "../groups";
26
- import History from "../history";
26
+ import { History } from "../history";
27
27
  import { defaultLang, getLanguage, languages, setLanguage, t } from "../i18n";
28
28
  import { CODES, shouldResizeFromCenter, shouldMaintainAspectRatio, shouldRotateWithDiscreteAngle, isArrowKey, KEYS, } from "../keys";
29
29
  import { isElementInViewport } from "../element/sizeHelpers";
30
30
  import { distance2d, getCornerRadius, getGridPoint, isPathALoop, } from "../math";
31
31
  import { clearRenderCache } from "../renderer/renderElement";
32
- import { calculateScrollCenter, getElementsAtPosition, getElementsWithinSelection, getNormalizedZoom, getSelectedElements, hasBackground, isSomeElementSelected, } from "../scene";
32
+ import { calculateScrollCenter, getElementsWithinSelection, getNormalizedZoom, getSelectedElements, hasBackground, isSomeElementSelected, } from "../scene";
33
33
  import Scene from "../scene/Scene";
34
34
  import { getStateForZoom } from "../scene/zoom";
35
35
  import { findShapeByKey } from "../shapes";
36
- import { debounce, distance, getFontString, getNearestScrollableContainer, isInputLike, isToolIcon, isWritableElement, sceneCoordsToViewportCoords, tupleToCoors, viewportCoordsToSceneCoords, wrapEvent, updateObject, updateActiveTool, getShortcutKey, isTransparent, easeToValuesRAF, muteFSAbortError, isTestEnv, easeOut, updateStable, addEventListener, normalizeEOL, getDateTime, } from "../utils";
36
+ import { getClosedCurveShape, getCurveShape, getEllipseShape, getFreedrawShape, getPolygonShape, getSelectionBoxShape, } from "../../utils/geometry/shape";
37
+ import { isPointInShape } from "../../utils/collision";
38
+ import { debounce, distance, getFontString, getNearestScrollableContainer, isInputLike, isToolIcon, isWritableElement, sceneCoordsToViewportCoords, tupleToCoors, viewportCoordsToSceneCoords, wrapEvent, updateObject, updateActiveTool, getShortcutKey, isTransparent, easeToValuesRAF, muteFSAbortError, isTestEnv, easeOut, updateStable, addEventListener, normalizeEOL, getDateTime, isShallowEqual, arrayToMap, } from "../utils";
37
39
  import { createSrcDoc, embeddableURLValidator, maybeParseEmbedSrc, getEmbedLink, } from "../element/embeddable";
38
- import { ContextMenu, CONTEXT_MENU_SEPARATOR, } from "./ContextMenu";
40
+ import { ContextMenu, CONTEXT_MENU_SEPARATOR } from "./ContextMenu";
39
41
  import LayerUI from "./LayerUI";
40
42
  import { Toast } from "./Toast";
41
43
  import { actionToggleViewMode } from "../actions/actionToggleViewMode";
@@ -43,8 +45,7 @@ import { dataURLToFile, generateIdFromFile, getDataURL, getFileFromEvent, ImageU
43
45
  import { getInitializedImageElements, loadHTMLImageElement, normalizeSVG, updateImageCache as _updateImageCache, } from "../element/image";
44
46
  import throttle from "lodash.throttle";
45
47
  import { fileOpen } from "../data/filesystem";
46
- import { bindTextToShapeAfterDuplication, getApproxMinLineHeight, getApproxMinLineWidth, getBoundTextElement, getContainerCenter, getContainerElement, getDefaultLineHeight, getLineHeightInPx, getTextBindableContainerAtPosition, isMeasureTextSupported, isValidTextContainer, } from "../element/textElement";
47
- import { isHittingElementNotConsideringBoundingBox } from "../element/collision";
48
+ import { bindTextToShapeAfterDuplication, getApproxMinLineHeight, getApproxMinLineWidth, getBoundTextElement, getContainerCenter, getContainerElement, getDefaultLineHeight, getLineHeightInPx, isMeasureTextSupported, isValidTextContainer, } 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,15 +79,19 @@ 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";
88
+ import { hitElementBoundText, hitElementBoundingBoxOnly, hitElementItself, shouldTestInside, } from "../element/collision";
86
89
  import { textWysiwyg } from "../element/textWysiwyg";
87
90
  import { isOverScrollBars } from "../scene/scrollbars";
91
+ import { syncInvalidIndices, syncMovedIndices } from "../fractionalIndex";
88
92
  import { isPointHittingLink, isPointHittingLinkIcon, } from "./hyperlink/helpers";
89
93
  import { getShortcutFromShortcutName } from "../actions/shortcuts";
94
+ import { actionTextAutoResize } from "../actions/actionTextAutoResize";
90
95
  const AppContext = React.createContext(null);
91
96
  const AppPropsContext = React.createContext(null);
92
97
  const deviceContextInitialValue = {
@@ -166,6 +171,7 @@ class App extends React.Component {
166
171
  library;
167
172
  libraryItemsFromStorage;
168
173
  id;
174
+ store;
169
175
  history;
170
176
  excalidrawContainerValue;
171
177
  files = {};
@@ -237,6 +243,8 @@ class App extends React.Component {
237
243
  this.canvas = document.createElement("canvas");
238
244
  this.rc = rough.canvas(this.canvas);
239
245
  this.renderer = new Renderer(this.scene);
246
+ this.store = new Store();
247
+ this.history = new History();
240
248
  if (excalidrawAPI) {
241
249
  const api = {
242
250
  updateScene: this.updateScene,
@@ -281,14 +289,11 @@ class App extends React.Component {
281
289
  container: this.excalidrawContainerRef.current,
282
290
  id: this.id,
283
291
  };
284
- this.fonts = new Fonts({
285
- scene: this.scene,
286
- onSceneUpdated: this.onSceneUpdated,
287
- });
292
+ this.fonts = new Fonts({ scene: this.scene });
288
293
  this.history = new History();
289
294
  this.actionManager.registerAll(actions);
290
- this.actionManager.registerAction(createUndoAction(this.history));
291
- this.actionManager.registerAction(createRedoAction(this.history));
295
+ this.actionManager.registerAction(createUndoAction(this.history, this.store));
296
+ this.actionManager.registerAction(createRedoAction(this.history, this.store));
292
297
  }
293
298
  onWindowMessage(event) {
294
299
  if (event.origin !== "https://player.vimeo.com" &&
@@ -439,7 +444,7 @@ class App extends React.Component {
439
444
  return false;
440
445
  });
441
446
  if (updated) {
442
- this.scene.informMutation();
447
+ this.scene.triggerUpdate();
443
448
  }
444
449
  // GC
445
450
  this.iFrameRefs.forEach((ref, id) => {
@@ -798,9 +803,9 @@ class App extends React.Component {
798
803
  render() {
799
804
  const selectedElements = this.scene.getSelectedElements(this.state);
800
805
  const { renderTopRightUI, renderCustomStats } = this.props;
801
- const versionNonce = this.scene.getVersionNonce();
806
+ const sceneNonce = this.scene.getSceneNonce();
802
807
  const { elementsMap, visibleElements } = this.renderer.getRenderableElements({
803
- versionNonce,
808
+ sceneNonce,
804
809
  zoom: this.state.zoom,
805
810
  offsetLeft: this.state.offsetLeft,
806
811
  offsetTop: this.state.offsetTop,
@@ -872,14 +877,14 @@ class App extends React.Component {
872
877
  this.focusContainer();
873
878
  callback?.();
874
879
  });
875
- } })), _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: {
880
+ } })), _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: {
876
881
  imageCache: this.imageCache,
877
882
  isExporting: false,
878
883
  renderGrid: true,
879
884
  canvasBackgroundColor: this.state.viewBackgroundColor,
880
885
  embedsValidationStatus: this.embedsValidationStatus,
881
886
  elementsPendingErasure: this.elementsPendingErasure,
882
- } }), _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()] }) }) }) }) }) }) }) }));
887
+ } }), _jsx(InteractiveCanvas, { containerRef: this.excalidrawContainerRef, canvas: this.interactiveCanvas, elementsMap: elementsMap, visibleElements: visibleElements, 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()] }) }) }) }) }) }) }) }));
883
888
  }
884
889
  focusContainer = () => {
885
890
  this.excalidrawContainerRef.current?.focus();
@@ -937,7 +942,7 @@ class App extends React.Component {
937
942
  mutateElement(frameElement, { customData: { generationData: data } }, false);
938
943
  }
939
944
  this.magicGenerations.set(frameElement.id, data);
940
- this.onSceneUpdated();
945
+ this.triggerRender();
941
946
  };
942
947
  getTextFromElements(elements) {
943
948
  const text = elements
@@ -1139,7 +1144,7 @@ class App extends React.Component {
1139
1144
  opacity: 100,
1140
1145
  locked: false,
1141
1146
  });
1142
- this.scene.addNewElement(frame);
1147
+ this.scene.insertElement(frame);
1143
1148
  for (const child of selectedElements) {
1144
1149
  mutateElement(child, { frameId: frame.id });
1145
1150
  }
@@ -1163,13 +1168,13 @@ class App extends React.Component {
1163
1168
  if (shouldUpdateStrokeColor) {
1164
1169
  this.syncActionResult({
1165
1170
  appState: { ...this.state, currentItemStrokeColor: color },
1166
- commitToHistory: true,
1171
+ storeAction: StoreAction.CAPTURE,
1167
1172
  });
1168
1173
  }
1169
1174
  else {
1170
1175
  this.syncActionResult({
1171
1176
  appState: { ...this.state, currentItemBackgroundColor: color },
1172
- commitToHistory: true,
1177
+ storeAction: StoreAction.CAPTURE,
1173
1178
  });
1174
1179
  }
1175
1180
  }
@@ -1183,6 +1188,7 @@ class App extends React.Component {
1183
1188
  }
1184
1189
  return el;
1185
1190
  }),
1191
+ storeAction: StoreAction.CAPTURE,
1186
1192
  });
1187
1193
  }
1188
1194
  },
@@ -1202,10 +1208,13 @@ class App extends React.Component {
1202
1208
  editingElement = element;
1203
1209
  }
1204
1210
  });
1205
- this.scene.replaceAllElements(actionResult.elements);
1206
- if (actionResult.commitToHistory) {
1207
- this.history.resumeRecording();
1211
+ if (actionResult.storeAction === StoreAction.UPDATE) {
1212
+ this.store.shouldUpdateSnapshot();
1213
+ }
1214
+ else if (actionResult.storeAction === StoreAction.CAPTURE) {
1215
+ this.store.shouldCaptureIncrement();
1208
1216
  }
1217
+ this.scene.replaceAllElements(actionResult.elements);
1209
1218
  }
1210
1219
  if (actionResult.files) {
1211
1220
  this.files = actionResult.replaceFiles
@@ -1214,8 +1223,11 @@ class App extends React.Component {
1214
1223
  this.addNewImagesToImageCache();
1215
1224
  }
1216
1225
  if (actionResult.appState || editingElement || this.state.contextMenu) {
1217
- if (actionResult.commitToHistory) {
1218
- this.history.resumeRecording();
1226
+ if (actionResult.storeAction === StoreAction.UPDATE) {
1227
+ this.store.shouldUpdateSnapshot();
1228
+ }
1229
+ else if (actionResult.storeAction === StoreAction.CAPTURE) {
1230
+ this.store.shouldCaptureIncrement();
1219
1231
  }
1220
1232
  let viewModeEnabled = actionResult?.appState?.viewModeEnabled || false;
1221
1233
  let zenModeEnabled = actionResult?.appState?.zenModeEnabled || false;
@@ -1254,10 +1266,6 @@ class App extends React.Component {
1254
1266
  name,
1255
1267
  errorMessage,
1256
1268
  });
1257
- }, () => {
1258
- if (actionResult.syncHistory) {
1259
- this.history.setCurrentState(this.state, this.scene.getElementsIncludingDeleted());
1260
- }
1261
1269
  });
1262
1270
  }
1263
1271
  });
@@ -1275,6 +1283,9 @@ class App extends React.Component {
1275
1283
  resetHistory = () => {
1276
1284
  this.history.clear();
1277
1285
  };
1286
+ resetStore = () => {
1287
+ this.store.clear();
1288
+ };
1278
1289
  /**
1279
1290
  * Resets scene & history.
1280
1291
  * ! Do not use to clear scene user action !
@@ -1286,6 +1297,7 @@ class App extends React.Component {
1286
1297
  isLoading: opts?.resetLoadingState ? false : state.isLoading,
1287
1298
  theme: this.state.theme,
1288
1299
  }));
1300
+ this.resetStore();
1289
1301
  this.resetHistory();
1290
1302
  });
1291
1303
  initializeScene = async () => {
@@ -1360,6 +1372,7 @@ class App extends React.Component {
1360
1372
  // text elements on canvas, and rerender them once done. This also
1361
1373
  // seems faster even in browsers that do fire the loadingdone event.
1362
1374
  this.fonts.loadFontsForElements(scene.elements);
1375
+ this.resetStore();
1363
1376
  if (initialData?.scrollX != null) {
1364
1377
  scene.appState.scrollX = initialData.scrollX;
1365
1378
  }
@@ -1369,7 +1382,7 @@ class App extends React.Component {
1369
1382
  this.resetHistory();
1370
1383
  this.syncActionResult({
1371
1384
  ...scene,
1372
- commitToHistory: true,
1385
+ storeAction: StoreAction.UPDATE,
1373
1386
  });
1374
1387
  };
1375
1388
  isMobileBreakpoint = (width, height) => {
@@ -1440,9 +1453,16 @@ class App extends React.Component {
1440
1453
  configurable: true,
1441
1454
  value: this.history,
1442
1455
  },
1456
+ store: {
1457
+ configurable: true,
1458
+ value: this.store,
1459
+ },
1443
1460
  });
1444
1461
  }
1445
- this.scene.addCallback(this.onSceneUpdated);
1462
+ this.store.onStoreIncrementEmitter.on((increment) => {
1463
+ this.history.record(increment.elementsChange, increment.appStateChange);
1464
+ });
1465
+ this.scene.onUpdate(this.triggerRender);
1446
1466
  this.addEventListeners();
1447
1467
  if (this.props.autoFocus && this.excalidrawContainerRef.current) {
1448
1468
  this.focusContainer();
@@ -1480,6 +1500,7 @@ class App extends React.Component {
1480
1500
  componentWillUnmount() {
1481
1501
  this.renderer.destroy();
1482
1502
  this.scene = new Scene();
1503
+ this.fonts = new Fonts({ scene: this.scene });
1483
1504
  this.renderer = new Renderer(this.scene);
1484
1505
  this.files = {};
1485
1506
  this.imageCache.clear();
@@ -1491,6 +1512,7 @@ class App extends React.Component {
1491
1512
  this.laserTrails.stop();
1492
1513
  this.eraserTrail.stop();
1493
1514
  this.onChangeEmitter.clear();
1515
+ this.store.onStoreIncrementEmitter.clear();
1494
1516
  ShapeCache.destroy();
1495
1517
  SnapCache.destroy();
1496
1518
  clearRenderCache();
@@ -1574,7 +1596,8 @@ class App extends React.Component {
1574
1596
  componentDidUpdate(prevProps, prevState) {
1575
1597
  this.updateEmbeddables();
1576
1598
  const elements = this.scene.getElementsIncludingDeleted();
1577
- const elementsMap = this.scene.getNonDeletedElementsMap();
1599
+ const elementsMap = this.scene.getElementsMapIncludingDeleted();
1600
+ const nonDeletedElementsMap = this.scene.getNonDeletedElementsMap();
1578
1601
  if (!this.state.showWelcomeScreen && !elements.length) {
1579
1602
  this.setState({ showWelcomeScreen: true });
1580
1603
  }
@@ -1660,7 +1683,7 @@ class App extends React.Component {
1660
1683
  this.excalidrawContainerRef.current?.classList.toggle("theme--dark", this.state.theme === THEME.DARK);
1661
1684
  if (this.state.editingLinearElement &&
1662
1685
  !this.state.selectedElementIds[this.state.editingLinearElement.elementId]) {
1663
- // defer so that the commitToHistory flag isn't reset via current update
1686
+ // defer so that the storeAction flag isn't reset via current update
1664
1687
  setTimeout(() => {
1665
1688
  // execute only if the condition still holds when the deferred callback
1666
1689
  // executes (it can be scheduled multiple times depending on how
@@ -1685,9 +1708,9 @@ class App extends React.Component {
1685
1708
  multiElement != null &&
1686
1709
  isBindingEnabled(this.state) &&
1687
1710
  isBindingElement(multiElement, false)) {
1688
- maybeBindLinearElement(multiElement, this.state, this.scene, tupleToCoors(LinearElementEditor.getPointAtIndexGlobalCoordinates(multiElement, -1, elementsMap)), elementsMap);
1711
+ maybeBindLinearElement(multiElement, this.state, tupleToCoors(LinearElementEditor.getPointAtIndexGlobalCoordinates(multiElement, -1, nonDeletedElementsMap)), this);
1689
1712
  }
1690
- this.history.record(this.state, elements);
1713
+ this.store.commit(elementsMap, this.state);
1691
1714
  // Do not notify consumers if we're still loading the scene. Among other
1692
1715
  // potential issues, this fixes a case where the tab isn't focused during
1693
1716
  // init, which would trigger onChange with empty elements, which would then
@@ -1952,16 +1975,15 @@ class App extends React.Component {
1952
1975
  }), {
1953
1976
  randomizeSeed: !opts.retainSeed,
1954
1977
  });
1955
- const allElements = [
1956
- ...this.scene.getElementsIncludingDeleted(),
1957
- ...newElements,
1958
- ];
1978
+ const prevElements = this.scene.getElementsIncludingDeleted();
1979
+ const nextElements = [...prevElements, ...newElements];
1980
+ syncMovedIndices(nextElements, arrayToMap(newElements));
1959
1981
  const topLayerFrame = this.getTopLayerFrameAtSceneCoords({ x, y });
1960
1982
  if (topLayerFrame) {
1961
1983
  const eligibleElements = filterElementsEligibleAsFrameChildren(newElements, topLayerFrame);
1962
- addElementsToFrame(allElements, eligibleElements, topLayerFrame);
1984
+ addElementsToFrame(nextElements, eligibleElements, topLayerFrame);
1963
1985
  }
1964
- this.scene.replaceAllElements(allElements);
1986
+ this.scene.replaceAllElements(nextElements);
1965
1987
  newElements.forEach((newElement) => {
1966
1988
  if (isTextElement(newElement) && isBoundToContainer(newElement)) {
1967
1989
  const container = getContainerElement(newElement, this.scene.getElementsMapIncludingDeleted());
@@ -1971,7 +1993,7 @@ class App extends React.Component {
1971
1993
  if (opts.files) {
1972
1994
  this.files = { ...this.files, ...opts.files };
1973
1995
  }
1974
- this.history.resumeRecording();
1996
+ this.store.shouldCaptureIncrement();
1975
1997
  const nextElementsToSelect = excludeElementsInFramesFromSelection(newElements);
1976
1998
  this.setState({
1977
1999
  ...this.state,
@@ -2129,16 +2151,7 @@ class App extends React.Component {
2129
2151
  if (textElements.length === 0) {
2130
2152
  return;
2131
2153
  }
2132
- const frameId = textElements[0].frameId;
2133
- if (frameId) {
2134
- this.scene.insertElementsAtIndex(textElements, this.scene.getElementIndex(frameId));
2135
- }
2136
- else {
2137
- this.scene.replaceAllElements([
2138
- ...this.scene.getElementsIncludingDeleted(),
2139
- ...textElements,
2140
- ]);
2141
- }
2154
+ this.scene.insertElements(textElements);
2142
2155
  this.setState({
2143
2156
  selectedElementIds: makeNextSelectedElementIds(Object.fromEntries(textElements.map((el) => [el.id, true])), this.state),
2144
2157
  });
@@ -2154,7 +2167,7 @@ class App extends React.Component {
2154
2167
  });
2155
2168
  PLAIN_PASTE_TOAST_SHOWN = true;
2156
2169
  }
2157
- this.history.resumeRecording();
2170
+ this.store.shouldCaptureIncrement();
2158
2171
  }
2159
2172
  setAppState = (state, callback) => {
2160
2173
  this.setState(state, callback);
@@ -2336,24 +2349,41 @@ class App extends React.Component {
2336
2349
  ShapeCache.delete(element);
2337
2350
  }
2338
2351
  });
2339
- this.scene.informMutation();
2352
+ this.scene.triggerUpdate();
2340
2353
  this.addNewImagesToImageCache();
2341
2354
  });
2342
2355
  updateScene = withBatchedUpdates((sceneData) => {
2343
- if (sceneData.commitToHistory) {
2344
- this.history.resumeRecording();
2356
+ const nextElements = syncInvalidIndices(sceneData.elements ?? []);
2357
+ if (sceneData.storeAction && sceneData.storeAction !== StoreAction.NONE) {
2358
+ const prevCommittedAppState = this.store.snapshot.appState;
2359
+ const prevCommittedElements = this.store.snapshot.elements;
2360
+ const nextCommittedAppState = sceneData.appState
2361
+ ? Object.assign({}, prevCommittedAppState, sceneData.appState) // new instance, with partial appstate applied to previously captured one, including hidden prop inside `prevCommittedAppState`
2362
+ : prevCommittedAppState;
2363
+ const nextCommittedElements = sceneData.elements
2364
+ ? this.store.filterUncomittedElements(this.scene.getElementsMapIncludingDeleted(), // Only used to detect uncomitted local elements
2365
+ arrayToMap(nextElements))
2366
+ : prevCommittedElements;
2367
+ // 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
2368
+ // do NOT schedule store actions (execute after re-render), as it might cause unexpected concurrency issues if not handled well
2369
+ if (sceneData.storeAction === StoreAction.CAPTURE) {
2370
+ this.store.captureIncrement(nextCommittedElements, nextCommittedAppState);
2371
+ }
2372
+ else if (sceneData.storeAction === StoreAction.UPDATE) {
2373
+ this.store.updateSnapshot(nextCommittedElements, nextCommittedAppState);
2374
+ }
2345
2375
  }
2346
2376
  if (sceneData.appState) {
2347
2377
  this.setState(sceneData.appState);
2348
2378
  }
2349
2379
  if (sceneData.elements) {
2350
- this.scene.replaceAllElements(sceneData.elements);
2380
+ this.scene.replaceAllElements(nextElements);
2351
2381
  }
2352
2382
  if (sceneData.collaborators) {
2353
2383
  this.setState({ collaborators: sceneData.collaborators });
2354
2384
  }
2355
2385
  });
2356
- onSceneUpdated = () => {
2386
+ triggerRender = () => {
2357
2387
  this.setState({});
2358
2388
  };
2359
2389
  /**
@@ -2521,7 +2551,9 @@ class App extends React.Component {
2521
2551
  simultaneouslyUpdated: selectedElements,
2522
2552
  });
2523
2553
  });
2524
- this.maybeSuggestBindingForAll(selectedElements);
2554
+ this.setState({
2555
+ suggestedBindings: getSuggestedBindingsForArrows(selectedElements, this),
2556
+ });
2525
2557
  event.preventDefault();
2526
2558
  }
2527
2559
  else if (event.key === KEYS.ENTER) {
@@ -2533,7 +2565,7 @@ class App extends React.Component {
2533
2565
  if (!this.state.editingLinearElement ||
2534
2566
  this.state.editingLinearElement.elementId !==
2535
2567
  selectedElements[0].id) {
2536
- this.history.resumeRecording();
2568
+ this.store.shouldCaptureIncrement();
2537
2569
  this.setState({
2538
2570
  editingLinearElement: new LinearElementEditor(selectedElement),
2539
2571
  });
@@ -2659,11 +2691,7 @@ class App extends React.Component {
2659
2691
  this.setState({ isBindingEnabled: true });
2660
2692
  }
2661
2693
  if (isArrowKey(event.key)) {
2662
- const selectedElements = this.scene.getSelectedElements(this.state);
2663
- const elementsMap = this.scene.getNonDeletedElementsMap();
2664
- isBindingEnabled(this.state)
2665
- ? bindOrUnbindSelectedElements(selectedElements, this.scene.getNonDeletedElements(), elementsMap)
2666
- : unbindLinearElements(selectedElements, elementsMap);
2694
+ bindOrUnbindLinearElements(this.scene.getSelectedElements(this.state).filter(isLinearElement), this, isBindingEnabled(this.state), this.state.selectedLinearElement?.selectedPointsIndices ?? []);
2667
2695
  this.setState({ suggestedBindings: [] });
2668
2696
  }
2669
2697
  });
@@ -2695,6 +2723,9 @@ class App extends React.Component {
2695
2723
  originSnapOffset: null,
2696
2724
  activeEmbeddable: null,
2697
2725
  };
2726
+ if (nextActiveTool.type === "freedraw") {
2727
+ this.store.shouldCaptureIncrement();
2728
+ }
2698
2729
  let nextState;
2699
2730
  if (nextActiveTool.type !== "selection") {
2700
2731
  nextState = {
@@ -2811,15 +2842,16 @@ class App extends React.Component {
2811
2842
  });
2812
2843
  handleTextWysiwyg(element, { isExistingElement = false, }) {
2813
2844
  const elementsMap = this.scene.getElementsMapIncludingDeleted();
2814
- const updateElement = (text, originalText, isDeleted) => {
2845
+ const updateElement = (nextOriginalText, isDeleted) => {
2815
2846
  this.scene.replaceAllElements([
2816
2847
  // Not sure why we include deleted elements as well hence using deleted elements map
2817
2848
  ...this.scene.getElementsIncludingDeleted().map((_element) => {
2818
2849
  if (_element.id === element.id && isTextElement(_element)) {
2819
- return updateTextElement(_element, getContainerElement(_element, elementsMap), elementsMap, {
2820
- text,
2821
- isDeleted,
2822
- originalText,
2850
+ return newElementWith(_element, {
2851
+ originalText: nextOriginalText,
2852
+ isDeleted: isDeleted ?? _element.isDeleted,
2853
+ // returns (wrapped) text and new dimensions
2854
+ ...refreshTextDimensions(_element, getContainerElement(_element, elementsMap), elementsMap, nextOriginalText),
2823
2855
  });
2824
2856
  }
2825
2857
  return _element;
@@ -2839,15 +2871,15 @@ class App extends React.Component {
2839
2871
  viewportY - this.state.offsetTop,
2840
2872
  ];
2841
2873
  },
2842
- onChange: withBatchedUpdates((text) => {
2843
- updateElement(text, text, false);
2874
+ onChange: withBatchedUpdates((nextOriginalText) => {
2875
+ updateElement(nextOriginalText, false);
2844
2876
  if (isNonDeletedElement(element)) {
2845
2877
  updateBoundElements(element, elementsMap);
2846
2878
  }
2847
2879
  }),
2848
- onSubmit: withBatchedUpdates(({ text, viaKeyboard, originalText }) => {
2849
- const isDeleted = !text.trim();
2850
- updateElement(text, originalText, isDeleted);
2880
+ onSubmit: withBatchedUpdates(({ viaKeyboard, nextOriginalText }) => {
2881
+ const isDeleted = !nextOriginalText.trim();
2882
+ updateElement(nextOriginalText, isDeleted);
2851
2883
  // select the created text element only if submitting via keyboard
2852
2884
  // (when submitting via click it should act as signal to deselect)
2853
2885
  if (!isDeleted && viaKeyboard) {
@@ -2867,7 +2899,7 @@ class App extends React.Component {
2867
2899
  ]);
2868
2900
  }
2869
2901
  if (!isDeleted || isExistingElement) {
2870
- this.history.resumeRecording();
2902
+ this.store.shouldCaptureIncrement();
2871
2903
  }
2872
2904
  this.setState({
2873
2905
  draggingElement: null,
@@ -2886,7 +2918,7 @@ class App extends React.Component {
2886
2918
  this.deselectElements();
2887
2919
  // do an initial update to re-initialize element position since we were
2888
2920
  // modifying element's x/y for sake of editor (case: syncing to remote)
2889
- updateElement(element.text, element.originalText, false);
2921
+ updateElement(element.originalText, false);
2890
2922
  }
2891
2923
  deselectElements() {
2892
2924
  this.setState({
@@ -2905,6 +2937,57 @@ class App extends React.Component {
2905
2937
  }
2906
2938
  return null;
2907
2939
  }
2940
+ /**
2941
+ * get the pure geometric shape of an excalidraw element
2942
+ * which is then used for hit detection
2943
+ */
2944
+ getElementShape(element) {
2945
+ switch (element.type) {
2946
+ case "rectangle":
2947
+ case "diamond":
2948
+ case "frame":
2949
+ case "magicframe":
2950
+ case "embeddable":
2951
+ case "image":
2952
+ case "iframe":
2953
+ case "text":
2954
+ case "selection":
2955
+ return getPolygonShape(element);
2956
+ case "arrow":
2957
+ case "line": {
2958
+ const roughShape = ShapeCache.get(element)?.[0] ??
2959
+ ShapeCache.generateElementShape(element, null)[0];
2960
+ const [, , , , cx, cy] = getElementAbsoluteCoords(element, this.scene.getNonDeletedElementsMap());
2961
+ return shouldTestInside(element)
2962
+ ? getClosedCurveShape(element, roughShape, [element.x, element.y], element.angle, [cx, cy])
2963
+ : getCurveShape(roughShape, [element.x, element.y], element.angle, [
2964
+ cx,
2965
+ cy,
2966
+ ]);
2967
+ }
2968
+ case "ellipse":
2969
+ return getEllipseShape(element);
2970
+ case "freedraw": {
2971
+ const [, , , , cx, cy] = getElementAbsoluteCoords(element, this.scene.getNonDeletedElementsMap());
2972
+ return getFreedrawShape(element, [cx, cy], shouldTestInside(element));
2973
+ }
2974
+ }
2975
+ }
2976
+ getBoundTextShape(element) {
2977
+ const boundTextElement = getBoundTextElement(element, this.scene.getNonDeletedElementsMap());
2978
+ if (boundTextElement) {
2979
+ if (element.type === "arrow") {
2980
+ return this.getElementShape({
2981
+ ...boundTextElement,
2982
+ // arrow's bound text accurate position is not stored in the element's property
2983
+ // but rather calculated and returned from the following static method
2984
+ ...LinearElementEditor.getBoundTextElementPosition(element, boundTextElement, this.scene.getNonDeletedElementsMap()),
2985
+ });
2986
+ }
2987
+ return this.getElementShape(boundTextElement);
2988
+ }
2989
+ return null;
2990
+ }
2908
2991
  getElementAtPosition(x, y, opts) {
2909
2992
  const allHitElements = this.getElementsAtPosition(x, y, opts?.includeBoundTextElement, opts?.includeLockedElements);
2910
2993
  if (allHitElements.length > 1) {
@@ -2918,9 +3001,20 @@ class App extends React.Component {
2918
3001
  const elementWithHighestZIndex = allHitElements[allHitElements.length - 1];
2919
3002
  // If we're hitting element with highest z-index only on its bounding box
2920
3003
  // while also hitting other element figure, the latter should be considered.
2921
- return isHittingElementBoundingBoxWithoutHittingElement(elementWithHighestZIndex, this.state, this.frameNameBoundsCache, x, y, this.scene.getNonDeletedElementsMap())
2922
- ? allHitElements[allHitElements.length - 2]
2923
- : elementWithHighestZIndex;
3004
+ return hitElementItself({
3005
+ x,
3006
+ y,
3007
+ element: elementWithHighestZIndex,
3008
+ shape: this.getElementShape(elementWithHighestZIndex),
3009
+ // when overlapping, we would like to be more precise
3010
+ // this also avoids the need to update past tests
3011
+ threshold: this.getElementHitThreshold() / 2,
3012
+ frameNameBound: isFrameLikeElement(elementWithHighestZIndex)
3013
+ ? this.frameNameBoundsCache.get(elementWithHighestZIndex)
3014
+ : null,
3015
+ })
3016
+ ? elementWithHighestZIndex
3017
+ : allHitElements[allHitElements.length - 2];
2924
3018
  }
2925
3019
  if (allHitElements.length === 1) {
2926
3020
  return allHitElements[0];
@@ -2928,15 +3022,17 @@ class App extends React.Component {
2928
3022
  return null;
2929
3023
  }
2930
3024
  getElementsAtPosition(x, y, includeBoundTextElement = false, includeLockedElements = false) {
2931
- const elements = includeBoundTextElement && includeLockedElements
3025
+ const iframeLikes = [];
3026
+ const elementsMap = this.scene.getNonDeletedElementsMap();
3027
+ const elements = (includeBoundTextElement && includeLockedElements
2932
3028
  ? this.scene.getNonDeletedElements()
2933
3029
  : this.scene
2934
3030
  .getNonDeletedElements()
2935
3031
  .filter((element) => (includeLockedElements || !element.locked) &&
2936
3032
  (includeBoundTextElement ||
2937
- !(isTextElement(element) && element.containerId)));
2938
- const elementsMap = this.scene.getNonDeletedElementsMap();
2939
- return getElementsAtPosition(elements, (element) => hitTest(element, this.state, this.frameNameBoundsCache, x, y, elementsMap)).filter((element) => {
3033
+ !(isTextElement(element) && element.containerId))))
3034
+ .filter((el) => this.hitElement(x, y, el))
3035
+ .filter((element) => {
2940
3036
  // hitting a frame's element from outside the frame is not considered a hit
2941
3037
  const containingFrame = getContainingFrame(element, elementsMap);
2942
3038
  return containingFrame &&
@@ -2944,8 +3040,81 @@ class App extends React.Component {
2944
3040
  this.state.frameRendering.clip
2945
3041
  ? isCursorInFrame({ x, y }, containingFrame, elementsMap)
2946
3042
  : true;
3043
+ })
3044
+ .filter((el) => {
3045
+ // The parameter elements comes ordered from lower z-index to higher.
3046
+ // We want to preserve that order on the returned array.
3047
+ // Exception being embeddables which should be on top of everything else in
3048
+ // terms of hit testing.
3049
+ if (isIframeElement(el)) {
3050
+ iframeLikes.push(el);
3051
+ return false;
3052
+ }
3053
+ return true;
3054
+ })
3055
+ .concat(iframeLikes);
3056
+ return elements;
3057
+ }
3058
+ getElementHitThreshold() {
3059
+ return DEFAULT_COLLISION_THRESHOLD / this.state.zoom.value;
3060
+ }
3061
+ hitElement(x, y, element, considerBoundingBox = true) {
3062
+ // if the element is selected, then hit test is done against its bounding box
3063
+ if (considerBoundingBox &&
3064
+ this.state.selectedElementIds[element.id] &&
3065
+ shouldShowBoundingBox([element], this.state)) {
3066
+ const selectionShape = getSelectionBoxShape(element, this.scene.getNonDeletedElementsMap(), this.getElementHitThreshold());
3067
+ return isPointInShape([x, y], selectionShape);
3068
+ }
3069
+ // take bound text element into consideration for hit collision as well
3070
+ const hitBoundTextOfElement = hitElementBoundText(x, y, this.getBoundTextShape(element));
3071
+ if (hitBoundTextOfElement) {
3072
+ return true;
3073
+ }
3074
+ return hitElementItself({
3075
+ x,
3076
+ y,
3077
+ element,
3078
+ shape: this.getElementShape(element),
3079
+ threshold: this.getElementHitThreshold(),
3080
+ frameNameBound: isFrameLikeElement(element)
3081
+ ? this.frameNameBoundsCache.get(element)
3082
+ : null,
2947
3083
  });
2948
3084
  }
3085
+ getTextBindableContainerAtPosition(x, y) {
3086
+ const elements = this.scene.getNonDeletedElements();
3087
+ const selectedElements = this.scene.getSelectedElements(this.state);
3088
+ if (selectedElements.length === 1) {
3089
+ return isTextBindableContainer(selectedElements[0], false)
3090
+ ? selectedElements[0]
3091
+ : null;
3092
+ }
3093
+ let hitElement = null;
3094
+ // We need to do hit testing from front (end of the array) to back (beginning of the array)
3095
+ for (let index = elements.length - 1; index >= 0; --index) {
3096
+ if (elements[index].isDeleted) {
3097
+ continue;
3098
+ }
3099
+ const [x1, y1, x2, y2] = getElementAbsoluteCoords(elements[index], this.scene.getNonDeletedElementsMap());
3100
+ if (isArrowElement(elements[index]) &&
3101
+ hitElementItself({
3102
+ x,
3103
+ y,
3104
+ element: elements[index],
3105
+ shape: this.getElementShape(elements[index]),
3106
+ threshold: this.getElementHitThreshold(),
3107
+ })) {
3108
+ hitElement = elements[index];
3109
+ break;
3110
+ }
3111
+ else if (x1 < x && x < x2 && y1 < y && y < y2) {
3112
+ hitElement = elements[index];
3113
+ break;
3114
+ }
3115
+ }
3116
+ return isTextBindableContainer(hitElement, false) ? hitElement : null;
3117
+ }
2949
3118
  startTextEditing = ({ sceneX, sceneY, insertAtParentCenter = true, container, }) => {
2950
3119
  let shouldBindToContainer = false;
2951
3120
  let parentCenterPosition = insertAtParentCenter &&
@@ -3044,7 +3213,7 @@ class App extends React.Component {
3044
3213
  this.scene.insertElementAtIndex(element, containerIndex + 1);
3045
3214
  }
3046
3215
  else {
3047
- this.scene.addNewElement(element);
3216
+ this.scene.insertElement(element);
3048
3217
  }
3049
3218
  }
3050
3219
  this.setState({
@@ -3069,7 +3238,7 @@ class App extends React.Component {
3069
3238
  if (event[KEYS.CTRL_OR_CMD] &&
3070
3239
  (!this.state.editingLinearElement ||
3071
3240
  this.state.editingLinearElement.elementId !== selectedElements[0].id)) {
3072
- this.history.resumeRecording();
3241
+ this.store.shouldCaptureIncrement();
3073
3242
  this.setState({
3074
3243
  editingLinearElement: new LinearElementEditor(selectedElements[0]),
3075
3244
  });
@@ -3084,6 +3253,7 @@ class App extends React.Component {
3084
3253
  const selectedGroupId = hitElement &&
3085
3254
  getSelectedGroupIdForElement(hitElement, this.state.selectedGroupIds);
3086
3255
  if (selectedGroupId) {
3256
+ this.store.shouldCaptureIncrement();
3087
3257
  this.setState((prevState) => ({
3088
3258
  ...prevState,
3089
3259
  ...selectGroupsForSelectedElements({
@@ -3103,11 +3273,17 @@ class App extends React.Component {
3103
3273
  });
3104
3274
  return;
3105
3275
  }
3106
- const container = getTextBindableContainerAtPosition(this.scene.getNonDeletedElements(), this.state, sceneX, sceneY, this.scene.getNonDeletedElementsMap());
3276
+ const container = this.getTextBindableContainerAtPosition(sceneX, sceneY);
3107
3277
  if (container) {
3108
3278
  if (hasBoundTextElement(container) ||
3109
3279
  !isTransparent(container.backgroundColor) ||
3110
- isHittingElementNotConsideringBoundingBox(container, this.state, this.frameNameBoundsCache, [sceneX, sceneY], this.scene.getNonDeletedElementsMap())) {
3280
+ hitElementItself({
3281
+ x: sceneX,
3282
+ y: sceneY,
3283
+ element: container,
3284
+ shape: this.getElementShape(container),
3285
+ threshold: this.getElementHitThreshold(),
3286
+ })) {
3111
3287
  const midPoint = getContainerCenter(container, this.state, this.scene.getNonDeletedElementsMap());
3112
3288
  sceneX = midPoint.x;
3113
3289
  sceneY = midPoint.y;
@@ -3381,15 +3557,23 @@ class App extends React.Component {
3381
3557
  if (selectedElements.length === 1 &&
3382
3558
  !isOverScrollBar &&
3383
3559
  !this.state.editingLinearElement) {
3384
- const elementWithTransformHandleType = getElementWithTransformHandleType(elements, this.state, scenePointerX, scenePointerY, this.state.zoom, event.pointerType, this.scene.getNonDeletedElementsMap());
3385
- if (elementWithTransformHandleType &&
3386
- elementWithTransformHandleType.transformHandleType) {
3387
- setCursor(this.interactiveCanvas, getCursorForResizingElement(elementWithTransformHandleType));
3388
- return;
3560
+ // for linear elements, we'd like to prioritize point dragging over edge resizing
3561
+ // therefore, we update and check hovered point index first
3562
+ if (this.state.selectedLinearElement) {
3563
+ this.handleHoverSelectedLinearElement(this.state.selectedLinearElement, scenePointerX, scenePointerY);
3564
+ }
3565
+ if (!this.state.selectedLinearElement ||
3566
+ this.state.selectedLinearElement.hoverPointIndex === -1) {
3567
+ const elementWithTransformHandleType = getElementWithTransformHandleType(elements, this.state, scenePointerX, scenePointerY, this.state.zoom, event.pointerType, this.scene.getNonDeletedElementsMap(), this.device);
3568
+ if (elementWithTransformHandleType &&
3569
+ elementWithTransformHandleType.transformHandleType) {
3570
+ setCursor(this.interactiveCanvas, getCursorForResizingElement(elementWithTransformHandleType));
3571
+ return;
3572
+ }
3389
3573
  }
3390
3574
  }
3391
3575
  else if (selectedElements.length > 1 && !isOverScrollBar) {
3392
- const transformHandleType = getTransformHandleTypeFromCoords(getCommonBounds(selectedElements), scenePointerX, scenePointerY, this.state.zoom, event.pointerType);
3576
+ const transformHandleType = getTransformHandleTypeFromCoords(getCommonBounds(selectedElements), scenePointerX, scenePointerY, this.state.zoom, event.pointerType, this.device);
3393
3577
  if (transformHandleType) {
3394
3578
  setCursor(this.interactiveCanvas, getCursorForResizingElement({
3395
3579
  transformHandleType,
@@ -3493,7 +3677,7 @@ class App extends React.Component {
3493
3677
  }
3494
3678
  };
3495
3679
  const distance = distance2d(pointerDownState.lastCoords.x, pointerDownState.lastCoords.y, scenePointer.x, scenePointer.y);
3496
- const threshold = 10 / this.state.zoom.value;
3680
+ const threshold = this.getElementHitThreshold();
3497
3681
  const point = { ...pointerDownState.lastCoords };
3498
3682
  let samplingInterval = 0;
3499
3683
  while (samplingInterval <= distance) {
@@ -3529,7 +3713,7 @@ class App extends React.Component {
3529
3713
  }
3530
3714
  }
3531
3715
  this.elementsPendingErasure = new Set(this.elementsPendingErasure);
3532
- this.onSceneUpdated();
3716
+ this.triggerRender();
3533
3717
  }
3534
3718
  };
3535
3719
  // set touch moving for mobile context menu
@@ -3539,30 +3723,29 @@ class App extends React.Component {
3539
3723
  handleHoverSelectedLinearElement(linearElementEditor, scenePointerX, scenePointerY) {
3540
3724
  const elementsMap = this.scene.getNonDeletedElementsMap();
3541
3725
  const element = LinearElementEditor.getElement(linearElementEditor.elementId, elementsMap);
3542
- const boundTextElement = getBoundTextElement(element, elementsMap);
3543
3726
  if (!element) {
3544
3727
  return;
3545
3728
  }
3546
3729
  if (this.state.selectedLinearElement) {
3547
3730
  let hoverPointIndex = -1;
3548
3731
  let segmentMidPointHoveredCoords = null;
3549
- if (isHittingElementNotConsideringBoundingBox(element, this.state, this.frameNameBoundsCache, [scenePointerX, scenePointerY], elementsMap)) {
3732
+ if (hitElementItself({
3733
+ x: scenePointerX,
3734
+ y: scenePointerY,
3735
+ element,
3736
+ shape: this.getElementShape(element),
3737
+ })) {
3550
3738
  hoverPointIndex = LinearElementEditor.getPointIndexUnderCursor(element, elementsMap, this.state.zoom, scenePointerX, scenePointerY);
3551
3739
  segmentMidPointHoveredCoords =
3552
3740
  LinearElementEditor.getSegmentMidpointHitCoords(linearElementEditor, { x: scenePointerX, y: scenePointerY }, this.state, this.scene.getNonDeletedElementsMap());
3553
3741
  if (hoverPointIndex >= 0 || segmentMidPointHoveredCoords) {
3554
3742
  setCursor(this.interactiveCanvas, CURSOR_TYPE.POINTER);
3555
3743
  }
3556
- else {
3744
+ else if (this.hitElement(scenePointerX, scenePointerY, element)) {
3557
3745
  setCursor(this.interactiveCanvas, CURSOR_TYPE.MOVE);
3558
3746
  }
3559
3747
  }
3560
- else if (shouldShowBoundingBox([element], this.state) &&
3561
- isHittingElementBoundingBoxWithoutHittingElement(element, this.state, this.frameNameBoundsCache, scenePointerX, scenePointerY, elementsMap)) {
3562
- setCursor(this.interactiveCanvas, CURSOR_TYPE.MOVE);
3563
- }
3564
- else if (boundTextElement &&
3565
- hitTest(boundTextElement, this.state, this.frameNameBoundsCache, scenePointerX, scenePointerY, this.scene.getNonDeletedElementsMap())) {
3748
+ else if (this.hitElement(scenePointerX, scenePointerY, element)) {
3566
3749
  setCursor(this.interactiveCanvas, CURSOR_TYPE.MOVE);
3567
3750
  }
3568
3751
  if (this.state.selectedLinearElement.hoverPointIndex !== hoverPointIndex) {
@@ -3629,6 +3812,7 @@ class App extends React.Component {
3629
3812
  return obj;
3630
3813
  }, {}), this.state),
3631
3814
  },
3815
+ storeAction: StoreAction.UPDATE,
3632
3816
  });
3633
3817
  return;
3634
3818
  }
@@ -4071,8 +4255,11 @@ class App extends React.Component {
4071
4255
  const elements = this.scene.getNonDeletedElements();
4072
4256
  const elementsMap = this.scene.getNonDeletedElementsMap();
4073
4257
  const selectedElements = this.scene.getSelectedElements(this.state);
4074
- if (selectedElements.length === 1 && !this.state.editingLinearElement) {
4075
- const elementWithTransformHandleType = getElementWithTransformHandleType(elements, this.state, pointerDownState.origin.x, pointerDownState.origin.y, this.state.zoom, event.pointerType, this.scene.getNonDeletedElementsMap());
4258
+ if (selectedElements.length === 1 &&
4259
+ !this.state.editingLinearElement &&
4260
+ !(this.state.selectedLinearElement &&
4261
+ this.state.selectedLinearElement.hoverPointIndex !== -1)) {
4262
+ const elementWithTransformHandleType = getElementWithTransformHandleType(elements, this.state, pointerDownState.origin.x, pointerDownState.origin.y, this.state.zoom, event.pointerType, this.scene.getNonDeletedElementsMap(), this.device);
4076
4263
  if (elementWithTransformHandleType != null) {
4077
4264
  this.setState({
4078
4265
  resizingElement: elementWithTransformHandleType.element,
@@ -4082,7 +4269,7 @@ class App extends React.Component {
4082
4269
  }
4083
4270
  }
4084
4271
  else if (selectedElements.length > 1) {
4085
- pointerDownState.resize.handleType = getTransformHandleTypeFromCoords(getCommonBounds(selectedElements), pointerDownState.origin.x, pointerDownState.origin.y, this.state.zoom, event.pointerType);
4272
+ pointerDownState.resize.handleType = getTransformHandleTypeFromCoords(getCommonBounds(selectedElements), pointerDownState.origin.x, pointerDownState.origin.y, this.state.zoom, event.pointerType, this.device);
4086
4273
  }
4087
4274
  if (pointerDownState.resize.handleType) {
4088
4275
  pointerDownState.resize.isResizing = true;
@@ -4096,7 +4283,7 @@ class App extends React.Component {
4096
4283
  else {
4097
4284
  if (this.state.selectedLinearElement) {
4098
4285
  const linearElementEditor = this.state.editingLinearElement || this.state.selectedLinearElement;
4099
- const ret = LinearElementEditor.handlePointerDown(event, this.state, this.history, pointerDownState.origin, linearElementEditor, this.scene.getNonDeletedElements(), elementsMap);
4286
+ const ret = LinearElementEditor.handlePointerDown(event, this.state, this.store, pointerDownState.origin, linearElementEditor, this);
4100
4287
  if (ret.hitElement) {
4101
4288
  pointerDownState.hit.element = ret.hitElement;
4102
4289
  }
@@ -4257,7 +4444,7 @@ class App extends React.Component {
4257
4444
  return false;
4258
4445
  }
4259
4446
  // How many pixels off the shape boundary we still consider a hit
4260
- const threshold = 10 / this.state.zoom.value;
4447
+ const threshold = this.getElementHitThreshold();
4261
4448
  const [x1, y1, x2, y2] = getCommonBounds(selectedElements);
4262
4449
  return (point.x > x1 - threshold &&
4263
4450
  point.x < x2 + threshold &&
@@ -4277,7 +4464,7 @@ class App extends React.Component {
4277
4464
  includeBoundTextElement: true,
4278
4465
  });
4279
4466
  // FIXME
4280
- let container = getTextBindableContainerAtPosition(this.scene.getNonDeletedElements(), this.state, sceneX, sceneY, this.scene.getNonDeletedElementsMap());
4467
+ let container = this.getTextBindableContainerAtPosition(sceneX, sceneY);
4281
4468
  if (hasBoundTextElement(element)) {
4282
4469
  container = element;
4283
4470
  sceneX = element.x + element.width / 2;
@@ -4335,8 +4522,8 @@ class App extends React.Component {
4335
4522
  points: [[0, 0]],
4336
4523
  pressures,
4337
4524
  });
4338
- const boundElement = getHoveredElementForBinding(pointerDownState.origin, this.scene.getNonDeletedElements(), this.scene.getNonDeletedElementsMap());
4339
- this.scene.addNewElement(element);
4525
+ const boundElement = getHoveredElementForBinding(pointerDownState.origin, this);
4526
+ this.scene.insertElement(element);
4340
4527
  this.setState({
4341
4528
  draggingElement: element,
4342
4529
  editingElement: element,
@@ -4364,10 +4551,7 @@ class App extends React.Component {
4364
4551
  width,
4365
4552
  height,
4366
4553
  });
4367
- this.scene.replaceAllElements([
4368
- ...this.scene.getElementsIncludingDeleted(),
4369
- element,
4370
- ]);
4554
+ this.scene.insertElement(element);
4371
4555
  return element;
4372
4556
  };
4373
4557
  //create rectangle element with youtube top left on nearest grid point width / hight 640/360
@@ -4402,10 +4586,7 @@ class App extends React.Component {
4402
4586
  height: embedLink.intrinsicSize.h,
4403
4587
  link,
4404
4588
  });
4405
- this.scene.replaceAllElements([
4406
- ...this.scene.getElementsIncludingDeleted(),
4407
- element,
4408
- ]);
4589
+ this.scene.insertElement(element);
4409
4590
  return element;
4410
4591
  };
4411
4592
  createImageElement = ({ sceneX, sceneY, addToFrameUnderCursor = true, }) => {
@@ -4513,8 +4694,8 @@ class App extends React.Component {
4513
4694
  mutateElement(element, {
4514
4695
  points: [...element.points, [0, 0]],
4515
4696
  });
4516
- const boundElement = getHoveredElementForBinding(pointerDownState.origin, this.scene.getNonDeletedElements(), this.scene.getNonDeletedElementsMap());
4517
- this.scene.addNewElement(element);
4697
+ const boundElement = getHoveredElementForBinding(pointerDownState.origin, this);
4698
+ this.scene.insertElement(element);
4518
4699
  this.setState({
4519
4700
  draggingElement: element,
4520
4701
  editingElement: element,
@@ -4574,7 +4755,7 @@ class App extends React.Component {
4574
4755
  });
4575
4756
  }
4576
4757
  else {
4577
- this.scene.addNewElement(element);
4758
+ this.scene.insertElement(element);
4578
4759
  this.setState({
4579
4760
  multiElement: null,
4580
4761
  draggingElement: element,
@@ -4596,10 +4777,7 @@ class App extends React.Component {
4596
4777
  const frame = type === TOOL_TYPE.magicframe
4597
4778
  ? newMagicFrameElement(constructorOpts)
4598
4779
  : newFrameElement(constructorOpts);
4599
- this.scene.replaceAllElements([
4600
- ...this.scene.getElementsIncludingDeleted(),
4601
- frame,
4602
- ]);
4780
+ this.scene.insertElement(frame);
4603
4781
  this.setState({
4604
4782
  multiElement: null,
4605
4783
  draggingElement: frame,
@@ -4813,7 +4991,9 @@ class App extends React.Component {
4813
4991
  // able to select and interact with the text input
4814
4992
  !this.state.editingFrame &&
4815
4993
  dragSelectedElements(pointerDownState, selectedElements, dragOffset, this.state, this.scene, snapOffset, event[KEYS.CTRL_OR_CMD] ? null : this.state.gridSize);
4816
- this.maybeSuggestBindingForAll(selectedElements);
4994
+ this.setState({
4995
+ suggestedBindings: getSuggestedBindingsForArrows(selectedElements, this),
4996
+ });
4817
4997
  // We duplicate the selected element if alt is pressed on pointer move
4818
4998
  if (event.altKey && !pointerDownState.hit.hasBeenDuplicated) {
4819
4999
  // Move the currently selected elements to the top of the z index stack, and
@@ -4857,6 +5037,7 @@ class App extends React.Component {
4857
5037
  }
4858
5038
  }
4859
5039
  const nextSceneElements = [...nextElements, ...elementsToAppend];
5040
+ syncMovedIndices(nextSceneElements, arrayToMap(elementsToAppend));
4860
5041
  bindTextToShapeAfterDuplication(nextElements, elementsToAppend, oldIdToDuplicatedId);
4861
5042
  fixBindingsAfterDuplication(nextSceneElements, elementsToAppend, oldIdToDuplicatedId, "duplicatesServeAsOld");
4862
5043
  bindElementsToFramesAfterDuplication(nextSceneElements, elementsToAppend, oldIdToDuplicatedId);
@@ -5049,7 +5230,7 @@ class App extends React.Component {
5049
5230
  this.actionManager.executeAction(actionFinalize);
5050
5231
  }
5051
5232
  else {
5052
- const editingLinearElement = LinearElementEditor.handlePointerUp(childEvent, this.state.editingLinearElement, this.state, this.scene.getNonDeletedElements(), elementsMap);
5233
+ const editingLinearElement = LinearElementEditor.handlePointerUp(childEvent, this.state.editingLinearElement, this.state, this);
5053
5234
  if (editingLinearElement !== this.state.editingLinearElement) {
5054
5235
  this.setState({
5055
5236
  editingLinearElement,
@@ -5068,7 +5249,7 @@ class App extends React.Component {
5068
5249
  }
5069
5250
  }
5070
5251
  else {
5071
- const linearElementEditor = LinearElementEditor.handlePointerUp(childEvent, this.state.selectedLinearElement, this.state, this.scene.getNonDeletedElements(), elementsMap);
5252
+ const linearElementEditor = LinearElementEditor.handlePointerUp(childEvent, this.state.selectedLinearElement, this.state, this);
5072
5253
  const { startBindingElement, endBindingElement } = linearElementEditor;
5073
5254
  const element = this.scene.getElement(linearElementEditor.elementId);
5074
5255
  if (isBindingElement(element)) {
@@ -5137,7 +5318,7 @@ class App extends React.Component {
5137
5318
  }
5138
5319
  if (isLinearElement(draggingElement)) {
5139
5320
  if (draggingElement.points.length > 1) {
5140
- this.history.resumeRecording();
5321
+ this.store.shouldCaptureIncrement();
5141
5322
  }
5142
5323
  const pointerCoords = viewportCoordsToSceneCoords(childEvent, this.state);
5143
5324
  if (!pointerDownState.drag.hasOccurred &&
@@ -5160,7 +5341,7 @@ class App extends React.Component {
5160
5341
  else if (pointerDownState.drag.hasOccurred && !multiElement) {
5161
5342
  if (isBindingEnabled(this.state) &&
5162
5343
  isBindingElement(draggingElement, false)) {
5163
- maybeBindLinearElement(draggingElement, this.state, this.scene, pointerCoords, elementsMap);
5344
+ maybeBindLinearElement(draggingElement, this.state, pointerCoords, this);
5164
5345
  }
5165
5346
  this.setState({ suggestedBindings: [], startBoundElement: null });
5166
5347
  if (!activeTool.locked) {
@@ -5189,11 +5370,15 @@ class App extends React.Component {
5189
5370
  draggingElement &&
5190
5371
  isInvisiblySmallElement(draggingElement)) {
5191
5372
  // remove invisible element which was added in onPointerDown
5192
- this.scene.replaceAllElements(this.scene
5193
- .getElementsIncludingDeleted()
5194
- .filter((el) => el.id !== draggingElement.id));
5195
- this.setState({
5196
- draggingElement: null,
5373
+ // update the store snapshot, so that invisible elements are not captured by the store
5374
+ this.updateScene({
5375
+ elements: this.scene
5376
+ .getElementsIncludingDeleted()
5377
+ .filter((el) => el.id !== draggingElement.id),
5378
+ appState: {
5379
+ draggingElement: null,
5380
+ },
5381
+ storeAction: StoreAction.UPDATE,
5197
5382
  });
5198
5383
  return;
5199
5384
  }
@@ -5216,7 +5401,7 @@ class App extends React.Component {
5216
5401
  groupIds: [],
5217
5402
  });
5218
5403
  removeElementsFromFrame([linearElement], this.scene.getNonDeletedElementsMap());
5219
- this.scene.informMutation();
5404
+ this.scene.triggerUpdate();
5220
5405
  }
5221
5406
  }
5222
5407
  }
@@ -5274,12 +5459,16 @@ class App extends React.Component {
5274
5459
  mutateElement(draggingElement, getNormalizedDimensions(draggingElement));
5275
5460
  }
5276
5461
  if (resizingElement) {
5277
- this.history.resumeRecording();
5462
+ this.store.shouldCaptureIncrement();
5278
5463
  }
5279
5464
  if (resizingElement && isInvisiblySmallElement(resizingElement)) {
5280
- this.scene.replaceAllElements(this.scene
5281
- .getElementsIncludingDeleted()
5282
- .filter((el) => el.id !== resizingElement.id));
5465
+ // update the store snapshot, so that invisible elements are not captured by the store
5466
+ this.updateScene({
5467
+ elements: this.scene
5468
+ .getElementsIncludingDeleted()
5469
+ .filter((el) => el.id !== resizingElement.id),
5470
+ storeAction: StoreAction.UPDATE,
5471
+ });
5283
5472
  }
5284
5473
  // handle frame membership for resizing frames and/or selected elements
5285
5474
  if (pointerDownState.resize.isResizing) {
@@ -5434,10 +5623,23 @@ class App extends React.Component {
5434
5623
  }));
5435
5624
  }
5436
5625
  }
5437
- if (!pointerDownState.drag.hasOccurred &&
5626
+ if (
5627
+ // not dragged
5628
+ !pointerDownState.drag.hasOccurred &&
5629
+ // not resized
5438
5630
  !this.state.isResizing &&
5631
+ // only hitting the bounding box of the previous hit element
5439
5632
  ((hitElement &&
5440
- isHittingElementBoundingBoxWithoutHittingElement(hitElement, this.state, this.frameNameBoundsCache, pointerDownState.origin.x, pointerDownState.origin.y, this.scene.getNonDeletedElementsMap())) ||
5633
+ hitElementBoundingBoxOnly({
5634
+ x: pointerDownState.origin.x,
5635
+ y: pointerDownState.origin.y,
5636
+ element: hitElement,
5637
+ shape: this.getElementShape(hitElement),
5638
+ threshold: this.getElementHitThreshold(),
5639
+ frameNameBound: isFrameLikeElement(hitElement)
5640
+ ? this.frameNameBoundsCache.get(hitElement)
5641
+ : null,
5642
+ }, elementsMap)) ||
5441
5643
  (!hitElement &&
5442
5644
  pointerDownState.hit.hasHitCommonBoundingBoxOfSelectedElements))) {
5443
5645
  if (this.state.editingLinearElement) {
@@ -5452,6 +5654,8 @@ class App extends React.Component {
5452
5654
  activeEmbeddable: null,
5453
5655
  });
5454
5656
  }
5657
+ // reset cursor
5658
+ setCursor(this.interactiveCanvas, CURSOR_TYPE.AUTO);
5455
5659
  return;
5456
5660
  }
5457
5661
  if (!activeTool.locked &&
@@ -5469,13 +5673,17 @@ class App extends React.Component {
5469
5673
  }));
5470
5674
  }
5471
5675
  if (activeTool.type !== "selection" ||
5472
- isSomeElementSelected(this.scene.getNonDeletedElements(), this.state)) {
5473
- this.history.resumeRecording();
5676
+ isSomeElementSelected(this.scene.getNonDeletedElements(), this.state) ||
5677
+ !isShallowEqual(this.state.previousSelectedElementIds, this.state.selectedElementIds)) {
5678
+ this.store.shouldCaptureIncrement();
5474
5679
  }
5475
5680
  if (pointerDownState.drag.hasOccurred || isResizing || isRotating) {
5476
- isBindingEnabled(this.state)
5477
- ? bindOrUnbindSelectedElements(this.scene.getSelectedElements(this.state), this.scene.getNonDeletedElements(), elementsMap)
5478
- : unbindLinearElements(this.scene.getSelectedElements(this.state), elementsMap);
5681
+ // We only allow binding via linear elements, specifically via dragging
5682
+ // the endpoints ("start" or "end").
5683
+ const linearElements = this.scene
5684
+ .getSelectedElements(this.state)
5685
+ .filter(isLinearElement);
5686
+ bindOrUnbindLinearElements(linearElements, this, isBindingEnabled(this.state), this.state.selectedLinearElement?.selectedPointsIndices ?? []);
5479
5687
  }
5480
5688
  if (activeTool.type === "laser") {
5481
5689
  this.laserTrails.endPath();
@@ -5510,7 +5718,7 @@ class App extends React.Component {
5510
5718
  }
5511
5719
  restoreReadyToEraseElements = () => {
5512
5720
  this.elementsPendingErasure = new Set();
5513
- this.onSceneUpdated();
5721
+ this.triggerRender();
5514
5722
  };
5515
5723
  eraseElements = () => {
5516
5724
  let didChange = false;
@@ -5526,7 +5734,7 @@ class App extends React.Component {
5526
5734
  });
5527
5735
  this.elementsPendingErasure = new Set();
5528
5736
  if (didChange) {
5529
- this.history.resumeRecording();
5737
+ this.store.shouldCaptureIncrement();
5530
5738
  this.scene.replaceAllElements(elements);
5531
5739
  }
5532
5740
  };
@@ -5629,7 +5837,7 @@ class App extends React.Component {
5629
5837
  this.setState({ errorMessage: t("errors.imageToolNotSupported") });
5630
5838
  return;
5631
5839
  }
5632
- this.scene.addNewElement(imageElement);
5840
+ this.scene.insertElement(imageElement);
5633
5841
  try {
5634
5842
  return await this.initializeImage({
5635
5843
  imageFile,
@@ -5802,7 +6010,7 @@ class App extends React.Component {
5802
6010
  if (uncachedImageElements.length) {
5803
6011
  const { updatedFiles } = await this.updateImageCache(uncachedImageElements, files);
5804
6012
  if (updatedFiles.size) {
5805
- this.scene.informMutation();
6013
+ this.scene.triggerUpdate();
5806
6014
  }
5807
6015
  }
5808
6016
  };
@@ -5818,7 +6026,7 @@ class App extends React.Component {
5818
6026
  }
5819
6027
  };
5820
6028
  maybeSuggestBindingAtCursor = (pointerCoords) => {
5821
- const hoveredBindableElement = getHoveredElementForBinding(pointerCoords, this.scene.getNonDeletedElements(), this.scene.getNonDeletedElementsMap());
6029
+ const hoveredBindableElement = getHoveredElementForBinding(pointerCoords, this);
5822
6030
  this.setState({
5823
6031
  suggestedBindings: hoveredBindableElement != null ? [hoveredBindableElement] : [],
5824
6032
  });
@@ -5833,7 +6041,7 @@ class App extends React.Component {
5833
6041
  return;
5834
6042
  }
5835
6043
  const suggestedBindings = pointerCoords.reduce((acc, coords) => {
5836
- const hoveredBindableElement = getHoveredElementForBinding(coords, this.scene.getNonDeletedElements(), this.scene.getNonDeletedElementsMap());
6044
+ const hoveredBindableElement = getHoveredElementForBinding(coords, this);
5837
6045
  if (hoveredBindableElement != null &&
5838
6046
  !isLinearElementSimpleAndAlreadyBound(linearElement, oppositeBindingBoundElement?.id, hoveredBindableElement)) {
5839
6047
  acc.push(hoveredBindableElement);
@@ -5842,13 +6050,6 @@ class App extends React.Component {
5842
6050
  }, []);
5843
6051
  this.setState({ suggestedBindings });
5844
6052
  };
5845
- maybeSuggestBindingForAll(selectedElements) {
5846
- if (selectedElements.length > 50) {
5847
- return;
5848
- }
5849
- const suggestedBindings = getEligibleElementsForBinding(selectedElements, this.scene.getNonDeletedElements(), this.scene.getNonDeletedElementsMap());
5850
- this.setState({ suggestedBindings });
5851
- }
5852
6053
  clearSelection(hitElement) {
5853
6054
  this.setState((prevState) => ({
5854
6055
  selectedElementIds: makeNextSelectedElementIds({}, prevState),
@@ -5908,7 +6109,7 @@ class App extends React.Component {
5908
6109
  isLoading: false,
5909
6110
  },
5910
6111
  replaceFiles: true,
5911
- commitToHistory: true,
6112
+ storeAction: StoreAction.CAPTURE,
5912
6113
  });
5913
6114
  return;
5914
6115
  }
@@ -5976,9 +6177,10 @@ class App extends React.Component {
5976
6177
  loadFileToCanvas = async (file, fileHandle) => {
5977
6178
  file = await normalizeFile(file);
5978
6179
  try {
6180
+ const elements = this.scene.getElementsIncludingDeleted();
5979
6181
  let ret;
5980
6182
  try {
5981
- ret = await loadSceneOrLibraryFromBlob(file, this.state, this.scene.getElementsIncludingDeleted(), fileHandle);
6183
+ ret = await loadSceneOrLibraryFromBlob(file, this.state, elements, fileHandle);
5982
6184
  }
5983
6185
  catch (error) {
5984
6186
  const imageSceneDataError = error instanceof ImageSceneDataError;
@@ -6003,6 +6205,10 @@ class App extends React.Component {
6003
6205
  return;
6004
6206
  }
6005
6207
  if (ret.type === MIME_TYPES.excalidraw) {
6208
+ // restore the fractional indices by mutating elements
6209
+ syncInvalidIndices(elements.concat(ret.data.elements));
6210
+ // update the store snapshot for old elements, otherwise we would end up with duplicated fractional indices on undo
6211
+ this.store.updateSnapshot(arrayToMap(elements), this.state);
6006
6212
  this.setState({ isLoading: true });
6007
6213
  this.syncActionResult({
6008
6214
  ...ret.data,
@@ -6011,7 +6217,7 @@ class App extends React.Component {
6011
6217
  isLoading: false,
6012
6218
  },
6013
6219
  replaceFiles: true,
6014
- commitToHistory: true,
6220
+ storeAction: StoreAction.CAPTURE,
6015
6221
  });
6016
6222
  }
6017
6223
  else if (ret.type === MIME_TYPES.excalidrawlib) {
@@ -6113,7 +6319,6 @@ class App extends React.Component {
6113
6319
  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)
6114
6320
  ? !shouldMaintainAspectRatio(event)
6115
6321
  : shouldMaintainAspectRatio(event), shouldResizeFromCenter(event), aspectRatio, this.state.originSnapOffset);
6116
- this.maybeSuggestBindingForAll([draggingElement]);
6117
6322
  // highlight elements that are to be added to frames on frames creation
6118
6323
  if (this.state.activeTool.type === TOOL_TYPE.frame ||
6119
6324
  this.state.activeTool.type === TOOL_TYPE.magicframe) {
@@ -6167,16 +6372,17 @@ class App extends React.Component {
6167
6372
  snapLines,
6168
6373
  });
6169
6374
  }
6170
- if (transformElements(pointerDownState.originalElements, transformHandleType, selectedElements, this.scene.getElementsMapIncludingDeleted(), shouldRotateWithDiscreteAngle(event), shouldResizeFromCenter(event), selectedElements.length === 1 && isImageElement(selectedElements[0])
6375
+ if (transformElements(pointerDownState.originalElements, transformHandleType, selectedElements, this.scene.getElementsMapIncludingDeleted(), shouldRotateWithDiscreteAngle(event), shouldResizeFromCenter(event), selectedElements.some((element) => isImageElement(element))
6171
6376
  ? !shouldMaintainAspectRatio(event)
6172
6377
  : shouldMaintainAspectRatio(event), resizeX, resizeY, pointerDownState.resize.center.x, pointerDownState.resize.center.y)) {
6173
- this.maybeSuggestBindingForAll(selectedElements);
6378
+ const suggestedBindings = getSuggestedBindingsForArrows(selectedElements, this);
6174
6379
  const elementsToHighlight = new Set();
6175
6380
  selectedFrames.forEach((frame) => {
6176
6381
  getElementsInResizingFrame(this.scene.getNonDeletedElements(), frame, this.state, this.scene.getNonDeletedElementsMap()).forEach((element) => elementsToHighlight.add(element));
6177
6382
  });
6178
6383
  this.setState({
6179
6384
  elementsToHighlight: [...elementsToHighlight],
6385
+ suggestedBindings,
6180
6386
  });
6181
6387
  return true;
6182
6388
  }
@@ -6221,6 +6427,7 @@ class App extends React.Component {
6221
6427
  return [actionCopy, ...options];
6222
6428
  }
6223
6429
  return [
6430
+ CONTEXT_MENU_SEPARATOR,
6224
6431
  actionCut,
6225
6432
  actionCopy,
6226
6433
  actionPaste,
@@ -6233,6 +6440,7 @@ class App extends React.Component {
6233
6440
  actionPasteStyles,
6234
6441
  CONTEXT_MENU_SEPARATOR,
6235
6442
  actionGroup,
6443
+ actionTextAutoResize,
6236
6444
  actionUnbindText,
6237
6445
  actionBindText,
6238
6446
  actionWrapTextInContainer,
@@ -6401,7 +6609,7 @@ export const createTestHook = () => {
6401
6609
  return this.app?.scene.getElementsIncludingDeleted();
6402
6610
  },
6403
6611
  set(elements) {
6404
- return this.app?.scene.replaceAllElements(elements);
6612
+ return this.app?.scene.replaceAllElements(syncInvalidIndices(elements));
6405
6613
  },
6406
6614
  },
6407
6615
  });