@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
@@ -0,0 +1,96 @@
1
+ import { LaserPointer } from "@excalidraw/laser-pointer";
2
+ import { getSvgPathFromStroke, sceneCoordsToViewportCoords } from "./utils";
3
+ import { SVG_NS } from "./constants";
4
+ export class AnimatedTrail {
5
+ animationFrameHandler;
6
+ app;
7
+ options;
8
+ currentTrail;
9
+ pastTrails = [];
10
+ container;
11
+ trailElement;
12
+ constructor(animationFrameHandler, app, options) {
13
+ this.animationFrameHandler = animationFrameHandler;
14
+ this.app = app;
15
+ this.options = options;
16
+ this.animationFrameHandler.register(this, this.onFrame.bind(this));
17
+ this.trailElement = document.createElementNS(SVG_NS, "path");
18
+ }
19
+ get hasCurrentTrail() {
20
+ return !!this.currentTrail;
21
+ }
22
+ hasLastPoint(x, y) {
23
+ if (this.currentTrail) {
24
+ const len = this.currentTrail.originalPoints.length;
25
+ return (this.currentTrail.originalPoints[len - 1][0] === x &&
26
+ this.currentTrail.originalPoints[len - 1][1] === y);
27
+ }
28
+ return false;
29
+ }
30
+ start(container) {
31
+ if (container) {
32
+ this.container = container;
33
+ }
34
+ if (this.trailElement.parentNode !== this.container && this.container) {
35
+ this.container.appendChild(this.trailElement);
36
+ }
37
+ this.animationFrameHandler.start(this);
38
+ }
39
+ stop() {
40
+ this.animationFrameHandler.stop(this);
41
+ if (this.trailElement.parentNode === this.container) {
42
+ this.container?.removeChild(this.trailElement);
43
+ }
44
+ }
45
+ startPath(x, y) {
46
+ this.currentTrail = new LaserPointer(this.options);
47
+ this.currentTrail.addPoint([x, y, performance.now()]);
48
+ this.update();
49
+ }
50
+ addPointToPath(x, y) {
51
+ if (this.currentTrail) {
52
+ this.currentTrail.addPoint([x, y, performance.now()]);
53
+ this.update();
54
+ }
55
+ }
56
+ endPath() {
57
+ if (this.currentTrail) {
58
+ this.currentTrail.close();
59
+ this.currentTrail.options.keepHead = false;
60
+ this.pastTrails.push(this.currentTrail);
61
+ this.currentTrail = undefined;
62
+ this.update();
63
+ }
64
+ }
65
+ update() {
66
+ this.start();
67
+ }
68
+ onFrame() {
69
+ const paths = [];
70
+ for (const trail of this.pastTrails) {
71
+ paths.push(this.drawTrail(trail, this.app.state));
72
+ }
73
+ if (this.currentTrail) {
74
+ const currentPath = this.drawTrail(this.currentTrail, this.app.state);
75
+ paths.push(currentPath);
76
+ }
77
+ this.pastTrails = this.pastTrails.filter((trail) => {
78
+ return trail.getStrokeOutline().length !== 0;
79
+ });
80
+ if (paths.length === 0) {
81
+ this.stop();
82
+ }
83
+ const svgPaths = paths.join(" ").trim();
84
+ this.trailElement.setAttribute("d", svgPaths);
85
+ this.trailElement.setAttribute("fill", (this.options.fill ?? (() => "black"))(this));
86
+ }
87
+ drawTrail(trail, state) {
88
+ const stroke = trail
89
+ .getStrokeOutline(trail.options.size / state.zoom.value)
90
+ .map(([x, y]) => {
91
+ const result = sceneCoordsToViewportCoords({ sceneX: x, sceneY: y }, state);
92
+ return [result.x, result.y];
93
+ });
94
+ return getSvgPathFromStroke(stroke, true);
95
+ }
96
+ }
@@ -0,0 +1,16 @@
1
+ export type AnimationCallback = (timestamp: number) => void | boolean;
2
+ export type AnimationTarget = {
3
+ callback: AnimationCallback;
4
+ stopped: boolean;
5
+ };
6
+ export declare class AnimationFrameHandler {
7
+ private targets;
8
+ private rafIds;
9
+ register(key: object, callback: AnimationCallback): void;
10
+ start(key: object): void;
11
+ stop(key: object): void;
12
+ private constructFrame;
13
+ private scheduleFrame;
14
+ private cancelFrame;
15
+ private onFrame;
16
+ }
@@ -0,0 +1,55 @@
1
+ export class AnimationFrameHandler {
2
+ targets = new WeakMap();
3
+ rafIds = new WeakMap();
4
+ register(key, callback) {
5
+ this.targets.set(key, { callback, stopped: true });
6
+ }
7
+ start(key) {
8
+ const target = this.targets.get(key);
9
+ if (!target) {
10
+ return;
11
+ }
12
+ if (this.rafIds.has(key)) {
13
+ return;
14
+ }
15
+ this.targets.set(key, { ...target, stopped: false });
16
+ this.scheduleFrame(key);
17
+ }
18
+ stop(key) {
19
+ const target = this.targets.get(key);
20
+ if (target && !target.stopped) {
21
+ this.targets.set(key, { ...target, stopped: true });
22
+ }
23
+ this.cancelFrame(key);
24
+ }
25
+ constructFrame(key) {
26
+ return (timestamp) => {
27
+ const target = this.targets.get(key);
28
+ if (!target) {
29
+ return;
30
+ }
31
+ const shouldAbort = this.onFrame(target, timestamp);
32
+ if (!target.stopped && !shouldAbort) {
33
+ this.scheduleFrame(key);
34
+ }
35
+ else {
36
+ this.cancelFrame(key);
37
+ }
38
+ };
39
+ }
40
+ scheduleFrame(key) {
41
+ const rafId = requestAnimationFrame(this.constructFrame(key));
42
+ this.rafIds.set(key, rafId);
43
+ }
44
+ cancelFrame(key) {
45
+ if (this.rafIds.has(key)) {
46
+ const rafId = this.rafIds.get(key);
47
+ cancelAnimationFrame(rafId);
48
+ }
49
+ this.rafIds.delete(key);
50
+ }
51
+ onFrame(target, timestamp) {
52
+ const shouldAbort = target.callback(timestamp);
53
+ return shouldAbort ?? false;
54
+ }
55
+ }
@@ -30,7 +30,7 @@ export declare const clearAppStateForLocalStorage: (appState: Partial<AppState>)
30
30
  scrollY?: number | undefined;
