@excalidraw/excalidraw 0.17.1-7441-4e2c539 → 0.17.1-a38e82f

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 (249) hide show
  1. package/CHANGELOG.md +52 -2
  2. package/dist/browser/dev/excalidraw-assets-dev/chunk-5VWQDKDR.js +20279 -0
  3. package/dist/browser/dev/excalidraw-assets-dev/chunk-5VWQDKDR.js.map +7 -0
  4. package/dist/browser/dev/excalidraw-assets-dev/{chunk-2W5GQUR4.js → chunk-IM4WTX2M.js} +12 -6
  5. package/dist/browser/dev/excalidraw-assets-dev/chunk-IM4WTX2M.js.map +7 -0
  6. package/dist/browser/dev/excalidraw-assets-dev/{en-OC6JWP3X.js → en-IOBA4CS2.js} +4 -2
  7. package/dist/browser/dev/excalidraw-assets-dev/image-LK4UNFRZ.css +6 -0
  8. package/dist/browser/dev/excalidraw-assets-dev/image-LK4UNFRZ.css.map +7 -0
  9. package/dist/browser/dev/excalidraw-assets-dev/{image-HYNUJ3XL.js → image-VKDAL6BQ.js} +2 -4
  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 +34707 -26
  15. package/dist/browser/dev/index.js.map +4 -4
  16. package/dist/browser/prod/excalidraw-assets/chunk-LIG3S5TN.js +11 -0
  17. package/dist/browser/prod/excalidraw-assets/chunk-N2C5DK3B.js +55 -0
  18. package/dist/browser/prod/excalidraw-assets/en-WFZVQ7I6.js +1 -0
  19. package/dist/browser/prod/excalidraw-assets/image-4AT7LYMR.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-TDNWCAOT.json} +9 -5
  25. package/dist/dev/index.css +189 -129
  26. package/dist/dev/index.css.map +3 -3
  27. package/dist/dev/index.js +38445 -39402
  28. package/dist/dev/index.js.map +4 -4
  29. package/dist/excalidraw/actions/actionAddToLibrary.d.ts +12 -12
  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 +8 -8
  33. package/dist/excalidraw/actions/actionBoundText.js +8 -8
  34. package/dist/excalidraw/actions/actionCanvas.d.ts +46 -46
  35. package/dist/excalidraw/actions/actionClipboard.d.ts +27 -27
  36. package/dist/excalidraw/actions/actionClipboard.js +9 -2
  37. package/dist/excalidraw/actions/actionDeleteSelected.d.ts +12 -12
  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 +8 -8
  44. package/dist/excalidraw/actions/actionExport.d.ts +35 -35
  45. package/dist/excalidraw/actions/actionExport.js +4 -4
  46. package/dist/excalidraw/actions/actionFinalize.d.ts +7 -7
  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 +13 -13
  51. package/dist/excalidraw/actions/actionFrame.js +1 -1
  52. package/dist/excalidraw/actions/actionGroup.d.ts +8 -8
  53. package/dist/excalidraw/actions/actionGroup.js +3 -2
  54. package/dist/excalidraw/actions/actionLinearEditor.d.ts +4 -4
  55. package/dist/excalidraw/actions/actionLinearEditor.js +1 -1
  56. package/dist/excalidraw/{element/Hyperlink.d.ts → actions/actionLink.d.ts} +28 -50
  57. package/dist/excalidraw/actions/actionLink.js +40 -0
  58. package/dist/excalidraw/actions/actionMenu.d.ts +11 -11
  59. package/dist/excalidraw/actions/actionNavigate.d.ts +8 -8
  60. package/dist/excalidraw/actions/actionNavigate.js +1 -1
  61. package/dist/excalidraw/actions/actionProperties.d.ts +64 -64
  62. package/dist/excalidraw/actions/actionProperties.js +32 -27
  63. package/dist/excalidraw/actions/actionSelectAll.d.ts +4 -4
  64. package/dist/excalidraw/actions/actionSelectAll.js +1 -1
  65. package/dist/excalidraw/actions/actionStyles.d.ts +6 -6
  66. package/dist/excalidraw/actions/actionStyles.js +4 -4
  67. package/dist/excalidraw/actions/actionToggleGridMode.d.ts +4 -4
  68. package/dist/excalidraw/actions/actionToggleObjectsSnapMode.d.ts +4 -4
  69. package/dist/excalidraw/actions/actionToggleStats.d.ts +4 -4
  70. package/dist/excalidraw/actions/actionToggleViewMode.d.ts +4 -4
  71. package/dist/excalidraw/actions/actionToggleZenMode.d.ts +4 -4
  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 +32 -17
  87. package/dist/excalidraw/components/App.js +474 -339
  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 +16 -12
  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/SVGLayer.d.ts +8 -0
  102. package/dist/excalidraw/components/SVGLayer.js +20 -0
  103. package/dist/excalidraw/components/ShareableLinkDialog.js +10 -10
  104. package/dist/excalidraw/components/Stack.d.ts +2 -2
  105. package/dist/excalidraw/components/TTDDialog/common.js +10 -1
  106. package/dist/excalidraw/components/TextField.d.ts +5 -2
  107. package/dist/excalidraw/components/TextField.js +6 -3
  108. package/dist/excalidraw/components/Toast.d.ts +3 -2
  109. package/dist/excalidraw/components/Toast.js +2 -2
  110. package/dist/excalidraw/components/ToolButton.js +2 -1
  111. package/dist/excalidraw/components/canvases/InteractiveCanvas.d.ts +2 -2
  112. package/dist/excalidraw/components/canvases/InteractiveCanvas.js +6 -5
  113. package/dist/excalidraw/components/canvases/StaticCanvas.d.ts +4 -3
  114. package/dist/excalidraw/components/canvases/StaticCanvas.js +7 -5
  115. package/dist/excalidraw/components/dropdownMenu/DropdownMenuContent.js +22 -2
  116. package/dist/excalidraw/components/dropdownMenu/common.d.ts +1 -1
  117. package/dist/excalidraw/components/hyperlink/Hyperlink.d.ts +19 -0
  118. package/dist/excalidraw/{element → components/hyperlink}/Hyperlink.js +40 -115
  119. package/dist/excalidraw/components/hyperlink/helpers.d.ts +7 -0
  120. package/dist/excalidraw/components/hyperlink/helpers.js +49 -0
  121. package/dist/excalidraw/components/icons.d.ts +2 -1
  122. package/dist/excalidraw/components/icons.js +2 -1
  123. package/dist/excalidraw/components/live-collaboration/LiveCollaborationTrigger.js +3 -2
  124. package/dist/excalidraw/components/main-menu/DefaultItems.js +5 -2
  125. package/dist/excalidraw/constants.d.ts +8 -0
  126. package/dist/excalidraw/constants.js +10 -0
  127. package/dist/excalidraw/data/blob.js +13 -14
  128. package/dist/excalidraw/data/filesystem.d.ts +1 -1
  129. package/dist/excalidraw/data/index.d.ts +2 -1
  130. package/dist/excalidraw/data/index.js +20 -16
  131. package/dist/excalidraw/data/json.d.ts +1 -1
  132. package/dist/excalidraw/data/json.js +5 -3
  133. package/dist/excalidraw/data/resave.d.ts +1 -1
  134. package/dist/excalidraw/data/resave.js +2 -2
  135. package/dist/excalidraw/data/restore.js +8 -13
  136. package/dist/excalidraw/data/transform.js +13 -9
  137. package/dist/excalidraw/distribute.d.ts +2 -2
  138. package/dist/excalidraw/distribute.js +2 -2
  139. package/dist/excalidraw/element/ElementCanvasButtons.d.ts +3 -2
  140. package/dist/excalidraw/element/ElementCanvasButtons.js +4 -4
  141. package/dist/excalidraw/element/binding.d.ts +9 -9
  142. package/dist/excalidraw/element/binding.js +61 -59
  143. package/dist/excalidraw/element/bounds.d.ts +5 -5
  144. package/dist/excalidraw/element/bounds.js +29 -32
  145. package/dist/excalidraw/element/collision.d.ts +11 -11
  146. package/dist/excalidraw/element/collision.js +49 -46
  147. package/dist/excalidraw/element/containerCache.d.ts +11 -0
  148. package/dist/excalidraw/element/containerCache.js +14 -0
  149. package/dist/excalidraw/element/dragElements.js +10 -19
  150. package/dist/excalidraw/element/embeddable.d.ts +11 -12
  151. package/dist/excalidraw/element/embeddable.js +17 -27
  152. package/dist/excalidraw/element/image.js +1 -2
  153. package/dist/excalidraw/element/index.d.ts +0 -1
  154. package/dist/excalidraw/element/index.js +0 -1
  155. package/dist/excalidraw/element/linearElementEditor.d.ts +35 -35
  156. package/dist/excalidraw/element/linearElementEditor.js +79 -80
  157. package/dist/excalidraw/element/newElement.d.ts +4 -6
  158. package/dist/excalidraw/element/newElement.js +11 -16
  159. package/dist/excalidraw/element/resizeElements.d.ts +6 -6
  160. package/dist/excalidraw/element/resizeElements.js +40 -46
  161. package/dist/excalidraw/element/resizeTest.d.ts +3 -3
  162. package/dist/excalidraw/element/resizeTest.js +4 -4
  163. package/dist/excalidraw/element/sizeHelpers.d.ts +2 -2
  164. package/dist/excalidraw/element/sizeHelpers.js +2 -2
  165. package/dist/excalidraw/element/textElement.d.ts +18 -20
  166. package/dist/excalidraw/element/textElement.js +80 -111
  167. package/dist/excalidraw/element/textWysiwyg.d.ts +1 -6
  168. package/dist/excalidraw/element/textWysiwyg.js +15 -37
  169. package/dist/excalidraw/element/transformHandles.d.ts +4 -4
  170. package/dist/excalidraw/element/transformHandles.js +6 -6
  171. package/dist/excalidraw/element/typeChecks.js +4 -1
  172. package/dist/excalidraw/element/types.d.ts +24 -11
  173. package/dist/excalidraw/emitter.d.ts +5 -9
  174. package/dist/excalidraw/emitter.js +12 -12
  175. package/dist/excalidraw/frame.d.ts +26 -20
  176. package/dist/excalidraw/frame.js +157 -84
  177. package/dist/excalidraw/groups.d.ts +3 -3
  178. package/dist/excalidraw/groups.js +11 -3
  179. package/dist/excalidraw/history.d.ts +1 -1
  180. package/dist/excalidraw/index.d.ts +7 -3
  181. package/dist/excalidraw/index.js +14 -5
  182. package/dist/excalidraw/laser-trails.d.ts +19 -0
  183. package/dist/excalidraw/laser-trails.js +95 -0
  184. package/dist/excalidraw/locales/en.json +9 -5
  185. package/dist/excalidraw/reactUtils.d.ts +14 -0
  186. package/dist/excalidraw/reactUtils.js +45 -0
  187. package/dist/excalidraw/renderer/helpers.d.ts +13 -0
  188. package/dist/excalidraw/renderer/helpers.js +39 -0
  189. package/dist/excalidraw/renderer/interactiveScene.d.ts +20 -0
  190. package/dist/excalidraw/renderer/{renderScene.js → interactiveScene.js} +199 -474
  191. package/dist/excalidraw/renderer/renderElement.d.ts +6 -6
  192. package/dist/excalidraw/renderer/renderElement.js +54 -366
  193. package/dist/excalidraw/renderer/staticScene.d.ts +11 -0
  194. package/dist/excalidraw/renderer/staticScene.js +205 -0
  195. package/dist/excalidraw/renderer/staticSvgScene.d.ts +5 -0
  196. package/dist/excalidraw/renderer/staticSvgScene.js +385 -0
  197. package/dist/excalidraw/scene/Fonts.js +2 -1
  198. package/dist/excalidraw/scene/Renderer.d.ts +1 -1
  199. package/dist/excalidraw/scene/Renderer.js +32 -20
  200. package/dist/excalidraw/scene/Scene.d.ts +10 -9
  201. package/dist/excalidraw/scene/Scene.js +45 -21
  202. package/dist/excalidraw/scene/Shape.d.ts +3 -1
  203. package/dist/excalidraw/scene/Shape.js +7 -5
  204. package/dist/excalidraw/scene/ShapeCache.d.ts +2 -1
  205. package/dist/excalidraw/scene/ShapeCache.js +1 -0
  206. package/dist/excalidraw/scene/comparisons.js +2 -1
  207. package/dist/excalidraw/scene/export.d.ts +3 -0
  208. package/dist/excalidraw/scene/export.js +20 -40
  209. package/dist/excalidraw/scene/index.d.ts +0 -1
  210. package/dist/excalidraw/scene/index.js +0 -1
  211. package/dist/excalidraw/scene/scrollbars.d.ts +1 -1
  212. package/dist/excalidraw/scene/scrollbars.js +1 -1
  213. package/dist/excalidraw/scene/selection.d.ts +5 -5
  214. package/dist/excalidraw/scene/selection.js +16 -14
  215. package/dist/excalidraw/scene/types.d.ts +11 -5
  216. package/dist/excalidraw/snapping.d.ts +7 -7
  217. package/dist/excalidraw/snapping.js +21 -20
  218. package/dist/excalidraw/types.d.ts +11 -12
  219. package/dist/excalidraw/utility-types.d.ts +5 -0
  220. package/dist/excalidraw/utils.d.ts +25 -16
  221. package/dist/excalidraw/utils.js +52 -45
  222. package/dist/{dev/en-RLIAOBCI.json → prod/en-TDNWCAOT.json} +9 -5
  223. package/dist/prod/index.css +1 -1
  224. package/dist/prod/index.js +45 -45
  225. package/dist/utils/export.d.ts +0 -6
  226. package/dist/utils/export.js +0 -6
  227. package/dist/utils/index.d.ts +3 -0
  228. package/dist/utils/index.js +3 -0
  229. package/dist/utils/withinBounds.js +2 -1
  230. package/package.json +4 -4
  231. package/dist/browser/dev/excalidraw-assets-dev/chunk-2W5GQUR4.js.map +0 -7
  232. package/dist/browser/dev/excalidraw-assets-dev/chunk-SUHLFFEF.js +0 -53449
  233. package/dist/browser/dev/excalidraw-assets-dev/chunk-SUHLFFEF.js.map +0 -7
  234. package/dist/browser/dev/excalidraw-assets-dev/image-NOPDRTTM.css +0 -5797
  235. package/dist/browser/dev/excalidraw-assets-dev/image-NOPDRTTM.css.map +0 -7
  236. package/dist/browser/prod/excalidraw-assets/chunk-HE2P7BQ6.js +0 -257
  237. package/dist/browser/prod/excalidraw-assets/chunk-OWLL6VOG.js +0 -11
  238. package/dist/browser/prod/excalidraw-assets/en-ERQOR3OC.js +0 -1
  239. package/dist/browser/prod/excalidraw-assets/image-DZ6B4AID.js +0 -1
  240. package/dist/browser/prod/excalidraw-assets/image-J2QCCYAR.css +0 -1
  241. package/dist/excalidraw/components/LaserTool/LaserPathManager.d.ts +0 -28
  242. package/dist/excalidraw/components/LaserTool/LaserPathManager.js +0 -225
  243. package/dist/excalidraw/components/LaserTool/LaserTool.d.ts +0 -8
  244. package/dist/excalidraw/components/LaserTool/LaserTool.js +0 -15
  245. package/dist/excalidraw/renderer/renderScene.d.ts +0 -25
  246. package/dist/excalidraw/vite.config.d.mts +0 -2
  247. package/dist/excalidraw/vite.config.mjs +0 -13
  248. /package/dist/browser/dev/excalidraw-assets-dev/{en-OC6JWP3X.js.map → en-IOBA4CS2.js.map} +0 -0
  249. /package/dist/browser/dev/excalidraw-assets-dev/{image-HYNUJ3XL.js.map → image-VKDAL6BQ.js.map} +0 -0
