@excalidraw/excalidraw 0.17.1-7500-ac247a0 → 0.17.1-b7babe5

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 (255) hide show
  1. package/CHANGELOG.md +56 -2
  2. package/dist/browser/dev/excalidraw-assets-dev/{chunk-2W5GQUR4.js → chunk-6NMK7JTV.js} +13 -6
  3. package/dist/browser/dev/excalidraw-assets-dev/chunk-6NMK7JTV.js.map +7 -0
  4. package/dist/browser/dev/excalidraw-assets-dev/chunk-CX3RATXT.js +20324 -0
  5. package/dist/browser/dev/excalidraw-assets-dev/chunk-CX3RATXT.js.map +7 -0
  6. package/dist/browser/dev/excalidraw-assets-dev/{en-OC6JWP3X.js → en-BZY7JRTM.js} +4 -2
  7. package/dist/browser/dev/excalidraw-assets-dev/{image-5TVMINCA.js → image-CVN3YKRW.js} +2 -4
  8. package/dist/browser/dev/excalidraw-assets-dev/image-LK4UNFRZ.css +6 -0
  9. package/dist/browser/dev/excalidraw-assets-dev/image-LK4UNFRZ.css.map +7 -0
  10. package/dist/browser/dev/excalidraw-assets-dev/roundRect-T5BX56ZF.js +161 -0
  11. package/dist/browser/dev/excalidraw-assets-dev/roundRect-T5BX56ZF.js.map +7 -0
  12. package/dist/browser/dev/index.css +189 -129
  13. package/dist/browser/dev/index.css.map +3 -3
  14. package/dist/browser/dev/index.js +34964 -37
  15. package/dist/browser/dev/index.js.map +4 -4
  16. package/dist/browser/prod/excalidraw-assets/chunk-VJAIK3AX.js +55 -0
  17. package/dist/browser/prod/excalidraw-assets/chunk-YYO5DFUW.js +11 -0
  18. package/dist/browser/prod/excalidraw-assets/en-O2YCQM2W.js +1 -0
  19. package/dist/browser/prod/excalidraw-assets/image-6FKY54X5.js +1 -0
  20. package/dist/browser/prod/excalidraw-assets/image-X66R2EM5.css +1 -0
  21. package/dist/browser/prod/excalidraw-assets/roundRect-2ACQK4DA.js +1 -0
  22. package/dist/browser/prod/index.css +1 -1
  23. package/dist/browser/prod/index.js +203 -1
  24. package/dist/{prod/en-RLIAOBCI.json → dev/en-EY7E2L5O.json} +10 -5
  25. package/dist/dev/index.css +189 -129
  26. package/dist/dev/index.css.map +3 -3
  27. package/dist/dev/index.js +38702 -39409
  28. package/dist/dev/index.js.map +4 -4
  29. package/dist/excalidraw/actions/actionAddToLibrary.d.ts +15 -15
  30. package/dist/excalidraw/actions/actionAlign.d.ts +6 -6
  31. package/dist/excalidraw/actions/actionAlign.js +2 -1
  32. package/dist/excalidraw/actions/actionBoundText.d.ts +10 -10
  33. package/dist/excalidraw/actions/actionBoundText.js +8 -8
  34. package/dist/excalidraw/actions/actionCanvas.d.ts +58 -58
  35. package/dist/excalidraw/actions/actionClipboard.d.ts +34 -34
  36. package/dist/excalidraw/actions/actionClipboard.js +9 -2
  37. package/dist/excalidraw/actions/actionDeleteSelected.d.ts +15 -15
  38. package/dist/excalidraw/actions/actionDeleteSelected.js +3 -2
  39. package/dist/excalidraw/actions/actionDistribute.d.ts +2 -2
  40. package/dist/excalidraw/actions/actionDistribute.js +1 -1
  41. package/dist/excalidraw/actions/actionDuplicateSelection.d.ts +1 -1
  42. package/dist/excalidraw/actions/actionDuplicateSelection.js +4 -3
  43. package/dist/excalidraw/actions/actionElementLock.d.ts +10 -10
  44. package/dist/excalidraw/actions/actionExport.d.ts +43 -43
  45. package/dist/excalidraw/actions/actionExport.js +4 -4
  46. package/dist/excalidraw/actions/actionFinalize.d.ts +9 -9
  47. package/dist/excalidraw/actions/actionFinalize.js +7 -6
  48. package/dist/excalidraw/actions/actionFlip.d.ts +2 -2
  49. package/dist/excalidraw/actions/actionFlip.js +11 -11
  50. package/dist/excalidraw/actions/actionFrame.d.ts +16 -16
  51. package/dist/excalidraw/actions/actionFrame.js +1 -1
  52. package/dist/excalidraw/actions/actionGroup.d.ts +10 -10
  53. package/dist/excalidraw/actions/actionGroup.js +3 -2
  54. package/dist/excalidraw/actions/actionLinearEditor.d.ts +5 -5
  55. package/dist/excalidraw/actions/actionLinearEditor.js +1 -1
  56. package/dist/excalidraw/{element/Hyperlink.d.ts → actions/actionLink.d.ts} +29 -51
  57. package/dist/excalidraw/actions/actionLink.js +40 -0
  58. package/dist/excalidraw/actions/actionMenu.d.ts +13 -13
  59. package/dist/excalidraw/actions/actionNavigate.d.ts +10 -10
  60. package/dist/excalidraw/actions/actionNavigate.js +1 -1
  61. package/dist/excalidraw/actions/actionProperties.d.ts +77 -77
  62. package/dist/excalidraw/actions/actionProperties.js +32 -27
  63. package/dist/excalidraw/actions/actionSelectAll.d.ts +5 -5
  64. package/dist/excalidraw/actions/actionSelectAll.js +1 -1
  65. package/dist/excalidraw/actions/actionStyles.d.ts +7 -7
  66. package/dist/excalidraw/actions/actionStyles.js +4 -4
  67. package/dist/excalidraw/actions/actionToggleGridMode.d.ts +5 -5
  68. package/dist/excalidraw/actions/actionToggleObjectsSnapMode.d.ts +5 -5
  69. package/dist/excalidraw/actions/actionToggleStats.d.ts +5 -5
  70. package/dist/excalidraw/actions/actionToggleViewMode.d.ts +5 -5
  71. package/dist/excalidraw/actions/actionToggleZenMode.d.ts +5 -5
  72. package/dist/excalidraw/actions/index.d.ts +1 -1
  73. package/dist/excalidraw/actions/index.js +1 -1
  74. package/dist/excalidraw/actions/manager.js +2 -1
  75. package/dist/excalidraw/align.d.ts +2 -2
  76. package/dist/excalidraw/align.js +2 -2
  77. package/dist/excalidraw/animated-trail.d.ts +33 -0
  78. package/dist/excalidraw/animated-trail.js +96 -0
  79. package/dist/excalidraw/animation-frame-handler.d.ts +16 -0
  80. package/dist/excalidraw/animation-frame-handler.js +55 -0
  81. package/dist/excalidraw/appState.d.ts +1 -1
  82. package/dist/excalidraw/appState.js +1 -3
  83. package/dist/excalidraw/clipboard.js +5 -5
  84. package/dist/excalidraw/components/Actions.d.ts +3 -3
  85. package/dist/excalidraw/components/Actions.js +18 -7
  86. package/dist/excalidraw/components/App.d.ts +23 -16
  87. package/dist/excalidraw/components/App.js +387 -272
  88. package/dist/excalidraw/components/Button.d.ts +1 -1
  89. package/dist/excalidraw/components/FilledButton.d.ts +2 -2
  90. package/dist/excalidraw/components/FilledButton.js +27 -3
  91. package/dist/excalidraw/components/FollowMode/FollowMode.js +1 -1
  92. package/dist/excalidraw/components/ImageExportDialog.d.ts +2 -1
  93. package/dist/excalidraw/components/ImageExportDialog.js +17 -13
  94. package/dist/excalidraw/components/JSONExportDialog.js +1 -1
  95. package/dist/excalidraw/components/{LaserTool/LaserPointerButton.d.ts → LaserPointerButton.d.ts} +1 -1
  96. package/dist/excalidraw/components/{LaserTool/LaserPointerButton.js → LaserPointerButton.js} +2 -2
  97. package/dist/excalidraw/components/LayerUI.js +3 -3
  98. package/dist/excalidraw/components/MobileMenu.js +1 -1
  99. package/dist/excalidraw/components/ProjectName.d.ts +0 -1
  100. package/dist/excalidraw/components/ProjectName.js +1 -1
  101. package/dist/excalidraw/components/PublishLibrary.js +1 -1
  102. package/dist/excalidraw/components/SVGLayer.d.ts +8 -0
  103. package/dist/excalidraw/components/SVGLayer.js +20 -0
  104. package/dist/excalidraw/components/ShareableLinkDialog.js +10 -10
  105. package/dist/excalidraw/components/Sidebar/Sidebar.d.ts +1 -1
  106. package/dist/excalidraw/components/Stack.d.ts +2 -2
  107. package/dist/excalidraw/components/TTDDialog/common.js +10 -1
  108. package/dist/excalidraw/components/TextField.d.ts +5 -2
  109. package/dist/excalidraw/components/TextField.js +6 -3
  110. package/dist/excalidraw/components/Toast.d.ts +3 -2
  111. package/dist/excalidraw/components/Toast.js +2 -2
  112. package/dist/excalidraw/components/ToolButton.js +2 -1
  113. package/dist/excalidraw/components/canvases/InteractiveCanvas.d.ts +2 -2
  114. package/dist/excalidraw/components/canvases/InteractiveCanvas.js +6 -5
  115. package/dist/excalidraw/components/canvases/StaticCanvas.d.ts +4 -3
  116. package/dist/excalidraw/components/canvases/StaticCanvas.js +7 -5
  117. package/dist/excalidraw/components/dropdownMenu/DropdownMenuContent.js +22 -2
  118. package/dist/excalidraw/components/hyperlink/Hyperlink.d.ts +19 -0
  119. package/dist/excalidraw/{element → components/hyperlink}/Hyperlink.js +40 -115
  120. package/dist/excalidraw/components/hyperlink/helpers.d.ts +7 -0
  121. package/dist/excalidraw/components/hyperlink/helpers.js +49 -0
  122. package/dist/excalidraw/components/icons.d.ts +2 -1
  123. package/dist/excalidraw/components/icons.js +2 -1
  124. package/dist/excalidraw/components/live-collaboration/LiveCollaborationTrigger.js +3 -2
  125. package/dist/excalidraw/components/main-menu/DefaultItems.js +5 -2
  126. package/dist/excalidraw/constants.d.ts +6 -0
  127. package/dist/excalidraw/constants.js +6 -0
  128. package/dist/excalidraw/data/blob.js +13 -14
  129. package/dist/excalidraw/data/filesystem.d.ts +1 -1
  130. package/dist/excalidraw/data/index.d.ts +2 -1
  131. package/dist/excalidraw/data/index.js +20 -16
  132. package/dist/excalidraw/data/json.d.ts +1 -1
  133. package/dist/excalidraw/data/json.js +5 -3
  134. package/dist/excalidraw/data/library.d.ts +60 -8
  135. package/dist/excalidraw/data/library.js +302 -33
  136. package/dist/excalidraw/data/resave.d.ts +1 -1
  137. package/dist/excalidraw/data/resave.js +2 -2
  138. package/dist/excalidraw/data/restore.js +8 -13
  139. package/dist/excalidraw/data/transform.js +13 -9
  140. package/dist/excalidraw/distribute.d.ts +2 -2
  141. package/dist/excalidraw/distribute.js +2 -2
  142. package/dist/excalidraw/element/ElementCanvasButtons.d.ts +3 -2
  143. package/dist/excalidraw/element/ElementCanvasButtons.js +4 -4
  144. package/dist/excalidraw/element/binding.d.ts +9 -9
  145. package/dist/excalidraw/element/binding.js +61 -59
  146. package/dist/excalidraw/element/bounds.d.ts +5 -5
  147. package/dist/excalidraw/element/bounds.js +29 -32
  148. package/dist/excalidraw/element/collision.d.ts +11 -11
  149. package/dist/excalidraw/element/collision.js +49 -46
  150. package/dist/excalidraw/element/containerCache.d.ts +11 -0
  151. package/dist/excalidraw/element/containerCache.js +14 -0
  152. package/dist/excalidraw/element/dragElements.js +10 -19
  153. package/dist/excalidraw/element/embeddable.d.ts +12 -13
  154. package/dist/excalidraw/element/embeddable.js +17 -27
  155. package/dist/excalidraw/element/image.js +1 -2
  156. package/dist/excalidraw/element/index.d.ts +8 -1
  157. package/dist/excalidraw/element/index.js +23 -1
  158. package/dist/excalidraw/element/linearElementEditor.d.ts +36 -36
  159. package/dist/excalidraw/element/linearElementEditor.js +79 -80
  160. package/dist/excalidraw/element/newElement.d.ts +4 -6
  161. package/dist/excalidraw/element/newElement.js +11 -16
  162. package/dist/excalidraw/element/resizeElements.d.ts +6 -6
  163. package/dist/excalidraw/element/resizeElements.js +40 -46
  164. package/dist/excalidraw/element/resizeTest.d.ts +3 -3
  165. package/dist/excalidraw/element/resizeTest.js +4 -4
  166. package/dist/excalidraw/element/sizeHelpers.d.ts +2 -2
  167. package/dist/excalidraw/element/sizeHelpers.js +2 -2
  168. package/dist/excalidraw/element/textElement.d.ts +34 -21
  169. package/dist/excalidraw/element/textElement.js +87 -111
  170. package/dist/excalidraw/element/textWysiwyg.d.ts +1 -6
  171. package/dist/excalidraw/element/textWysiwyg.js +15 -37
  172. package/dist/excalidraw/element/transformHandles.d.ts +4 -4
  173. package/dist/excalidraw/element/transformHandles.js +6 -6
  174. package/dist/excalidraw/element/typeChecks.js +4 -1
  175. package/dist/excalidraw/element/types.d.ts +24 -11
  176. package/dist/excalidraw/frame.d.ts +26 -20
  177. package/dist/excalidraw/frame.js +157 -84
  178. package/dist/excalidraw/groups.d.ts +3 -3
  179. package/dist/excalidraw/groups.js +11 -3
  180. package/dist/excalidraw/history.d.ts +1 -1
  181. package/dist/excalidraw/hooks/useLibraryItemSvg.js +1 -1
  182. package/dist/excalidraw/index.d.ts +9 -10
  183. package/dist/excalidraw/index.js +16 -12
  184. package/dist/excalidraw/laser-trails.d.ts +19 -0
  185. package/dist/excalidraw/laser-trails.js +95 -0
  186. package/dist/excalidraw/locales/en.json +10 -5
  187. package/dist/excalidraw/queue.d.ts +9 -0
  188. package/dist/excalidraw/queue.js +27 -0
  189. package/dist/excalidraw/reactUtils.d.ts +14 -0
  190. package/dist/excalidraw/reactUtils.js +45 -0
  191. package/dist/excalidraw/renderer/helpers.d.ts +13 -0
  192. package/dist/excalidraw/renderer/helpers.js +39 -0
  193. package/dist/excalidraw/renderer/interactiveScene.d.ts +20 -0
  194. package/dist/excalidraw/renderer/{renderScene.js → interactiveScene.js} +199 -474
  195. package/dist/excalidraw/renderer/renderElement.d.ts +6 -6
  196. package/dist/excalidraw/renderer/renderElement.js +54 -366
  197. package/dist/excalidraw/renderer/staticScene.d.ts +11 -0
  198. package/dist/excalidraw/renderer/staticScene.js +205 -0
  199. package/dist/excalidraw/renderer/staticSvgScene.d.ts +5 -0
  200. package/dist/excalidraw/renderer/staticSvgScene.js +385 -0
  201. package/dist/excalidraw/scene/Fonts.js +2 -1
  202. package/dist/excalidraw/scene/Renderer.d.ts +1 -1
  203. package/dist/excalidraw/scene/Renderer.js +32 -20
  204. package/dist/excalidraw/scene/Scene.d.ts +10 -9
  205. package/dist/excalidraw/scene/Scene.js +45 -21
  206. package/dist/excalidraw/scene/Shape.d.ts +3 -1
  207. package/dist/excalidraw/scene/Shape.js +7 -5
  208. package/dist/excalidraw/scene/ShapeCache.d.ts +2 -1
  209. package/dist/excalidraw/scene/ShapeCache.js +1 -0
  210. package/dist/excalidraw/scene/comparisons.js +2 -1
  211. package/dist/excalidraw/scene/export.d.ts +3 -0
  212. package/dist/excalidraw/scene/export.js +20 -40
  213. package/dist/excalidraw/scene/index.d.ts +0 -1
  214. package/dist/excalidraw/scene/index.js +0 -1
  215. package/dist/excalidraw/scene/scrollbars.d.ts +1 -1
  216. package/dist/excalidraw/scene/scrollbars.js +1 -1
  217. package/dist/excalidraw/scene/selection.d.ts +5 -5
  218. package/dist/excalidraw/scene/selection.js +16 -14
  219. package/dist/excalidraw/scene/types.d.ts +11 -5
  220. package/dist/excalidraw/snapping.d.ts +7 -7
  221. package/dist/excalidraw/snapping.js +21 -20
  222. package/dist/excalidraw/types.d.ts +16 -17
  223. package/dist/excalidraw/utility-types.d.ts +7 -0
  224. package/dist/excalidraw/utils.d.ts +21 -16
  225. package/dist/excalidraw/utils.js +43 -45
  226. package/dist/{dev/en-RLIAOBCI.json → prod/en-EY7E2L5O.json} +10 -5
  227. package/dist/prod/index.css +1 -1
  228. package/dist/prod/index.js +42 -42
  229. package/dist/utils/bbox.d.ts +2 -2
  230. package/dist/utils/export.d.ts +3 -3
  231. package/dist/utils/export.js +3 -13
  232. package/dist/utils/index.d.ts +2 -2
  233. package/dist/utils/index.js +2 -2
  234. package/dist/utils/withinBounds.d.ts +1 -1
  235. package/dist/utils/withinBounds.js +5 -2
  236. package/package.json +4 -4
  237. package/dist/browser/dev/excalidraw-assets-dev/chunk-2W5GQUR4.js.map +0 -7
  238. package/dist/browser/dev/excalidraw-assets-dev/chunk-KGZXLFLR.js +0 -53497
  239. package/dist/browser/dev/excalidraw-assets-dev/chunk-KGZXLFLR.js.map +0 -7
  240. package/dist/browser/dev/excalidraw-assets-dev/image-3MFRCKYM.css +0 -5797
  241. package/dist/browser/dev/excalidraw-assets-dev/image-3MFRCKYM.css.map +0 -7
  242. package/dist/browser/prod/excalidraw-assets/chunk-4YN2HN3S.js +0 -257
  243. package/dist/browser/prod/excalidraw-assets/chunk-OWLL6VOG.js +0 -11
  244. package/dist/browser/prod/excalidraw-assets/en-ERQOR3OC.js +0 -1
  245. package/dist/browser/prod/excalidraw-assets/image-LTLHTTSE.js +0 -1
  246. package/dist/browser/prod/excalidraw-assets/image-QBL334OA.css +0 -1
  247. package/dist/excalidraw/components/LaserTool/LaserPathManager.d.ts +0 -28
  248. package/dist/excalidraw/components/LaserTool/LaserPathManager.js +0 -225
  249. package/dist/excalidraw/components/LaserTool/LaserTool.d.ts +0 -8
  250. package/dist/excalidraw/components/LaserTool/LaserTool.js +0 -15
  251. package/dist/excalidraw/renderer/renderScene.d.ts +0 -25
  252. package/dist/excalidraw/vite.config.d.mts +0 -2
  253. package/dist/excalidraw/vite.config.mjs +0 -13
  254. /package/dist/browser/dev/excalidraw-assets-dev/{en-OC6JWP3X.js.map → en-BZY7JRTM.js.map} +0 -0
  255. /package/dist/browser/dev/excalidraw-assets-dev/{image-5TVMINCA.js.map → image-CVN3YKRW.js.map} +0 -0