31
31
  cursorButton?: "up" | "down" | undefined;
32
32
  scrolledOutside?: boolean | undefined;
33
- name?: string | undefined;
33
+ name?: string | null | undefined;
34
34
  zoom?: Readonly<{
35
35
  value: NormalizedZoomValue;
36
36
  }> | undefined;
@@ -1,7 +1,5 @@
1
1
  import { COLOR_PALETTE } from "./colors";
2
2
  import { DEFAULT_ELEMENT_PROPS, DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE, DEFAULT_TEXT_ALIGN, EXPORT_SCALES, THEME, } from "./constants";
3
- import { t } from "./i18n";
4
- import { getDateTime } from "./utils";
5
3
  const defaultExportScale = EXPORT_SCALES.includes(devicePixelRatio)
6
4
  ? devicePixelRatio
7
5
  : 1;
@@ -52,7 +50,7 @@ export const getDefaultAppState = () => {
52
50
  isRotating: false,
53
51
  lastPointerDownWith: "mouse",
54
52
  multiElement: null,
55
- name: `${t("labels.untitled")}-${getDateTime()}`,
53
+ name: null,
56
54
  contextMenu: null,
57
55
  openMenu: null,
58
56
  openPopup: null,
@@ -4,8 +4,7 @@ import { isFrameLikeElement, isInitializedImageElement, } from "./element/typeCh
4
4
  import { deepCopyElement } from "./element/newElement";
5
5
  import { mutateElement } from "./element/mutateElement";
6
6
  import { getContainingFrame } from "./frame";
7
- import { isMemberOf, isPromiseLike } from "./utils";
8
- import { t } from "./i18n";
7
+ import { arrayToMap, isMemberOf, isPromiseLike } from "./utils";
9
8
  export const probablySupportsClipboardReadText = "clipboard" in navigator && "readText" in navigator.clipboard;
10
9
  export const probablySupportsClipboardWriteText = "clipboard" in navigator && "writeText" in navigator.clipboard;
11
10
  export const probablySupportsClipboardBlob = "clipboard" in navigator &&
@@ -61,6 +60,7 @@ export const createPasteEvent = ({ types, files, }) => {
61
60
  return event;
62
61
  };
63
62
  export const serializeAsClipboardJSON = ({ elements, files, }) => {
63
+ const elementsMap = arrayToMap(elements);
64
64
  const framesToCopy = new Set(elements.filter((element) => isFrameLikeElement(element)));
65
65
  let foundFile = false;
66
66
  const _files = elements.reduce((acc, element) => {
@@ -79,8 +79,8 @@ export const serializeAsClipboardJSON = ({ elements, files, }) => {
79
79
  const contents = {
80
80
  type: EXPORT_DATA_TYPES.excalidrawClipboard,
81
81
  elements: elements.map((element) => {
82
- if (getContainingFrame(element) &&
83
- !framesToCopy.has(getContainingFrame(element))) {
82
+ if (getContainingFrame(element, elementsMap) &&
83
+ !framesToCopy.has(getContainingFrame(element, elementsMap))) {
84
84
  const copiedElement = deepCopyElement(element);
85
85
  mutateElement(copiedElement, {
86
86
  frameId: null,
@@ -313,7 +313,7 @@ export const copyTextToSystemClipboard = async (text, clipboardEvent) => {
313
313
  }
314
314
  // (3) if that fails, use document.execCommand
315
315
  if (!copyTextViaExecCommand(text)) {
316
- throw new Error(t("errors.copyToSystemClipboardFailed"));
316
+ throw new Error("Error copying to clipboard.");
317
317
  }
318
318
  };
319
319
  // adapted from https://github.com/zenorocha/clipboard.js/blob/ce79f170aa655c408b6aab33c9472e8e4fa52e19/src/clipboard-action.js#L48
@@ -1,11 +1,11 @@
1
1
  /// <reference types="react" />
2
2
  import { ActionManager } from "../actions/manager";
3
- import { ExcalidrawElement } from "../element/types";
3
+ import { NonDeletedElementsMap, NonDeletedSceneElementsMap } from "../element/types";
4
4
  import { AppClassProperties, AppProps, UIAppState, Zoom } from "../types";
5
5
  import "./Actions.scss";
6
- export declare const SelectedShapeActions: ({ appState, elements, renderAction, }: {
6
+ export declare const SelectedShapeActions: ({ appState, elementsMap, renderAction, }: {
7
7
  appState: UIAppState;
8
- elements: readonly ExcalidrawElement[];
8
+ elementsMap: NonDeletedElementsMap | NonDeletedSceneElementsMap;
9
9
  renderAction: ActionManager["renderAction"];
10
10
  }) => JSX.Element;
11
11
  export declare const ShapesSwitcher: ({ activeTool, appState, app, UIOptions, }: {
@@ -1,6 +1,5 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useState } from "react";
3
- import { getNonDeletedElements } from "../element";
4
3
  import { t } from "../i18n";
5
4
  import { useDevice } from "./App";
6
5
  import { canChangeRoundness, canHaveArrowheads, getTargetElements, hasBackground, hasStrokeStyle, hasStrokeWidth, } from "../scene";
@@ -20,8 +19,8 @@ import DropdownMenu from "./dropdownMenu/DropdownMenu";
20
19
  import { EmbedIcon, extraToolsIcon, frameToolIcon, mermaidLogoIcon, laserPointerToolIcon, OpenAIIcon, MagicIcon, } from "./icons";
21
20
  import { KEYS } from "../keys";
22
21
  import { useTunnels } from "../context/tunnels";
23
- export const SelectedShapeActions = ({ appState, elements, renderAction, }) => {
24
- const targetElements = getTargetElements(getNonDeletedElements(elements), appState);
22
+ export const SelectedShapeActions = ({ appState, elementsMap, renderAction, }) => {
23
+ const targetElements = getTargetElements(elementsMap, appState);
25
24
  let isSingleElementBoundContainer = false;
26
25
  if (targetElements.length === 2 &&
27
26
  (hasBoundTextElement(targetElements[0]) ||
@@ -58,8 +57,8 @@ export const SelectedShapeActions = ({ appState, elements, renderAction, }) => {
58
57
  targetElements.some((element) => hasStrokeStyle(element.type))) && (_jsxs(_Fragment, { children: [renderAction("changeStrokeStyle"), renderAction("changeSloppiness")] })), (canChangeRoundness(appState.activeTool.type) ||
59
58
  targetElements.some((element) => canChangeRoundness(element.type))) && (_jsx(_Fragment, { children: renderAction("changeRoundness") })), (appState.activeTool.type === "text" ||
60
59
  targetElements.some(isTextElement)) && (_jsxs(_Fragment, { children: [renderAction("changeFontSize"), renderAction("changeFontFamily"), (appState.activeTool.type === "text" ||
61
- suppportsHorizontalAlign(targetElements)) &&
62
- renderAction("changeTextAlign")] })), shouldAllowVerticalAlign(targetElements) &&
60
+ suppportsHorizontalAlign(targetElements, elementsMap)) &&
61
+ renderAction("changeTextAlign")] })), shouldAllowVerticalAlign(targetElements, elementsMap) &&
63
62
  renderAction("changeVerticalAlign"), (canHaveArrowheads(appState.activeTool.type) ||
64
63
  targetElements.some((element) => canHaveArrowheads(element.type))) && (_jsx(_Fragment, { children: renderAction("changeArrowhead") })), renderAction("changeOpacity"), _jsxs("fieldset", { children: [_jsx("legend", { children: t("labels.layers") }), _jsxs("div", { className: "buttonList", children: [renderAction("sendToBack"), renderAction("sendBackward"), renderAction("bringToFront"), renderAction("bringForward")] })] }), targetElements.length > 1 && !isSingleElementBoundContainer && (_jsxs("fieldset", { children: [_jsx("legend", { children: t("labels.align") }), _jsxs("div", { className: "buttonList", children: [isRTL ? (_jsxs(_Fragment, { children: [renderAction("alignRight"), renderAction("alignHorizontallyCentered"), renderAction("alignLeft")] })) : (_jsxs(_Fragment, { children: [renderAction("alignLeft"), renderAction("alignHorizontallyCentered"), renderAction("alignRight")] })), targetElements.length > 2 &&
65
64
  renderAction("distributeHorizontally"), _jsx("div", { style: { flexBasis: "100%", height: 0 } }), _jsxs("div", { style: {
@@ -103,14 +102,26 @@ export const ShapesSwitcher = ({ activeTool, appState, app, UIOptions, }) => {
103
102
  app.setActiveTool({ type: value });
104
103
  }
105
104
  } }, value));
106
- }), _jsx("div", { className: "App-toolbar__divider" }), _jsxs(DropdownMenu, { open: isExtraToolsMenuOpen, children: [_jsx(DropdownMenu.Trigger, { className: clsx("App-toolbar__extra-tools-trigger", {
105
+ }), _jsx("div", { className: "App-toolbar__divider" }), _jsxs(DropdownMenu, { open: isExtraToolsMenuOpen, children: [_jsxs(DropdownMenu.Trigger, { className: clsx("App-toolbar__extra-tools-trigger", {
107
106
  "App-toolbar__extra-tools-trigger--selected": frameToolSelected ||
108
107
  embeddableToolSelected ||
109
108
  // in collab we're already highlighting the laser button
110
109
  // outside toolbar, so let's not highlight extra-tools button
111
110
  // on top of it
112
111
  (laserToolSelected && !app.props.isCollaborating),
113
- }), onToggle: () => setIsExtraToolsMenuOpen(!isExtraToolsMenuOpen), title: t("toolBar.extraTools"), children: extraToolsIcon }), _jsxs(DropdownMenu.Content, { onClickOutside: () => setIsExtraToolsMenuOpen(false), onSelect: () => setIsExtraToolsMenuOpen(false), className: "App-toolbar__extra-tools-dropdown", children: [_jsx(DropdownMenu.Item, { onSelect: () => app.setActiveTool({ type: "frame" }), icon: frameToolIcon, shortcut: KEYS.F.toLocaleUpperCase(), "data-testid": "toolbar-frame", selected: frameToolSelected, children: t("toolBar.frame") }), _jsx(DropdownMenu.Item, { onSelect: () => app.setActiveTool({ type: "embeddable" }), icon: EmbedIcon, "data-testid": "toolbar-embeddable", selected: embeddableToolSelected, children: t("toolBar.embeddable") }), _jsx(DropdownMenu.Item, { onSelect: () => app.setActiveTool({ type: "laser" }), icon: laserPointerToolIcon, "data-testid": "toolbar-laser", selected: laserToolSelected, shortcut: KEYS.K.toLocaleUpperCase(), children: t("toolBar.laser") }), _jsx("div", { style: { margin: "6px 0", fontSize: 14, fontWeight: 600 }, children: "Generate" }), app.props.aiEnabled !== false && _jsx(TTDDialogTriggerTunnel.Out, {}), _jsx(DropdownMenu.Item, { onSelect: () => app.setOpenDialog({ name: "ttd", tab: "mermaid" }), icon: mermaidLogoIcon, "data-testid": "toolbar-embeddable", children: t("toolBar.mermaidToExcalidraw") }), app.props.aiEnabled !== false && (_jsxs(_Fragment, { children: [_jsxs(DropdownMenu.Item, { onSelect: () => app.onMagicframeToolSelect(), icon: MagicIcon, "data-testid": "toolbar-magicframe", children: [t("toolBar.magicframe"), _jsx(DropdownMenu.Item.Badge, { children: "AI" })] }), _jsx(DropdownMenu.Item, { onSelect: () => {
112
+ }), onToggle: () => setIsExtraToolsMenuOpen(!isExtraToolsMenuOpen), title: t("toolBar.extraTools"), children: [extraToolsIcon, app.props.aiEnabled !== false && (_jsx("div", { style: {
113
+ display: "inline-flex",
114
+ marginLeft: "auto",
115
+ padding: "2px 4px",
116
+ borderRadius: 6,
117
+ fontSize: 8,
118
+ fontFamily: "Cascadia, monospace",
119
+ position: "absolute",
120
+ background: "pink",
121
+ color: "black",
122
+ bottom: 3,
123
+ right: 4,
124
+ }, children: "AI" }))] }), _jsxs(DropdownMenu.Content, { onClickOutside: () => setIsExtraToolsMenuOpen(false), onSelect: () => setIsExtraToolsMenuOpen(false), className: "App-toolbar__extra-tools-dropdown", children: [_jsx(DropdownMenu.Item, { onSelect: () => app.setActiveTool({ type: "frame" }), icon: frameToolIcon, shortcut: KEYS.F.toLocaleUpperCase(), "data-testid": "toolbar-frame", selected: frameToolSelected, children: t("toolBar.frame") }), _jsx(DropdownMenu.Item, { onSelect: () => app.setActiveTool({ type: "embeddable" }), icon: EmbedIcon, "data-testid": "toolbar-embeddable", selected: embeddableToolSelected, children: t("toolBar.embeddable") }), _jsx(DropdownMenu.Item, { onSelect: () => app.setActiveTool({ type: "laser" }), icon: laserPointerToolIcon, "data-testid": "toolbar-laser", selected: laserToolSelected, shortcut: KEYS.K.toLocaleUpperCase(), children: t("toolBar.laser") }), _jsx("div", { style: { margin: "6px 0", fontSize: 14, fontWeight: 600 }, children: "Generate" }), app.props.aiEnabled !== false && _jsx(TTDDialogTriggerTunnel.Out, {}), _jsx(DropdownMenu.Item, { onSelect: () => app.setOpenDialog({ name: "ttd", tab: "mermaid" }), icon: mermaidLogoIcon, "data-testid": "toolbar-embeddable", children: t("toolBar.mermaidToExcalidraw") }), app.props.aiEnabled !== false && (_jsxs(_Fragment, { children: [_jsxs(DropdownMenu.Item, { onSelect: () => app.onMagicframeToolSelect(), icon: MagicIcon, "data-testid": "toolbar-magicframe", children: [t("toolBar.magicframe"), _jsx(DropdownMenu.Item.Badge, { children: "AI" })] }), _jsx(DropdownMenu.Item, { onSelect: () => {
114
125
  trackEvent("ai", "open-settings", "d2c");
115
126
  app.setOpenDialog({
116
127
  name: "settings",
@@ -4,14 +4,16 @@ import { ActionManager } from "../actions/manager";
4
4
  import { EXPORT_IMAGE_TYPES } from "../constants";
5
5
  import { ExportedElements } from "../data";
6
6
  import { LinearElementEditor } from "../element/linearElementEditor";
7
- import { ExcalidrawElement, NonDeleted, NonDeletedExcalidrawElement, ExcalidrawFrameLikeElement, ExcalidrawIframeElement } from "../element/types";
7
+ import { ExcalidrawElement, NonDeleted, NonDeletedExcalidrawElement, ExcalidrawFrameLikeElement, ExcalidrawIframeElement, ExcalidrawEmbeddableElement } from "../element/types";
8
8
  import History from "../history";
9
9
  import Scene from "../scene/Scene";
10
10
  import { AppClassProperties, AppProps, AppState, ExcalidrawImperativeAPI, BinaryFiles, LibraryItems, SceneData, Device, FrameNameBoundsCache, SidebarName, SidebarTabName, ToolType, OnUserFollowedPayload } from "../types";
11
11
  import { FileSystemHandle } from "../data/filesystem";
12
12
  import { Renderer } from "../scene/Renderer";
13
- import { LaserPathManager } from "./LaserTool/LaserPathManager";
14
13
  import { Emitter } from "../emitter";
14
+ import { AnimationFrameHandler } from "../animation-frame-handler";
15
+ import { AnimatedTrail } from "../animated-trail";
16
+ import { LaserTrails } from "../laser-trails";
15
17
  export declare const ExcalidrawContainerContext: React.Context<{
16
18
  container: HTMLDivElement | null;
17
19
  id: string | null;
@@ -58,14 +60,28 @@ declare class App extends React.Component<AppProps, AppState> {
58
60
  files: BinaryFiles;
59
61
  imageCache: AppClassProperties["imageCache"];
60
62
  private iFrameRefs;
63
+ /**
64
+ * Indicates whether the embeddable's url has been validated for rendering.
65
+ * If value not set, indicates that the validation is pending.
66
+ * Initially or on url change the flag is not reset so that we can guarantee
67
+ * the validation came from a trusted source (the editor).
68
+ **/
69
+ private embedsValidationStatus;
70
+ /** embeds that have been inserted to DOM (as a perf optim, we don't want to
71
+ * insert to DOM before user initially scrolls to them) */
72
+ private initializedEmbeds;
73
+ private elementsPendingErasure;
61
74
  hitLinkElement?: NonDeletedExcalidrawElement;
62
75
  lastPointerDownEvent: React.PointerEvent<HTMLElement> | null;
63
76
  lastPointerUpEvent: React.PointerEvent<HTMLElement> | PointerEvent | null;
77
+ lastPointerMoveEvent: PointerEvent | null;
64
78
  lastViewportPosition: {
65
79
  x: number;
66
80
  y: number;
67
81
  };
68
- laserPathManager: LaserPathManager;
82
+ animationFrameHandler: AnimationFrameHandler;
83
+ laserTrails: LaserTrails;
84
+ eraserTrail: AnimatedTrail;
69
85
  onChangeEmitter: Emitter<[elements: readonly ExcalidrawElement[], appState: AppState, files: BinaryFiles]>;
70
86
  onPointerDownEmitter: Emitter<[activeTool: {
71
87
  lastActiveTool: import("../types").ActiveTool | null;
@@ -130,12 +146,6 @@ declare class App extends React.Component<AppProps, AppState> {
130
146
  boxSelection: {
131
147
  hasOccurred: boolean;
132
148
  };
133
- elementIdsToErase: {
134
- [key: string]: {
135
- opacity: number;
136
- erase: boolean;
137
- };
138
- };
139
149
  }>, event: React.PointerEvent<HTMLElement>]>;
140
150
  onPointerUpEmitter: Emitter<[activeTool: {
141
151
  lastActiveTool: import("../types").ActiveTool | null;
@@ -200,28 +210,26 @@ declare class App extends React.Component<AppProps, AppState> {
200
210
  boxSelection: {
201
211
  hasOccurred: boolean;
202
212
  };
203
- elementIdsToErase: {
204
- [key: string]: {
205
- opacity: number;
206
- erase: boolean;
207
- };
208
- };
209
213
  }>, event: PointerEvent]>;
210
214
  onUserFollowEmitter: Emitter<[payload: OnUserFollowedPayload]>;
211
215
  onScrollChangeEmitter: Emitter<[scrollX: number, scrollY: number, zoom: Readonly<{
212
216
  value: import("../types").NormalizedZoomValue;
213
217
  }>]>;
218
+ missingPointerEventCleanupEmitter: Emitter<[event: PointerEvent | null]>;
219
+ onRemoveEventListenersEmitter: Emitter<[]>;
214
220
  constructor(props: AppProps);
215
221
  private onWindowMessage;
216
222
  private cacheEmbeddableRef;
217
223
  private getHTMLIFrameElement;
218
224
  private handleEmbeddableCenterClick;
219
225
  private isIframeLikeElementCenter;
226
+ private updateEmbedValidationStatus;
220
227
  private updateEmbeddables;
221
228
  private renderEmbeddables;
222
229
  private getFrameNameDOMId;
223
230
  frameNameBoundsCache: FrameNameBoundsCache;
224
231
  private renderFrameNames;
232
+ private toggleOverscrollBehavior;
225
233
  render(): JSX.Element;
226
234
  focusContainer: AppClassProperties["focusContainer"];
227
235
  getSceneElementsIncludingDeleted: () => readonly ExcalidrawElement[];
@@ -258,9 +266,9 @@ declare class App extends React.Component<AppProps, AppState> {
258
266
  componentDidMount(): Promise<void>;
259
267
  componentWillUnmount(): void;
260
268
  private onResize;
261
- private removeEventListeners;
262
269
  /** generally invoked only if fullscreen was invoked programmatically */
263
270
  private onFullscreenChange;
271
+ private removeEventListeners;
264
272
  private addEventListeners;
265
273
  componentDidUpdate(prevProps: AppProps, prevState: AppState): void;
266
274
  private renderInteractiveSceneCallback;
@@ -367,6 +375,7 @@ declare class App extends React.Component<AppProps, AppState> {
367
375
  * GestureEvent is standardized.
368
376
  */
369
377
  private isTouchScreenMultiTouchGesture;
378
+ getName: () => string;
370
379
  private onGestureStart;
371
380
  private onGestureChange;
372
381
  private onGestureEnd;
@@ -388,6 +397,11 @@ declare class App extends React.Component<AppProps, AppState> {
388
397
  private handleCanvasPointerUp;
389
398
  private maybeOpenContextMenuAfterPointerDownOnTouchDevices;
390
399
  private resetContextMenuTimer;
400
+ /**
401
+ * pointerup may not fire in certian cases (user tabs away...), so in order
402
+ * to properly cleanup pointerdown state, we need to fire any hanging
403
+ * pointerup handlers manually
404
+ */
391
405
  private maybeCleanupAfterMissingPointerUp;
392
406
  private handleCanvasPanUsingWheelOrSpaceDrag;
393
407
  private updateGestureOnPointerDown;
@@ -412,7 +426,7 @@ declare class App extends React.Component<AppProps, AppState> {
412
426
  sceneX: number;
413
427
  sceneY: number;
414
428
  link: string;
415
- }) => NonDeleted<import("../element/types").ExcalidrawEmbeddableElement> | undefined;
429
+ }) => NonDeleted<ExcalidrawEmbeddableElement> | undefined;
416
430
  private createImageElement;
417
431
  private handleLinearElementOnPointerDown;
418
432
  private getCurrentItemRoundness;
@@ -475,4 +489,5 @@ declare global {
475
489
  };
476
490
  }
477
491
  }
492
+ export declare const createTestHook: () => void;
478
493
  export default App;