@@ -1,50 +1,61 @@
1
1
  import { isElementInViewport } from "../element/sizeHelpers";
2
2
  import { isImageElement } from "../element/typeChecks";
3
- import { cancelRender } from "../renderer/renderScene";
4
- import { memoize } from "../utils";
3
+ import { renderInteractiveSceneThrottled } from "../renderer/interactiveScene";
4
+ import { renderStaticSceneThrottled } from "../renderer/staticScene";
5
+ import { memoize, toBrandedType } from "../utils";
5
6
  export class Renderer {
6
7
  scene;
7
8
  constructor(scene) {
8
9
  this.scene = scene;
9
10
  }
10
11
  getRenderableElements = (() => {
11
- const getVisibleCanvasElements = ({ elements, zoom, offsetLeft, offsetTop, scrollX, scrollY, height, width, }) => {
12
- return elements.filter((element) => isElementInViewport(element, width, height, {
13
- zoom,
14
- offsetLeft,
15
- offsetTop,
16
- scrollX,
17
- scrollY,
18
- }));
12
+ const getVisibleCanvasElements = ({ elementsMap, zoom, offsetLeft, offsetTop, scrollX, scrollY, height, width, }) => {
13
+ const visibleElements = [];
14
+ for (const element of elementsMap.values()) {
15
+ if (isElementInViewport(element, width, height, {
16
+ zoom,
17
+ offsetLeft,
18
+ offsetTop,
19
+ scrollX,
20
+ scrollY,
21
+ }, elementsMap)) {
22
+ visibleElements.push(element);
23
+ }
24
+ }
25
+ return visibleElements;
19
26
  };
20
- const getCanvasElements = ({ editingElement, elements, pendingImageElementId, }) => {
21
- return elements.filter((element) => {
27
+ const getRenderableElements = ({ elements, editingElement, pendingImageElementId, }) => {
28
+ const elementsMap = toBrandedType(new Map());
29
+ for (const element of elements) {
22
30
  if (isImageElement(element)) {
23
31
  if (
24
32
  // => not placed on canvas yet (but in elements array)
25
33
  pendingImageElementId === element.id) {
26
- return false;
34
+ continue;
27
35
  }
28
36
  }
29
37
  // we don't want to render text element that's being currently edited
30
38
  // (it's rendered on remote only)
31
- return (!editingElement ||
39
+ if (!editingElement ||
32
40
  editingElement.type !== "text" ||
33
- element.id !== editingElement.id);
34
- });
41
+ element.id !== editingElement.id) {
42
+ elementsMap.set(element.id, element);
43
+ }
44
+ }
45
+ return elementsMap;
35
46
  };
36
47
  return memoize(({ zoom, offsetLeft, offsetTop, scrollX, scrollY, height, width, editingElement, pendingImageElementId,
37
48
  // unused but serves we cache on it to invalidate elements if they
38
49
  // get mutated
39
50
  versionNonce: _versionNonce, }) => {
40
51
  const elements = this.scene.getNonDeletedElements();
41
- const canvasElements = getCanvasElements({
52
+ const elementsMap = getRenderableElements({
42
53
  elements,
43
54
  editingElement,
44
55
  pendingImageElementId,
45
56
  });
46
57
  const visibleElements = getVisibleCanvasElements({
47
- elements: canvasElements,
58
+ elementsMap,
48
59
  zoom,
49
60
  offsetLeft,
50
61
  offsetTop,
@@ -53,13 +64,14 @@ export class Renderer {
53
64
  height,
54
65
  width,
55
66
  });
56
- return { canvasElements, visibleElements };
67
+ return { elementsMap, visibleElements };
57
68
  });
58
69
  })();
59
70
  // NOTE Doesn't destroy everything (scene, rc, etc.) because it may not be
60
71
  // safe to break TS contract here (for upstream cases)
61
72
  destroy() {
62
- cancelRender();
73
+ renderInteractiveSceneThrottled.cancel();
74
+ renderStaticSceneThrottled.cancel();
63
75
  this.getRenderableElements.clear();
64
76
  }
65
77
  }
@@ -1,4 +1,4 @@
1
- import { ExcalidrawElement, NonDeletedExcalidrawElement, NonDeleted, ExcalidrawFrameLikeElement } from "../element/types";
1
+ import { ExcalidrawElement, NonDeletedExcalidrawElement, NonDeleted, ExcalidrawFrameLikeElement, ElementsMapOrArray } from "../element/types";
2
2
  import { LinearElementEditor } from "../element/linearElementEditor";
3
3
  import { AppState } from "../types";
4
4
  type ElementIdKey = InstanceType<typeof LinearElementEditor>["elementId"];
@@ -9,21 +9,19 @@ export type ExcalidrawElementsIncludingDeleted = readonly ExcalidrawElement[];
9
9
  declare class Scene {
10
10
  private static sceneMapByElement;
11
11
  private static sceneMapById;
12
- static mapElementToScene(elementKey: ElementKey, scene: Scene,
13
- /**
14
- * needed because of frame exporting hack.
15
- * elementId:Scene mapping will be removed completely, soon.
16
- */
17
- mapElementIds?: boolean): void;
12
+ static mapElementToScene(elementKey: ElementKey, scene: Scene): void;
18
13
  static getScene(elementKey: ElementKey): Scene | null;
19
14
  private callbacks;
20
15
  private nonDeletedElements;
16
+ private nonDeletedElementsMap;
21
17
  private elements;
22
18
  private nonDeletedFramesLikes;
23
19
  private frames;
24
20
  private elementsMap;
25
21
  private selectedElementsCache;
26
22
  private versionNonce;
23
+ getElementsMapIncludingDeleted(): Map<string, ExcalidrawElement> & import("../utility-types").MakeBrand<"SceneElementsMap">;
24
+ getNonDeletedElementsMap(): Map<string, NonDeletedExcalidrawElement> & import("../utility-types").MakeBrand<"NonDeletedSceneElementsMap">;
27
25
  getElementsIncludingDeleted(): readonly ExcalidrawElement[];
28
26
  getNonDeletedElements(): readonly NonDeletedExcalidrawElement[];
29
27
  getFramesIncludingDeleted(): readonly ExcalidrawFrameLikeElement[];
@@ -34,7 +32,7 @@ declare class Scene {
34
32
  * scene state. This in effect will likely result in cache-miss, and
35
33
  * the cache won't be updated in this case.
36
34
  */
37
- elements?: readonly ExcalidrawElement[];
35
+ elements?: ElementsMapOrArray;
38
36
  includeBoundTextElement?: boolean;
39
37
  includeElementsInFrames?: boolean;
40
38
  }): NonDeleted<ExcalidrawElement>[];
@@ -55,7 +53,7 @@ declare class Scene {
55
53
  * @returns whether a change was made
56
54
  */
57
55
  mapElements(iteratee: (element: ExcalidrawElement) => ExcalidrawElement): boolean;
58
- replaceAllElements(nextElements: readonly ExcalidrawElement[], mapElementIds?: boolean): void;
56
+ replaceAllElements(nextElements: ElementsMapOrArray): void;
59
57
  informMutation(): void;
60
58
  addCallback(cb: SceneStateCallback): SceneStateCallbackRemover;
61
59
  destroy(): void;
@@ -63,5 +61,8 @@ declare class Scene {
63
61
  insertElementsAtIndex(elements: ExcalidrawElement[], index: number): void;
64
62
  addNewElement: (element: ExcalidrawElement) => void;
65
63
  getElementIndex(elementId: string): number;
64
+ getContainerElement: (element: (ExcalidrawElement & {
65
+ containerId: ExcalidrawElement["id"] | null;
66
+ }) | null) => ExcalidrawElement | null;
66
67
  }
67
68
  export default Scene;
@@ -1,7 +1,19 @@
1
- import { getNonDeletedElements, isNonDeletedElement } from "../element";
1
+ import { isNonDeletedElement } from "../element";
2
2
  import { isFrameLikeElement } from "../element/typeChecks";
3
3
  import { getSelectedElements } from "./selection";
4
4
  import { randomInteger } from "../random";
5
+ import { toBrandedType } from "../utils";
6
+ const getNonDeletedElements = (allElements) => {
7
+ const elementsMap = new Map();
8
+ const elements = [];
9
+ for (const element of allElements) {
10
+ if (!element.isDeleted) {
11
+ elements.push(element);
12
+ elementsMap.set(element.id, element);
13
+ }
14
+ }
15
+ return { elementsMap, elements };
16
+ };
5
17
  const hashSelectionOpts = (opts) => {
6
18
  const keys = ["includeBoundTextElement", "includeElementsInFrames"];
7
19
  let hash = "";
@@ -22,27 +34,17 @@ class Scene {
22
34
  // ---------------------------------------------------------------------------
23
35
  static sceneMapByElement = new WeakMap();
24
36
  static sceneMapById = new Map();
25
- static mapElementToScene(elementKey, scene,
26
- /**
27
- * needed because of frame exporting hack.
28
- * elementId:Scene mapping will be removed completely, soon.
29
- */
30
- mapElementIds = true) {
37
+ static mapElementToScene(elementKey, scene) {
31
38
  if (isIdKey(elementKey)) {
32
- if (!mapElementIds) {
33
- return;
34
- }
35
39
  // for cases where we don't have access to the element object
36
40
  // (e.g. restore serialized appState with id references)
37
41
  this.sceneMapById.set(elementKey, scene);
38
42
  }
39
43
  else {
40
44
  this.sceneMapByElement.set(elementKey, scene);
41
- if (!mapElementIds) {
42
- // if mapping element objects, also cache the id string when later
43
- // looking up by id alone
44
- this.sceneMapById.set(elementKey.id, scene);
45
- }
45
+ // if mapping element objects, also cache the id string when later
46
+ // looking up by id alone
47
+ this.sceneMapById.set(elementKey.id, scene);
46
48
  }
47
49
  }
48
50
  static getScene(elementKey) {
@@ -56,16 +58,23 @@ class Scene {
56
58
  // ---------------------------------------------------------------------------
57
59
  callbacks = new Set();
58
60
  nonDeletedElements = [];
61
+ nonDeletedElementsMap = toBrandedType(new Map());
59
62
  elements = [];
60
63
  nonDeletedFramesLikes = [];
61
64
  frames = [];
62
- elementsMap = new Map();
65
+ elementsMap = toBrandedType(new Map());
63
66
  selectedElementsCache = {
64
67
  selectedElementIds: null,
65
68
  elements: null,
66
69
  cache: new Map(),
67
70
  };
68
71
  versionNonce;
72
+ getElementsMapIncludingDeleted() {
73
+ return this.elementsMap;
74
+ }
75
+ getNonDeletedElementsMap() {
76
+ return this.nonDeletedElementsMap;
77
+ }
69
78
  getElementsIncludingDeleted() {
70
79
  return this.elements;
71
80
  }
@@ -141,20 +150,26 @@ class Scene {
141
150
  }
142
151
  return didChange;
143
152
  }
144
- replaceAllElements(nextElements, mapElementIds = true) {
145
- this.elements = nextElements;
153
+ replaceAllElements(nextElements) {
154
+ this.elements =
155
+ // ts doesn't like `Array.isArray` of `instanceof Map`
156
+ nextElements instanceof Array
157
+ ? nextElements
158
+ : Array.from(nextElements.values());
146
159
  const nextFrameLikes = [];
147
160
  this.elementsMap.clear();
148
- nextElements.forEach((element) => {
161
+ this.elements.forEach((element) => {
149
162
  if (isFrameLikeElement(element)) {
150
163
  nextFrameLikes.push(element);
151
164
  }
152
165
  this.elementsMap.set(element.id, element);
153
166
  Scene.mapElementToScene(element, this);
154
167
  });
155
- this.nonDeletedElements = getNonDeletedElements(this.elements);
168
+ const nonDeletedElements = getNonDeletedElements(this.elements);
169
+ this.nonDeletedElements = nonDeletedElements.elements;
170
+ this.nonDeletedElementsMap = nonDeletedElements.elementsMap;
156
171
  this.frames = nextFrameLikes;
157
- this.nonDeletedFramesLikes = getNonDeletedElements(this.frames);
172
+ this.nonDeletedFramesLikes = getNonDeletedElements(this.frames).elements;
158
173
  this.informMutation();
159
174
  }
160
175
  informMutation() {
@@ -226,5 +241,14 @@ class Scene {
226
241
  getElementIndex(elementId) {
227
242
  return this.elements.findIndex((element) => element.id === elementId);
228
243
  }
244
+ getContainerElement = (element) => {
245
+ if (!element) {
246
+ return null;
247
+ }
248
+ if (element.containerId) {
249
+ return this.getElement(element.containerId) || null;
250
+ }
251
+ return null;
252
+ };
229
253
  }
230
254
  export default Scene;
@@ -1,6 +1,7 @@
1
1
  import type { Drawable, Options } from "roughjs/bin/core";
2
2
  import type { RoughGenerator } from "roughjs/bin/generator";
3
3
  import type { ExcalidrawElement, NonDeletedExcalidrawElement, ExcalidrawSelectionElement } from "../element/types";
4
+ import { EmbedsValidationStatus } from "../types";
4
5
  export declare const generateRoughOptions: (element: ExcalidrawElement, continuousPath?: boolean) => Options;
5
6
  /**
6
7
  * Generates the roughjs shape for given element.
@@ -9,7 +10,8 @@ export declare const generateRoughOptions: (element: ExcalidrawElement, continuo
9
10
  *
10
11
  * @private
11
12
  */
12
- export declare const _generateElementShape: (element: Exclude<NonDeletedExcalidrawElement, ExcalidrawSelectionElement>, generator: RoughGenerator, { isExporting, canvasBackgroundColor, }: {
13
+ export declare const _generateElementShape: (element: Exclude<NonDeletedExcalidrawElement, ExcalidrawSelectionElement>, generator: RoughGenerator, { isExporting, canvasBackgroundColor, embedsValidationStatus, }: {
13
14
  isExporting: boolean;
14
15
  canvasBackgroundColor: string;
16
+ embedsValidationStatus: EmbedsValidationStatus | null;
15
17
  }) => Drawable | Drawable[] | null;
@@ -84,9 +84,11 @@ export const generateRoughOptions = (element, continuousPath = false) => {
84
84
  }
85
85
  }
86
86
  };
87
- const modifyIframeLikeForRoughOptions = (element, isExporting) => {
87
+ const modifyIframeLikeForRoughOptions = (element, isExporting, embedsValidationStatus) => {
88
88
  if (isIframeLikeElement(element) &&
89
- (isExporting || (isEmbeddableElement(element) && !element.validated)) &&
89
+ (isExporting ||
90
+ (isEmbeddableElement(element) &&
91
+ embedsValidationStatus?.get(element.id) !== true)) &&
90
92
  isTransparent(element.backgroundColor) &&
91
93
  isTransparent(element.strokeColor)) {
92
94
  return {
@@ -204,7 +206,7 @@ const getArrowheadShapes = (element, shape, position, arrowhead, generator, opti
204
206
  *
205
207
  * @private
206
208
  */
207
- export const _generateElementShape = (element, generator, { isExporting, canvasBackgroundColor, }) => {
209
+ export const _generateElementShape = (element, generator, { isExporting, canvasBackgroundColor, embedsValidationStatus, }) => {
208
210
  switch (element.type) {
209
211
  case "rectangle":
210
212
  case "iframe":
@@ -216,10 +218,10 @@ export const _generateElementShape = (element, generator, { isExporting, canvasB
216
218
  const w = element.width;
217
219
  const h = element.height;
218
220
  const r = getCornerRadius(Math.min(w, h), element);
219
- shape = generator.path(`M ${r} 0 L ${w - r} 0 Q ${w} 0, ${w} ${r} L ${w} ${h - r} Q ${w} ${h}, ${w - r} ${h} L ${r} ${h} Q 0 ${h}, 0 ${h - r} L 0 ${r} Q 0 0, ${r} 0`, generateRoughOptions(modifyIframeLikeForRoughOptions(element, isExporting), true));
221
+ shape = generator.path(`M ${r} 0 L ${w - r} 0 Q ${w} 0, ${w} ${r} L ${w} ${h - r} Q ${w} ${h}, ${w - r} ${h} L ${r} ${h} Q 0 ${h}, 0 ${h - r} L 0 ${r} Q 0 0, ${r} 0`, generateRoughOptions(modifyIframeLikeForRoughOptions(element, isExporting, embedsValidationStatus), true));
220
222
  }
221
223
  else {
222
- shape = generator.rectangle(0, 0, element.width, element.height, generateRoughOptions(modifyIframeLikeForRoughOptions(element, isExporting), false));
224
+ shape = generator.rectangle(0, 0, element.width, element.height, generateRoughOptions(modifyIframeLikeForRoughOptions(element, isExporting, embedsValidationStatus), false));
223
225
  }
224
226
  return shape;
225
227
  }
@@ -1,7 +1,7 @@
1
1
  import { Drawable } from "roughjs/bin/core";
2
2
  import { ExcalidrawElement } from "../element/types";
3
3
  import { ElementShape, ElementShapes } from "./types";
4
- import { AppState } from "../types";
4
+ import { AppState, EmbedsValidationStatus } from "../types";
5
5
  export declare class ShapeCache {
6
6
  private static rg;
7
7
  private static cache;
@@ -20,5 +20,6 @@ export declare class ShapeCache {
20
20
  static generateElementShape: <T extends import("../element/types").ExcalidrawRectangleElement | import("../element/types").ExcalidrawDiamondElement | import("../element/types").ExcalidrawEllipseElement | import("../element/types").ExcalidrawTextElement | import("../element/types").ExcalidrawLinearElement | import("../element/types").ExcalidrawFreeDrawElement | import("../element/types").ExcalidrawImageElement | import("../element/types").ExcalidrawFrameElement | import("../element/types").ExcalidrawMagicFrameElement | import("../element/types").ExcalidrawIframeElement | import("../element/types").ExcalidrawEmbeddableElement>(element: T, renderConfig: {
21
21
  isExporting: boolean;
22
22
  canvasBackgroundColor: AppState["viewBackgroundColor"];
23
+ embedsValidationStatus: EmbedsValidationStatus;
23
24
  } | null) => ((T["type"] extends keyof ElementShapes ? ElementShapes[T["type"]] | undefined : ElementShape | undefined) & ({} | null)) | (T["type"] extends keyof ElementShapes ? ElementShapes[T["type"]] : Drawable | null);
24
25
  }
@@ -35,6 +35,7 @@ export class ShapeCache {
35
35
  const shape = _generateElementShape(element, ShapeCache.rg, renderConfig || {
36
36
  isExporting: false,
37
37
  canvasBackgroundColor: COLOR_PALETTE.white,
38
+ embedsValidationStatus: null,
38
39
  });
39
40
  ShapeCache.cache.set(element, shape);
40
41
  return shape;
@@ -27,7 +27,8 @@ export const canChangeRoundness = (type) => type === "rectangle" ||
27
27
  type === "embeddable" ||
28
28
  type === "arrow" ||
29
29
  type === "line" ||
30
- type === "diamond";
30
+ type === "diamond" ||
31
+ type === "image";
31
32
  export const canHaveArrowheads = (type) => type === "arrow";
32
33
  export const getElementAtPosition = (elements, isAtPositionFn) => {
33
34
  let hitElement = null;
@@ -18,6 +18,9 @@ export declare const exportToSvg: (elements: readonly NonDeletedExcalidrawElemen
18
18
  exportEmbedScene?: boolean;
19
19
  frameRendering?: AppState["frameRendering"];
20
20
  }, files: BinaryFiles | null, opts?: {
21
+ /**
22
+ * if true, all embeddables passed in will be rendered when possible.
23
+ */
21
24
  renderEmbeddables?: boolean;
22
25
  exportingFrame?: ExcalidrawFrameLikeElement | null;
23
26
  }) => Promise<SVGSVGElement>;
@@ -1,38 +1,17 @@
1
1
  import rough from "roughjs/bin/rough";
2
2
  import { getCommonBounds, getElementAbsoluteCoords, } from "../element/bounds";
3
- import { renderSceneToSvg, renderStaticScene } from "../renderer/renderScene";
4
- import { cloneJSON, distance, getFontString } from "../utils";
3
+ import { renderSceneToSvg } from "../renderer/staticSvgScene";
4
+ import { arrayToMap, distance, getFontString, toBrandedType } from "../utils";
5
5
  import { DEFAULT_EXPORT_PADDING, FONT_FAMILY, FRAME_STYLE, SVG_NS, THEME_FILTER, } from "../constants";
6
6
  import { getDefaultAppState } from "../appState";
7
7
  import { serializeAsJSON } from "../data/json";
8
8
  import { getInitializedImageElements, updateImageCache, } from "../element/image";
9
- import { elementsOverlappingBBox } from "../../utils/export";
10
- import { getFrameLikeElements, getFrameLikeTitle, getRootElements, } from "../frame";
9
+ import { getElementsOverlappingFrame, getFrameLikeElements, getFrameLikeTitle, getRootElements, } from "../frame";
11
10
  import { newTextElement } from "../element";
12
11
  import { newElementWith } from "../element/mutateElement";
13
- import Scene from "./Scene";
14
12
  import { isFrameElement, isFrameLikeElement } from "../element/typeChecks";
13
+ import { renderStaticScene } from "../renderer/staticScene";
15
14
  const SVG_EXPORT_TAG = `<!-- svg-source:excalidraw -->`;
16
- // getContainerElement and getBoundTextElement and potentially other helpers
17
- // depend on `Scene` which will not be available when these pure utils are
18
- // called outside initialized Excalidraw editor instance or even if called
19
- // from inside Excalidraw if the elements were never cached by Scene (e.g.
20
- // for library elements).
21
- //
22
- // As such, before passing the elements down, we need to initialize a custom
23
- // Scene instance and assign them to it.
24
- //
25
- // FIXME This is a super hacky workaround and we'll need to rewrite this soon.
26
- const __createSceneForElementsHack__ = (elements) => {
27
- const scene = new Scene();
28
- // we can't duplicate elements to regenerate ids because we need the
29
- // orig ids when embedding. So we do another hack of not mapping element
30
- // ids to Scene instances so that we don't override the editor elements
31
- // mapping.
32
- // We still need to clone the objects themselves to regen references.
33
- scene.replaceAllElements(cloneJSON(elements), false);
34
- return scene;
35
- };
36
15
  const truncateText = (element, maxWidth) => {
37
16
  if (element.width <= maxWidth) {
38
17
  return element;
@@ -109,11 +88,7 @@ const getFrameRenderingConfig = (exportingFrame, frameRendering) => {
109
88
  const prepareElementsForRender = ({ elements, exportingFrame, frameRendering, exportWithDarkMode, }) => {
110
89
  let nextElements;
111
90
  if (exportingFrame) {
112
- nextElements = elementsOverlappingBBox({
113
- elements,
114
- bounds: exportingFrame,
115
- type: "overlap",
116
- });
91
+ nextElements = getElementsOverlappingFrame(elements, exportingFrame);
117
92
  }
118
93
  else if (frameRendering.enabled && frameRendering.name) {
119
94
  nextElements = addFrameLabelsAsTextElements(elements, {
@@ -131,8 +106,6 @@ export const exportToCanvas = async (elements, appState, files, { exportBackgrou
131
106
  canvas.height = height * appState.exportScale;
132
107
  return { canvas, scale: appState.exportScale };
133
108
  }) => {
134
- const tempScene = __createSceneForElementsHack__(elements);
135
- elements = tempScene.getNonDeletedElements();
136
109
  const frameRendering = getFrameRenderingConfig(exportingFrame ?? null, appState.frameRendering ?? null);
137
110
  const elementsForRender = prepareElementsForRender({
138
111
  elements,
@@ -154,7 +127,8 @@ export const exportToCanvas = async (elements, appState, files, { exportBackgrou
154
127
  renderStaticScene({
155
128
  canvas,
156
129
  rc: rough.canvas(canvas),
157
- elements: elementsForRender,
130
+ elementsMap: toBrandedType(arrayToMap(elementsForRender)),
131
+ allElementsMap: toBrandedType(arrayToMap(elements)),
158
132
  visibleElements: elementsForRender,
159
133
  scale,
160
134
  appState: {
@@ -172,14 +146,14 @@ export const exportToCanvas = async (elements, appState, files, { exportBackgrou
172
146
  imageCache,
173
147
  renderGrid: false,
174
148
  isExporting: true,
149
+ // empty disables embeddable rendering
150
+ embedsValidationStatus: new Map(),
151
+ elementsPendingErasure: new Set(),
175
152
  },
176
153
  });
177
- tempScene.destroy();
178
154
  return canvas;
179
155
  };
180
156
  export const exportToSvg = async (elements, appState, files, opts) => {
181
- const tempScene = __createSceneForElementsHack__(elements);
182
- elements = tempScene.getNonDeletedElements();
183
157
  const frameRendering = getFrameRenderingConfig(opts?.exportingFrame ?? null, appState.frameRendering ?? null);
184
158
  let { exportPadding = DEFAULT_EXPORT_PADDING, exportWithDarkMode = false, viewBackgroundColor, exportScale = 1, exportEmbedScene, } = appState;
185
159
  const { exportingFrame = null } = opts || {};
@@ -235,8 +209,9 @@ export const exportToSvg = async (elements, appState, files, opts) => {
235
209
  const offsetY = -minY + exportPadding;
236
210
  const frameElements = getFrameLikeElements(elements);
237
211
  let exportingFrameClipPath = "";
212
+ const elementsMap = arrayToMap(elements);
238
213
  for (const frame of frameElements) {
239
- const [x1, y1, x2, y2] = getElementAbsoluteCoords(frame);
214
+ const [x1, y1, x2, y2] = getElementAbsoluteCoords(frame, elementsMap);
240
215
  const cx = (x2 - x1) / 2 - (frame.x - x1);
241
216
  const cy = (y2 - y1) / 2 - (frame.y - y1);
242
217
  exportingFrameClipPath += `<clipPath id=${frame.id}>
@@ -279,16 +254,21 @@ export const exportToSvg = async (elements, appState, files, opts) => {
279
254
  svgRoot.appendChild(rect);
280
255
  }
281
256
  const rsvg = rough.svg(svgRoot);
282
- renderSceneToSvg(elementsForRender, rsvg, svgRoot, files || {}, {
257
+ const renderEmbeddables = opts?.renderEmbeddables ?? false;
258
+ renderSceneToSvg(elementsForRender, toBrandedType(arrayToMap(elementsForRender)), rsvg, svgRoot, files || {}, {
283
259
  offsetX,
284
260
  offsetY,
285
261
  isExporting: true,
286
262
  exportWithDarkMode,
287
- renderEmbeddables: opts?.renderEmbeddables ?? false,
263
+ renderEmbeddables,
288
264
  frameRendering,
289
265
  canvasBackgroundColor: viewBackgroundColor,
266
+ embedsValidationStatus: renderEmbeddables
267
+ ? new Map(elementsForRender
268
+ .filter((element) => isFrameLikeElement(element))
269
+ .map((element) => [element.id, true]))
270
+ : new Map(),
290
271
  });
291
- tempScene.destroy();
292
272
  return svgRoot;
293
273
  };
294
274
  // calculate smallest area to fit the contents in
@@ -1,4 +1,3 @@
1
- export { isOverScrollBars } from "./scrollbars";
2
1
  export { isSomeElementSelected, getElementsWithinSelection, getCommonAttributeOfSelectedElements, getSelectedElements, getTargetElements, } from "./selection";
3
2
  export { calculateScrollCenter } from "./scroll";
4
3
  export { hasBackground, hasStrokeWidth, hasStrokeStyle, canHaveArrowheads, canChangeRoundness, getElementAtPosition, getElementsAtPosition, } from "./comparisons";
@@ -1,4 +1,3 @@
1
- export { isOverScrollBars } from "./scrollbars";
2
1
  export { isSomeElementSelected, getElementsWithinSelection, getCommonAttributeOfSelectedElements, getSelectedElements, getTargetElements, } from "./selection";
3
2
  export { calculateScrollCenter } from "./scroll";
4
3
  export { hasBackground, hasStrokeWidth, hasStrokeStyle, canHaveArrowheads, canChangeRoundness, getElementAtPosition, getElementsAtPosition, } from "./comparisons";
@@ -1,6 +1,6 @@
1
- import { ExcalidrawElement } from "../element/types";
2
1
  import { InteractiveCanvasAppState } from "../types";
3
2
  import { ScrollBars } from "./types";
3
+ import { ExcalidrawElement } from "../element/types";
4
4
  export declare const SCROLLBAR_MARGIN = 4;
5
5
  export declare const SCROLLBAR_WIDTH = 6;
6
6
  export declare const SCROLLBAR_COLOR = "rgba(0,0,0,0.3)";
@@ -5,7 +5,7 @@ export const SCROLLBAR_MARGIN = 4;
5
5
  export const SCROLLBAR_WIDTH = 6;
6
6
  export const SCROLLBAR_COLOR = "rgba(0,0,0,0.3)";
7
7
  export const getScrollBars = (elements, viewportWidth, viewportHeight, appState) => {
8
- if (elements.length === 0) {
8
+ if (!elements.length) {
9
9
  return {
10
10
  horizontal: null,
11
11
  vertical: null,
@@ -1,4 +1,4 @@
1
- import { ExcalidrawElement, NonDeletedExcalidrawElement } from "../element/types";
1
+ import { ElementsMap, ElementsMapOrArray, ExcalidrawElement, NonDeletedExcalidrawElement } from "../element/types";
2
2
  import { AppState, InteractiveCanvasAppState } from "../types";
3
3
  /**
4
4
  * Frames and their containing elements are not to be selected at the same time.
@@ -7,8 +7,8 @@ import { AppState, InteractiveCanvasAppState } from "../types";
7
7
  * @param selectedElements
8
8
  */
9
9
  export declare const excludeElementsInFramesFromSelection: <T extends ExcalidrawElement>(selectedElements: readonly T[]) => T[];
10
- export declare const getElementsWithinSelection: (elements: readonly NonDeletedExcalidrawElement[], selection: NonDeletedExcalidrawElement, excludeElementsInFrames?: boolean) => NonDeletedExcalidrawElement[];
11
- export declare const getVisibleAndNonSelectedElements: (elements: readonly NonDeletedExcalidrawElement[], selectedElements: readonly NonDeletedExcalidrawElement[], appState: AppState) => NonDeletedExcalidrawElement[];
10
+ export declare const getElementsWithinSelection: (elements: readonly NonDeletedExcalidrawElement[], selection: NonDeletedExcalidrawElement, elementsMap: ElementsMap, excludeElementsInFrames?: boolean) => NonDeletedExcalidrawElement[];
11
+ export declare const getVisibleAndNonSelectedElements: (elements: readonly NonDeletedExcalidrawElement[], selectedElements: readonly NonDeletedExcalidrawElement[], appState: AppState, elementsMap: ElementsMap) => NonDeletedExcalidrawElement[];
12
12
  export declare const isSomeElementSelected: {
13
13
  (elements: readonly NonDeletedExcalidrawElement[], appState: Pick<AppState, "selectedElementIds">): boolean;
14
14
  clearCache(): void;
@@ -18,11 +18,11 @@ export declare const isSomeElementSelected: {
18
18
  * elements. If elements don't share the same value, returns `null`.
19
19
  */
20
20
  export declare const getCommonAttributeOfSelectedElements: <T>(elements: readonly NonDeletedExcalidrawElement[], appState: Pick<AppState, "selectedElementIds">, getAttribute: (element: ExcalidrawElement) => T) => T | null;
21
- export declare const getSelectedElements: (elements: readonly NonDeletedExcalidrawElement[], appState: Pick<InteractiveCanvasAppState, "selectedElementIds">, opts?: {
21
+ export declare const getSelectedElements: (elements: ElementsMapOrArray, appState: Pick<InteractiveCanvasAppState, "selectedElementIds">, opts?: {
22
22
  includeBoundTextElement?: boolean;
23
23
  includeElementsInFrames?: boolean;
24
24
  }) => ExcalidrawElement[];
25
- export declare const getTargetElements: (elements: readonly NonDeletedExcalidrawElement[], appState: Pick<AppState, "selectedElementIds" | "editingElement">) => ExcalidrawElement[];
25
+ export declare const getTargetElements: (elements: ElementsMapOrArray, appState: Pick<AppState, "selectedElementIds" | "editingElement">) => ExcalidrawElement[];
26
26
  /**
27
27
  * returns prevState's selectedElementids if no change from previous, so as to
28
28
  * retain reference identity for memoization
@@ -23,13 +23,13 @@ export const excludeElementsInFramesFromSelection = (selectedElements) => {
23
23
  return true;
24
24
  });
25
25
  };
26
- export const getElementsWithinSelection = (elements, selection, excludeElementsInFrames = true) => {
27
- const [selectionX1, selectionY1, selectionX2, selectionY2] = getElementAbsoluteCoords(selection);
26
+ export const getElementsWithinSelection = (elements, selection, elementsMap, excludeElementsInFrames = true) => {
27
+ const [selectionX1, selectionY1, selectionX2, selectionY2] = getElementAbsoluteCoords(selection, elementsMap);
28
28
  let elementsInSelection = elements.filter((element) => {
29
- let [elementX1, elementY1, elementX2, elementY2] = getElementBounds(element);
30
- const containingFrame = getContainingFrame(element);
29
+ let [elementX1, elementY1, elementX2, elementY2] = getElementBounds(element, elementsMap);
30
+ const containingFrame = getContainingFrame(element, elementsMap);
31
31
  if (containingFrame) {
32
- const [fx1, fy1, fx2, fy2] = getElementBounds(containingFrame);
32
+ const [fx1, fy1, fx2, fy2] = getElementBounds(containingFrame, elementsMap);
33
33
  elementX1 = Math.max(fx1, elementX1);
34
34
  elementY1 = Math.max(fy1, elementY1);
35
35
  elementX2 = Math.min(fx2, elementX2);
@@ -47,18 +47,18 @@ export const getElementsWithinSelection = (elements, selection, excludeElementsI
47
47
  ? excludeElementsInFramesFromSelection(elementsInSelection)
48
48
  : elementsInSelection;
49
49
  elementsInSelection = elementsInSelection.filter((element) => {
50
- const containingFrame = getContainingFrame(element);
50
+ const containingFrame = getContainingFrame(element, elementsMap);
51
51
  if (containingFrame) {
52
- return elementOverlapsWithFrame(element, containingFrame);
52
+ return elementOverlapsWithFrame(element, containingFrame, elementsMap);
53
53
  }
54
54
  return true;
55
55
  });
56
56
  return elementsInSelection;
57
57
  };
58
- export const getVisibleAndNonSelectedElements = (elements, selectedElements, appState) => {
58
+ export const getVisibleAndNonSelectedElements = (elements, selectedElements, appState, elementsMap) => {
59
59
  const selectedElementsSet = new Set(selectedElements.map((element) => element.id));
60
60
  return elements.filter((element) => {
61
- const isVisible = isElementInViewport(element, appState.width, appState.height, appState);
61
+ const isVisible = isElementInViewport(element, appState.width, appState.height, appState, elementsMap);
62
62
  return !selectedElementsSet.has(element.id) && isVisible;
63
63
  });
64
64
  };
@@ -94,17 +94,19 @@ export const getCommonAttributeOfSelectedElements = (elements, appState, getAttr
94
94
  return attributes.length === 1 ? attributes[0] : null;
95
95
  };
96
96
  export const getSelectedElements = (elements, appState, opts) => {
97
- const selectedElements = elements.filter((element) => {
97
+ const selectedElements = [];
98
+ for (const element of elements.values()) {
98
99
  if (appState.selectedElementIds[element.id]) {
99
- return element;
100
+ selectedElements.push(element);
101
+ continue;
100
102
  }
101
103
  if (opts?.includeBoundTextElement &&
102
104
  isBoundToContainer(element) &&
103
105
  appState.selectedElementIds[element?.containerId]) {
104
- return element;
106
+ selectedElements.push(element);
107
+ continue;
105
108
  }
106
- return null;
107
- });
109
+ }
108
110
  if (opts?.includeElementsInFrames) {
109
111
  const elementsToInclude = [];
110
112
  selectedElements.forEach((element) => {