@@ -6,10 +6,10 @@ import { rescalePoints } from "../points";
6
6
  import { getBoundTextElement, getContainerElement } from "./textElement";
7
7
  import { LinearElementEditor } from "./linearElementEditor";
8
8
  import { ShapeCache } from "../scene/ShapeCache";
9
- import Scene from "../scene/Scene";
9
+ import { arrayToMap } from "../utils";
10
10
  export class ElementBounds {
11
11
  static boundsCache = new WeakMap();
12
- static getBounds(element) {
12
+ static getBounds(element, elementsMap) {
13
13
  const cachedBounds = ElementBounds.boundsCache.get(element);
14
14
  if (cachedBounds?.version &&
15
15
  cachedBounds.version === element.version &&
@@ -18,22 +18,16 @@ export class ElementBounds {
18
18
  !isBoundToContainer(element)) {
19
19
  return cachedBounds.bounds;
20
20
  }
21
- const bounds = ElementBounds.calculateBounds(element);
22
- // hack to ensure that downstream checks could retrieve element Scene
23
- // so as to have correctly calculated bounds
24
- // FIXME remove when we get rid of all the id:Scene / element:Scene mapping
25
- const shouldCache = Scene.getScene(element);
26
- if (shouldCache) {
27
- ElementBounds.boundsCache.set(element, {
28
- version: element.version,
29
- bounds,
30
- });
31
- }
21
+ const bounds = ElementBounds.calculateBounds(element, elementsMap);
22
+ ElementBounds.boundsCache.set(element, {
23
+ version: element.version,
24
+ bounds,
25
+ });
32
26
  return bounds;
33
27
  }
34
- static calculateBounds(element) {
28
+ static calculateBounds(element, elementsMap) {
35
29
  let bounds;
36
- const [x1, y1, x2, y2, cx, cy] = getElementAbsoluteCoords(element);
30
+ const [x1, y1, x2, y2, cx, cy] = getElementAbsoluteCoords(element, elementsMap);
37
31
  if (isFreeDrawElement(element)) {
38
32
  const [minX, minY, maxX, maxY] = getBoundsFromPoints(element.points.map(([x, y]) => rotate(x, y, cx - element.x, cy - element.y, element.angle)));
39
33
  return [
@@ -44,7 +38,7 @@ export class ElementBounds {
44
38
  ];
45
39
  }
46
40
  else if (isLinearElement(element)) {
47
- bounds = getLinearElementRotatedBounds(element, cx, cy);
41
+ bounds = getLinearElementRotatedBounds(element, cx, cy, elementsMap);
48
42
  }
49
43
  else if (element.type === "diamond") {
50
44
  const [x11, y11] = rotate(cx, y1, cx, cy, element.angle);
@@ -84,17 +78,19 @@ export class ElementBounds {
84
78
  //
85
79
  // If the element is created from right to left, the width is going to be negative
86
80
  // This set of functions retrieves the absolute position of the 4 points.
87
- export const getElementAbsoluteCoords = (element, includeBoundText = false) => {
81
+ export const getElementAbsoluteCoords = (element, elementsMap, includeBoundText = false) => {
88
82
  if (isFreeDrawElement(element)) {
89
83
  return getFreeDrawElementAbsoluteCoords(element);
90
84
  }
91
85
  else if (isLinearElement(element)) {
92
- return LinearElementEditor.getElementAbsoluteCoords(element, includeBoundText);
86
+ return LinearElementEditor.getElementAbsoluteCoords(element, elementsMap, includeBoundText);
93
87
  }
94
88
  else if (isTextElement(element)) {
95
- const container = getContainerElement(element);
89
+ const container = elementsMap
90
+ ? getContainerElement(element, elementsMap)
91
+ : null;
96
92
  if (isArrowElement(container)) {
97
- const coords = LinearElementEditor.getBoundTextElementPosition(container, element);
93
+ const coords = LinearElementEditor.getBoundTextElementPosition(container, element, elementsMap);
98
94
  return [
99
95
  coords.x,
100
96
  coords.y,
@@ -119,8 +115,8 @@ export const getElementAbsoluteCoords = (element, includeBoundText = false) => {
119
115
  * that can be used for visual collision detection (useful for frames)
120
116
  * as opposed to bounding box collision detection
121
117
  */
122
- export const getElementLineSegments = (element) => {
123
- const [x1, y1, x2, y2, cx, cy] = getElementAbsoluteCoords(element);
118
+ export const getElementLineSegments = (element, elementsMap) => {
119
+ const [x1, y1, x2, y2, cx, cy] = getElementAbsoluteCoords(element, elementsMap);
124
120
  const center = [cx, cy];
125
121
  if (isLinearElement(element) || isFreeDrawElement(element)) {
126
122
  const segments = [];
@@ -459,14 +455,14 @@ const generateLinearElementShape = (element) => {
459
455
  })();
460
456
  return generator[method](element.points, options);
461
457
  };
462
- const getLinearElementRotatedBounds = (element, cx, cy) => {
458
+ const getLinearElementRotatedBounds = (element, cx, cy, elementsMap) => {
459
+ const boundTextElement = getBoundTextElement(element, elementsMap);
463
460
  if (element.points.length < 2) {
464
461
  const [pointX, pointY] = element.points[0];
465
462
  const [x, y] = rotate(element.x + pointX, element.y + pointY, cx, cy, element.angle);
466
463
  let coords = [x, y, x, y];
467
- const boundTextElement = getBoundTextElement(element);
468
464
  if (boundTextElement) {
469
- const coordsWithBoundText = LinearElementEditor.getMinMaxXYWithBoundText(element, [x, y, x, y], boundTextElement);
465
+ const coordsWithBoundText = LinearElementEditor.getMinMaxXYWithBoundText(element, elementsMap, [x, y, x, y], boundTextElement);
470
466
  coords = [
471
467
  coordsWithBoundText[0],
472
468
  coordsWithBoundText[1],
@@ -483,9 +479,8 @@ const getLinearElementRotatedBounds = (element, cx, cy) => {
483
479
  const transformXY = (x, y) => rotate(element.x + x, element.y + y, cx, cy, element.angle);
484
480
  const res = getMinMaxXYFromCurvePathOps(ops, transformXY);
485
481
  let coords = [res[0], res[1], res[2], res[3]];
486
- const boundTextElement = getBoundTextElement(element);
487
482
  if (boundTextElement) {
488
- const coordsWithBoundText = LinearElementEditor.getMinMaxXYWithBoundText(element, coords, boundTextElement);
483
+ const coordsWithBoundText = LinearElementEditor.getMinMaxXYWithBoundText(element, elementsMap, coords, boundTextElement);
489
484
  coords = [
490
485
  coordsWithBoundText[0],
491
486
  coordsWithBoundText[1],
@@ -495,8 +490,8 @@ const getLinearElementRotatedBounds = (element, cx, cy) => {
495
490
  }
496
491
  return coords;
497
492
  };
498
- export const getElementBounds = (element) => {
499
- return ElementBounds.getBounds(element);
493
+ export const getElementBounds = (element, elementsMap) => {
494
+ return ElementBounds.getBounds(element, elementsMap);
500
495
  };
501
496
  export const getCommonBounds = (elements) => {
502
497
  if (!elements.length) {
@@ -506,8 +501,9 @@ export const getCommonBounds = (elements) => {
506
501
  let maxX = -Infinity;
507
502
  let minY = Infinity;
508
503
  let maxY = -Infinity;
504
+ const elementsMap = arrayToMap(elements);
509
505
  elements.forEach((element) => {
510
- const [x1, y1, x2, y2] = getElementBounds(element);
506
+ const [x1, y1, x2, y2] = getElementBounds(element, elementsMap);
511
507
  minX = Math.min(minX, x1);
512
508
  minY = Math.min(minY, y1);
513
509
  maxX = Math.max(maxX, x2);
@@ -577,15 +573,16 @@ export const getClosestElementBounds = (elements, from) => {
577
573
  }
578
574
  let minDistance = Infinity;
579
575
  let closestElement = elements[0];
576
+ const elementsMap = arrayToMap(elements);
580
577
  elements.forEach((element) => {
581
- const [x1, y1, x2, y2] = getElementBounds(element);
578
+ const [x1, y1, x2, y2] = getElementBounds(element, elementsMap);
582
579
  const distance = distance2d((x1 + x2) / 2, (y1 + y2) / 2, from.x, from.y);
583
580
  if (distance < minDistance) {
584
581
  minDistance = distance;
585
582
  closestElement = element;
586
583
  }
587
584
  });
588
- return getElementBounds(closestElement);
585
+ return getElementBounds(closestElement, elementsMap);
589
586
  };
590
587
  export const getCommonBoundingBox = (elements) => {
591
588
  const [minX, minY, maxX, maxY] = getCommonBounds(elements);
@@ -1,21 +1,21 @@
1
1
  import * as GA from "../ga";
2
- import { NonDeletedExcalidrawElement, ExcalidrawBindableElement, ExcalidrawElement, ExcalidrawRectangleElement, ExcalidrawDiamondElement, ExcalidrawTextElement, ExcalidrawEllipseElement, NonDeleted, ExcalidrawImageElement, ExcalidrawFrameLikeElement, ExcalidrawIframeLikeElement } from "./types";
2
+ import { NonDeletedExcalidrawElement, ExcalidrawBindableElement, ExcalidrawElement, ExcalidrawRectangleElement, ExcalidrawDiamondElement, ExcalidrawTextElement, ExcalidrawEllipseElement, NonDeleted, ExcalidrawImageElement, ExcalidrawFrameLikeElement, ExcalidrawIframeLikeElement, ElementsMap } from "./types";
3
3
  import { FrameNameBoundsCache, Point } from "../types";
4
4
  import { AppState } from "../types";
5
- export declare const hitTest: (element: NonDeletedExcalidrawElement, appState: AppState, frameNameBoundsCache: FrameNameBoundsCache, x: number, y: number) => boolean;
6
- export declare const isHittingElementBoundingBoxWithoutHittingElement: (element: NonDeletedExcalidrawElement, appState: AppState, frameNameBoundsCache: FrameNameBoundsCache, x: number, y: number) => boolean;
7
- export declare const isHittingElementNotConsideringBoundingBox: (element: NonDeletedExcalidrawElement, appState: AppState, frameNameBoundsCache: FrameNameBoundsCache | null, point: readonly [number, number]) => boolean;
8
- export declare const isPointHittingElementBoundingBox: (element: NonDeleted<ExcalidrawElement>, [x, y]: readonly [number, number], threshold: number, frameNameBoundsCache: FrameNameBoundsCache | null) => boolean;
5
+ export declare const hitTest: (element: NonDeletedExcalidrawElement, appState: AppState, frameNameBoundsCache: FrameNameBoundsCache, x: number, y: number, elementsMap: ElementsMap) => boolean;
6
+ export declare const isHittingElementBoundingBoxWithoutHittingElement: (element: NonDeletedExcalidrawElement, appState: AppState, frameNameBoundsCache: FrameNameBoundsCache, x: number, y: number, elementsMap: ElementsMap) => boolean;
7
+ export declare const isHittingElementNotConsideringBoundingBox: (element: NonDeletedExcalidrawElement, appState: AppState, frameNameBoundsCache: FrameNameBoundsCache | null, point: readonly [number, number], elementsMap: ElementsMap) => boolean;
8
+ export declare const isPointHittingElementBoundingBox: (element: NonDeleted<ExcalidrawElement>, elementsMap: ElementsMap, [x, y]: readonly [number, number], threshold: number, frameNameBoundsCache: FrameNameBoundsCache | null) => boolean;
9
9
  export declare const bindingBorderTest: (element: NonDeleted<ExcalidrawBindableElement>, { x, y }: {
10
10
  x: number;
11
11
  y: number;
12
- }) => boolean;
12
+ }, elementsMap: ElementsMap) => boolean;
13
13
  export declare const maxBindingGap: (element: ExcalidrawElement, elementWidth: number, elementHeight: number) => number;
14
- export declare const distanceToBindableElement: (element: ExcalidrawBindableElement, point: readonly [number, number]) => number;
15
- export declare const pointInAbsoluteCoords: (element: ExcalidrawElement, point: readonly [number, number]) => readonly [number, number];
16
- export declare const determineFocusDistance: (element: ExcalidrawBindableElement, a: readonly [number, number], b: readonly [number, number]) => number;
17
- export declare const determineFocusPoint: (element: ExcalidrawBindableElement, focus: number, adjecentPoint: readonly [number, number]) => readonly [number, number];
18
- export declare const intersectElementWithLine: (element: ExcalidrawBindableElement, a: readonly [number, number], b: readonly [number, number], gap?: number) => Point[];
14
+ export declare const distanceToBindableElement: (element: ExcalidrawBindableElement, point: readonly [number, number], elementsMap: ElementsMap) => number;
15
+ export declare const pointInAbsoluteCoords: (element: ExcalidrawElement, elementsMap: ElementsMap, point: readonly [number, number]) => readonly [number, number];
16
+ export declare const determineFocusDistance: (element: ExcalidrawBindableElement, a: readonly [number, number], b: readonly [number, number], elementsMap: ElementsMap) => number;
17
+ export declare const determineFocusPoint: (element: ExcalidrawBindableElement, focus: number, adjecentPoint: readonly [number, number], elementsMap: ElementsMap) => readonly [number, number];
18
+ export declare const intersectElementWithLine: (element: ExcalidrawBindableElement, a: readonly [number, number], b: readonly [number, number], gap: number | undefined, elementsMap: ElementsMap) => Point[];
19
19
  export declare const getCircleIntersections: (center: readonly [number, number, number, number, number, number, number, number], radius: number, line: readonly [number, number, number, number, number, number, number, number]) => GA.Point[];
20
20
  export declare const findFocusPointForEllipse: (ellipse: ExcalidrawEllipseElement, relativeDistance: number, point: readonly [number, number, number, number, number, number, number, number]) => readonly [number, number, number, number, number, number, number, number];
21
21
  export declare const findFocusPointForRectangulars: (element: ExcalidrawRectangleElement | ExcalidrawImageElement | ExcalidrawDiamondElement | ExcalidrawTextElement | ExcalidrawIframeLikeElement | ExcalidrawFrameLikeElement, relativeDistance: number, point: readonly [number, number, number, number, number, number, number, number]) => readonly [number, number, number, number, number, number, number, number];
@@ -27,36 +27,36 @@ const isElementDraggableFromInside = (element) => {
27
27
  }
28
28
  return isDraggableFromInside || isImageElement(element);
29
29
  };
30
- export const hitTest = (element, appState, frameNameBoundsCache, x, y) => {
30
+ export const hitTest = (element, appState, frameNameBoundsCache, x, y, elementsMap) => {
31
31
  // How many pixels off the shape boundary we still consider a hit
32
32
  const threshold = 10 / appState.zoom.value;
33
33
  const point = [x, y];
34
34
  if (isElementSelected(appState, element) &&
35
35
  shouldShowBoundingBox([element], appState)) {
36
- return isPointHittingElementBoundingBox(element, point, threshold, frameNameBoundsCache);
36
+ return isPointHittingElementBoundingBox(element, elementsMap, point, threshold, frameNameBoundsCache);
37
37
  }
38
- const boundTextElement = getBoundTextElement(element);
38
+ const boundTextElement = getBoundTextElement(element, elementsMap);
39
39
  if (boundTextElement) {
40
- const isHittingBoundTextElement = hitTest(boundTextElement, appState, frameNameBoundsCache, x, y);
40
+ const isHittingBoundTextElement = hitTest(boundTextElement, appState, frameNameBoundsCache, x, y, elementsMap);
41
41
  if (isHittingBoundTextElement) {
42
42
  return true;
43
43
  }
44
44
  }
45
- return isHittingElementNotConsideringBoundingBox(element, appState, frameNameBoundsCache, point);
45
+ return isHittingElementNotConsideringBoundingBox(element, appState, frameNameBoundsCache, point, elementsMap);
46
46
  };
47
- export const isHittingElementBoundingBoxWithoutHittingElement = (element, appState, frameNameBoundsCache, x, y) => {
47
+ export const isHittingElementBoundingBoxWithoutHittingElement = (element, appState, frameNameBoundsCache, x, y, elementsMap) => {
48
48
  const threshold = 10 / appState.zoom.value;
49
49
  // So that bound text element hit is considered within bounding box of container even if its outside actual bounding box of element
50
50
  // eg for linear elements text can be outside the element bounding box
51
- const boundTextElement = getBoundTextElement(element);
51
+ const boundTextElement = getBoundTextElement(element, elementsMap);
52
52
  if (boundTextElement &&
53
- hitTest(boundTextElement, appState, frameNameBoundsCache, x, y)) {
53
+ hitTest(boundTextElement, appState, frameNameBoundsCache, x, y, elementsMap)) {
54
54
  return false;
55
55
  }
56
- return (!isHittingElementNotConsideringBoundingBox(element, appState, frameNameBoundsCache, [x, y]) &&
57
- isPointHittingElementBoundingBox(element, [x, y], threshold, frameNameBoundsCache));
56
+ return (!isHittingElementNotConsideringBoundingBox(element, appState, frameNameBoundsCache, [x, y], elementsMap) &&
57
+ isPointHittingElementBoundingBox(element, elementsMap, [x, y], threshold, frameNameBoundsCache));
58
58
  };
59
- export const isHittingElementNotConsideringBoundingBox = (element, appState, frameNameBoundsCache, point) => {
59
+ export const isHittingElementNotConsideringBoundingBox = (element, appState, frameNameBoundsCache, point, elementsMap) => {
60
60
  const threshold = 10 / appState.zoom.value;
61
61
  const check = isTextElement(element)
62
62
  ? isStrictlyInside
@@ -65,6 +65,7 @@ export const isHittingElementNotConsideringBoundingBox = (element, appState, fra
65
65
  : isNearCheck;
66
66
  return hitTestPointAgainstElement({
67
67
  element,
68
+ elementsMap,
68
69
  point,
69
70
  threshold,
70
71
  check,
@@ -72,7 +73,7 @@ export const isHittingElementNotConsideringBoundingBox = (element, appState, fra
72
73
  });
73
74
  };
74
75
  const isElementSelected = (appState, element) => appState.selectedElementIds[element.id];
75
- export const isPointHittingElementBoundingBox = (element, [x, y], threshold, frameNameBoundsCache) => {
76
+ export const isPointHittingElementBoundingBox = (element, elementsMap, [x, y], threshold, frameNameBoundsCache) => {
76
77
  // frames needs be checked differently so as to be able to drag it
77
78
  // by its frame, whether it has been selected or not
78
79
  // this logic here is not ideal
@@ -80,13 +81,14 @@ export const isPointHittingElementBoundingBox = (element, [x, y], threshold, fra
80
81
  if (isFrameLikeElement(element)) {
81
82
  return hitTestPointAgainstElement({
82
83
  element,
84
+ elementsMap,
83
85
  point: [x, y],
84
86
  threshold,
85
87
  check: isInsideCheck,
86
88
  frameNameBoundsCache,
87
89
  });
88
90
  }
89
- const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
91
+ const [x1, y1, x2, y2] = getElementAbsoluteCoords(element, elementsMap);
90
92
  const elementCenterX = (x1 + x2) / 2;
91
93
  const elementCenterY = (y1 + y2) / 2;
92
94
  // reverse rotate to take element's angle into account.
@@ -96,12 +98,13 @@ export const isPointHittingElementBoundingBox = (element, [x, y], threshold, fra
96
98
  rotatedY > y1 - threshold &&
97
99
  rotatedY < y2 + threshold);
98
100
  };
99
- export const bindingBorderTest = (element, { x, y }) => {
101
+ export const bindingBorderTest = (element, { x, y }, elementsMap) => {
100
102
  const threshold = maxBindingGap(element, element.width, element.height);
101
103
  const check = isOutsideCheck;
102
104
  const point = [x, y];
103
105
  return hitTestPointAgainstElement({
104
106
  element,
107
+ elementsMap,
105
108
  point,
106
109
  threshold,
107
110
  check,
@@ -124,13 +127,13 @@ const hitTestPointAgainstElement = (args) => {
124
127
  case "text":
125
128
  case "diamond":
126
129
  case "ellipse":
127
- const distance = distanceToBindableElement(args.element, args.point);
130
+ const distance = distanceToBindableElement(args.element, args.point, args.elementsMap);
128
131
  return args.check(distance, args.threshold);
129
132
  case "freedraw": {
130
- if (!args.check(distanceToRectangle(args.element, args.point), args.threshold)) {
133
+ if (!args.check(distanceToRectangle(args.element, args.point, args.elementsMap), args.threshold)) {
131
134
  return false;
132
135
  }
133
- return hitTestFreeDrawElement(args.element, args.point, args.threshold);
136
+ return hitTestFreeDrawElement(args.element, args.point, args.threshold, args.elementsMap);
134
137
  }
135
138
  case "arrow":
136
139
  case "line":
@@ -141,7 +144,7 @@ const hitTestPointAgainstElement = (args) => {
141
144
  case "frame":
142
145
  case "magicframe": {
143
146
  // check distance to frame element first
144
- if (args.check(distanceToBindableElement(args.element, args.point), args.threshold)) {
147
+ if (args.check(distanceToBindableElement(args.element, args.point, args.elementsMap), args.threshold)) {
145
148
  return true;
146
149
  }
147
150
  const frameNameBounds = args.frameNameBoundsCache?.get(args.element);
@@ -152,7 +155,7 @@ const hitTestPointAgainstElement = (args) => {
152
155
  }
153
156
  }
154
157
  };
155
- export const distanceToBindableElement = (element, point) => {
158
+ export const distanceToBindableElement = (element, point, elementsMap) => {
156
159
  switch (element.type) {
157
160
  case "rectangle":
158
161
  case "image":
@@ -161,11 +164,11 @@ export const distanceToBindableElement = (element, point) => {
161
164
  case "embeddable":
162
165
  case "frame":
163
166
  case "magicframe":
164
- return distanceToRectangle(element, point);
167
+ return distanceToRectangle(element, point, elementsMap);
165
168
  case "diamond":
166
- return distanceToDiamond(element, point);
169
+ return distanceToDiamond(element, point, elementsMap);
167
170
  case "ellipse":
168
- return distanceToEllipse(element, point);
171
+ return distanceToEllipse(element, point, elementsMap);
169
172
  }
170
173
  };
171
174
  const isStrictlyInside = (distance, threshold) => {
@@ -180,25 +183,25 @@ const isNearCheck = (distance, threshold) => {
180
183
  const isOutsideCheck = (distance, threshold) => {
181
184
  return 0 <= distance && distance < threshold;
182
185
  };
183
- const distanceToRectangle = (element, point) => {
184
- const [, pointRel, hwidth, hheight] = pointRelativeToElement(element, point);
186
+ const distanceToRectangle = (element, point, elementsMap) => {
187
+ const [, pointRel, hwidth, hheight] = pointRelativeToElement(element, point, elementsMap);
185
188
  return Math.max(GAPoint.distanceToLine(pointRel, GALine.equation(0, 1, -hheight)), GAPoint.distanceToLine(pointRel, GALine.equation(1, 0, -hwidth)));
186
189
  };
187
190
  const distanceToRectangleBox = (box, point) => {
188
191
  const [, pointRel, hwidth, hheight] = pointRelativeToDivElement(point, box);
189
192
  return Math.max(GAPoint.distanceToLine(pointRel, GALine.equation(0, 1, -hheight)), GAPoint.distanceToLine(pointRel, GALine.equation(1, 0, -hwidth)));
190
193
  };
191
- const distanceToDiamond = (element, point) => {
192
- const [, pointRel, hwidth, hheight] = pointRelativeToElement(element, point);
194
+ const distanceToDiamond = (element, point, elementsMap) => {
195
+ const [, pointRel, hwidth, hheight] = pointRelativeToElement(element, point, elementsMap);
193
196
  const side = GALine.equation(hheight, hwidth, -hheight * hwidth);
194
197
  return GAPoint.distanceToLine(pointRel, side);
195
198
  };
196
- const distanceToEllipse = (element, point) => {
197
- const [pointRel, tangent] = ellipseParamsForTest(element, point);
199
+ const distanceToEllipse = (element, point, elementsMap) => {
200
+ const [pointRel, tangent] = ellipseParamsForTest(element, point, elementsMap);
198
201
  return -GALine.sign(tangent) * GAPoint.distanceToLine(pointRel, tangent);
199
202
  };
200
- const ellipseParamsForTest = (element, point) => {
201
- const [, pointRel, hwidth, hheight] = pointRelativeToElement(element, point);
203
+ const ellipseParamsForTest = (element, point, elementsMap) => {
204
+ const [, pointRel, hwidth, hheight] = pointRelativeToElement(element, point, elementsMap);
202
205
  const [px, py] = GAPoint.toTuple(pointRel);
203
206
  // We're working in positive quadrant, so start with `t = 45deg`, `tx=cos(t)`
204
207
  let tx = 0.707;
@@ -228,7 +231,7 @@ const ellipseParamsForTest = (element, point) => {
228
231
  const tangent = GALine.orthogonalThrough(pointRel, closestPoint);
229
232
  return [pointRel, tangent];
230
233
  };
231
- const hitTestFreeDrawElement = (element, point, threshold) => {
234
+ const hitTestFreeDrawElement = (element, point, threshold, elementsMap) => {
232
235
  // Check point-distance-to-line-segment for every segment in the
233
236
  // element's points (its input points, not its outline points).
234
237
  // This is... okay? It's plenty fast, but the GA library may
@@ -241,7 +244,7 @@ const hitTestFreeDrawElement = (element, point, threshold) => {
241
244
  }
242
245
  else {
243
246
  // Counter-rotate the point around center before testing
244
- const [minX, minY, maxX, maxY] = getElementAbsoluteCoords(element);
247
+ const [minX, minY, maxX, maxY] = getElementAbsoluteCoords(element, elementsMap);
245
248
  const rotatedPoint = rotatePoint(point, [minX + (maxX - minX) / 2, minY + (maxY - minY) / 2], -element.angle);
246
249
  x = rotatedPoint[0] - element.x;
247
250
  y = rotatedPoint[1] - element.y;
@@ -285,7 +288,7 @@ const hitTestLinear = (args) => {
285
288
  if (!ShapeCache.get(element)) {
286
289
  return false;
287
290
  }
288
- const [point, pointAbs, hwidth, hheight] = pointRelativeToElement(args.element, args.point);
291
+ const [point, pointAbs, hwidth, hheight] = pointRelativeToElement(args.element, args.point, args.elementsMap);
289
292
  const side1 = GALine.equation(0, 1, -hheight);
290
293
  const side2 = GALine.equation(1, 0, -hwidth);
291
294
  if (!isInsideCheck(GAPoint.distanceToLine(pointAbs, side1), threshold) ||
@@ -318,9 +321,9 @@ const hitTestLinear = (args) => {
318
321
  // Rectangles, diamonds and ellipses are symmetrical over axes,
319
322
  // and other elements have a rectangular boundary,
320
323
  // so we only need to perform hit tests for the positive quadrant.
321
- const pointRelativeToElement = (element, pointTuple) => {
324
+ const pointRelativeToElement = (element, pointTuple, elementsMap) => {
322
325
  const point = GAPoint.from(pointTuple);
323
- const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
326
+ const [x1, y1, x2, y2] = getElementAbsoluteCoords(element, elementsMap);
324
327
  const center = coordsCenter(x1, y1, x2, y2);
325
328
  // GA has angle orientation opposite to `rotate`
326
329
  const rotate = GATransform.rotation(center, element.angle);
@@ -348,18 +351,18 @@ const pointRelativeToDivElement = (pointTuple, rectangle) => {
348
351
  return [pointRelToPos, pointRelToCenterAbs, halfWidth, halfHeight];
349
352
  };
350
353
  // Returns point in absolute coordinates
351
- export const pointInAbsoluteCoords = (element,
354
+ export const pointInAbsoluteCoords = (element, elementsMap,
352
355
  // Point relative to the element position
353
356
  point) => {
354
357
  const [x, y] = point;
355
- const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
358
+ const [x1, y1, x2, y2] = getElementAbsoluteCoords(element, elementsMap);
356
359
  const cx = (x2 - x1) / 2;
357
360
  const cy = (y2 - y1) / 2;
358
361
  const [rotatedX, rotatedY] = rotate(x, y, cx, cy, element.angle);
359
362
  return [element.x + rotatedX, element.y + rotatedY];
360
363
  };
361
- const relativizationToElementCenter = (element) => {
362
- const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
364
+ const relativizationToElementCenter = (element, elementsMap) => {
365
+ const [x1, y1, x2, y2] = getElementAbsoluteCoords(element, elementsMap);
363
366
  const center = coordsCenter(x1, y1, x2, y2);
364
367
  // GA has angle orientation opposite to `rotate`
365
368
  const rotate = GATransform.rotation(center, element.angle);
@@ -378,8 +381,8 @@ export const determineFocusDistance = (element,
378
381
  // Point on the line, in absolute coordinates
379
382
  a,
380
383
  // Another point on the line, in absolute coordinates (closer to element)
381
- b) => {
382
- const relateToCenter = relativizationToElementCenter(element);
384
+ b, elementsMap) => {
385
+ const relateToCenter = relativizationToElementCenter(element, elementsMap);
383
386
  const aRel = GATransform.apply(relateToCenter, GAPoint.from(a));
384
387
  const bRel = GATransform.apply(relateToCenter, GAPoint.from(b));
385
388
  const line = GALine.through(aRel, bRel);
@@ -414,13 +417,13 @@ b) => {
414
417
  export const determineFocusPoint = (element,
415
418
  // The oriented, relative distance from the center of `element` of the
416
419
  // returned focusPoint
417
- focus, adjecentPoint) => {
420
+ focus, adjecentPoint, elementsMap) => {
418
421
  if (focus === 0) {
419
- const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
422
+ const [x1, y1, x2, y2] = getElementAbsoluteCoords(element, elementsMap);
420
423
  const center = coordsCenter(x1, y1, x2, y2);
421
424
  return GAPoint.toTuple(center);
422
425
  }
423
- const relateToCenter = relativizationToElementCenter(element);
426
+ const relateToCenter = relativizationToElementCenter(element, elementsMap);
424
427
  const adjecentPointRel = GATransform.apply(relateToCenter, GAPoint.from(adjecentPoint));
425
428
  const reverseRelateToCenter = GA.reverse(relateToCenter);
426
429
  let point;
@@ -449,8 +452,8 @@ a,
449
452
  // Another point on the line, in absolute coordinates
450
453
  b,
451
454
  // If given, the element is inflated by this value
452
- gap = 0) => {
453
- const relateToCenter = relativizationToElementCenter(element);
455
+ gap = 0, elementsMap) => {
456
+ const relateToCenter = relativizationToElementCenter(element, elementsMap);
454
457
  const aRel = GATransform.apply(relateToCenter, GAPoint.from(a));
455
458
  const bRel = GATransform.apply(relateToCenter, GAPoint.from(b));
456
459
  const line = GALine.through(aRel, bRel);
@@ -0,0 +1,11 @@
1
+ import { ExcalidrawTextContainer } from "./types";
2
+ export declare const originalContainerCache: {
3
+ [id: ExcalidrawTextContainer["id"]]: {
4
+ height: ExcalidrawTextContainer["height"];
5
+ } | undefined;
6
+ };
7
+ export declare const updateOriginalContainerCache: (id: ExcalidrawTextContainer["id"], height: ExcalidrawTextContainer["height"]) => {
8
+ height: ExcalidrawTextContainer["height"];
9
+ };
10
+ export declare const resetOriginalContainerCache: (id: ExcalidrawTextContainer["id"]) => void;
11
+ export declare const getOriginalContainerHeightFromCache: (id: ExcalidrawTextContainer["id"]) => number | null;
@@ -0,0 +1,14 @@
1
+ export const originalContainerCache = {};
2
+ export const updateOriginalContainerCache = (id, height) => {
3
+ const data = originalContainerCache[id] || (originalContainerCache[id] = { height });
4
+ data.height = height;
5
+ return data;
6
+ };
7
+ export const resetOriginalContainerCache = (id) => {
8
+ if (originalContainerCache[id]) {
9
+ delete originalContainerCache[id];
10
+ }
11
+ };
12
+ export const getOriginalContainerHeightFromCache = (id) => {
13
+ return originalContainerCache[id]?.height ?? null;
14
+ };
@@ -3,9 +3,8 @@ import { getCommonBounds } from "./bounds";
3
3
  import { mutateElement } from "./mutateElement";
4
4
  import { getPerfectElementSize } from "./sizeHelpers";
5
5
  import { getBoundTextElement } from "./textElement";
6
- import { isSelectedViaGroup } from "../groups";
7
6
  import { getGridPoint } from "../math";
8
- import { isArrowElement, isBoundToContainer, isFrameLikeElement, } from "./typeChecks";
7
+ import { isArrowElement, isFrameLikeElement } from "./typeChecks";
9
8
  export const dragSelectedElements = (pointerDownState, selectedElements, offset, appState, scene, snapOffset, gridSize) => {
10
9
  // we do not want a frame and its elements to be selected at the same time
11
10
  // but when it happens (due to some bug), we want to avoid updating element
@@ -15,33 +14,25 @@ export const dragSelectedElements = (pointerDownState, selectedElements, offset,
15
14
  .filter((e) => isFrameLikeElement(e))
16
15
  .map((f) => f.id);
17
16
  if (frames.length > 0) {
18
- const elementsInFrames = scene
19
- .getNonDeletedElements()
20
- .filter((e) => !isBoundToContainer(e))
21
- .filter((e) => e.frameId !== null)
22
- .filter((e) => frames.includes(e.frameId));
23
- elementsInFrames.forEach((element) => elementsToUpdate.add(element));
17
+ for (const element of scene.getNonDeletedElements()) {
18
+ if (element.frameId !== null && frames.includes(element.frameId)) {
19
+ elementsToUpdate.add(element);
20
+ }
21
+ }
24
22
  }
25
23
  const commonBounds = getCommonBounds(Array.from(elementsToUpdate).map((el) => pointerDownState.originalElements.get(el.id) ?? el));
26
24
  const adjustedOffset = calculateOffset(commonBounds, offset, snapOffset, gridSize);
27
25
  elementsToUpdate.forEach((element) => {
28
26
  updateElementCoords(pointerDownState, element, adjustedOffset);
29
- // update coords of bound text only if we're dragging the container directly
30
- // (we don't drag the group that it's part of)
31
27
  if (
32
- // Don't update coords of arrow label since we calculate its position during render
33
- !isArrowElement(element) &&
34
- // container isn't part of any group
35
- // (perf optim so we don't check `isSelectedViaGroup()` in every case)
36
- (!element.groupIds.length ||
37
- // container is part of a group, but we're dragging the container directly
38
- (appState.editingGroupId && !isSelectedViaGroup(appState, element)))) {
39
- const textElement = getBoundTextElement(element);
28
+ // skip arrow labels since we calculate its position during render
29
+ !isArrowElement(element)) {
30
+ const textElement = getBoundTextElement(element, scene.getNonDeletedElementsMap());
40
31
  if (textElement) {
41
32
  updateElementCoords(pointerDownState, textElement, adjustedOffset);
42
33
  }
43
34
  }
44
- updateBoundElements(element, {
35
+ updateBoundElements(element, scene.getElementsMapIncludingDeleted(), {
45
36
  simultaneouslyUpdated: Array.from(elementsToUpdate),
46
37
  });
47
38
  });
@@ -1,9 +1,8 @@
1
1
  /// <reference types="react" />
2
2
  import { ExcalidrawProps } from "../types";
3
- import { ExcalidrawElement, ExcalidrawIframeLikeElement, IframeData, NonDeletedExcalidrawElement } from "./types";
3
+ import { ExcalidrawElement, ExcalidrawIframeLikeElement, IframeData } from "./types";
4
4
  export declare const createSrcDoc: (body: string) => string;
5
5
  export declare const getEmbedLink: (link: string | null | undefined) => IframeData | null;
6
- export declare const isIframeLikeOrItsLabel: (element: NonDeletedExcalidrawElement) => Boolean;
7
6
  export declare const createPlaceholderEmbeddableLabel: (element: ExcalidrawIframeLikeElement) => ExcalidrawElement;
8
7
  export declare const actionSetEmbeddableAsActiveTool: {
9
8
  name: "setEmbeddableAsActiveTool";
@@ -26,13 +25,13 @@ export declare const actionSetEmbeddableAsActiveTool: {
26
25
  isLoading: boolean;
27
26
  errorMessage: import("react").ReactNode;
28
27
  activeEmbeddable: {
29
- element: NonDeletedExcalidrawElement;
30
- state: "active" | "hover";
28
+ element: import("./types").NonDeletedExcalidrawElement;
29
+ state: "hover" | "active";
31
30
  } | null;
32
- draggingElement: NonDeletedExcalidrawElement | null;
33
- resizingElement: NonDeletedExcalidrawElement | null;
31
+ draggingElement: import("./types").NonDeletedExcalidrawElement | null;
32
+ resizingElement: import("./types").NonDeletedExcalidrawElement | null;
34
33
  multiElement: import("./types").NonDeleted<import("./types").ExcalidrawLinearElement> | null;
35
- selectionElement: NonDeletedExcalidrawElement | null;
34
+ selectionElement: import("./types").NonDeletedExcalidrawElement | null;
36
35
  isBindingEnabled: boolean;
37
36
  startBoundElement: import("./types").NonDeleted<import("./types").ExcalidrawBindableElement> | null;
38
37
  suggestedBindings: import("./binding").SuggestedBinding[];
@@ -45,7 +44,7 @@ export declare const actionSetEmbeddableAsActiveTool: {
45
44
  };
46
45
  editingFrame: string | null;
47
46
  elementsToHighlight: import("./types").NonDeleted<ExcalidrawElement>[] | null;
48
- editingElement: NonDeletedExcalidrawElement | null;
47
+ editingElement: import("./types").NonDeletedExcalidrawElement | null;
49
48
  editingLinearElement: import("./linearElementEditor").LinearElementEditor | null;
50
49
  penMode: boolean;
51
50
  penDetected: boolean;
@@ -71,7 +70,7 @@ export declare const actionSetEmbeddableAsActiveTool: {
71
70
  scrollY: number;
72
71
  cursorButton: "up" | "down";
73
72
  scrolledOutside: boolean;
74
- name: string;
73
+ name: string | null;
75
74
  isResizing: boolean;
76
75
  isRotating: boolean;
77
76
  zoom: Readonly<{
@@ -84,14 +83,14 @@ export declare const actionSetEmbeddableAsActiveTool: {
84
83
  tab?: string | undefined;
85
84
  } | null;
86
85
  openDialog: {
87
- name: "help" | "imageExport" | "jsonExport";
86
+ name: "imageExport" | "help" | "jsonExport";
88
87
  } | {
89
88
  name: "settings";
90
89
  source: "settings" | "tool" | "generation";
91
90
  tab: "text-to-diagram" | "diagram-to-code";
92
91
  } | {
93
92
  name: "ttd";
94
- tab: "mermaid" | "text-to-diagram";
93
+ tab: "text-to-diagram" | "mermaid";
95
94
  } | null;
96
95
  defaultSidebarDockedPreference: boolean;
97
96
  lastPointerDownWith: import("./types").PointerType;
@@ -148,7 +147,7 @@ export declare const actionSetEmbeddableAsActiveTool: {
148
147
  data: import("../charts").Spreadsheet;
149
148
  };
150
149
  pendingImageElementId: string | null;
151
- showHyperlinkPopup: false | "editor" | "info";
150
+ showHyperlinkPopup: false | "info" | "editor";
152
151
  selectedLinearElement: import("./linearElementEditor").LinearElementEditor | null;
153
152
  snapLines: readonly import("../snapping").SnapLine[];
154
153
  originSnapOffset: {
@@ -164,5 +163,5 @@ export declare const actionSetEmbeddableAsActiveTool: {
164
163
  } & {
165
164
  keyTest?: undefined;
166
165
  };
167
- export declare const extractSrc: (htmlString: string) => string;
166
+ export declare const maybeParseEmbedSrc: (str: string) => string;
168
167
  export declare const embeddableURLValidator: (url: string | null | undefined, validateEmbeddable: ExcalidrawProps["validateEmbeddable"]) => boolean;