@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,4 +1,4 @@
1
- /// <reference types="react" />
1
+ import React from "react";
2
2
  import "./Button.scss";
3
3
  interface ButtonProps extends React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement> {
4
4
  type?: "button" | "submit" | "reset";
@@ -6,12 +6,12 @@ export type ButtonSize = "medium" | "large";
6
6
  export type FilledButtonProps = {
7
7
  label: string;
8
8
  children?: React.ReactNode;
9
- onClick?: () => void;
9
+ onClick?: (event: React.MouseEvent) => void;
10
10
  variant?: ButtonVariant;
11
11
  color?: ButtonColor;
12
12
  size?: ButtonSize;
13
13
  className?: string;
14
14
  fullWidth?: boolean;
15
- startIcon?: React.ReactNode;
15
+ icon?: React.ReactNode;
16
16
  };
17
17
  export declare const FilledButton: React.ForwardRefExoticComponent<FilledButtonProps & React.RefAttributes<HTMLButtonElement>>;
@@ -1,7 +1,31 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { forwardRef } from "react";
2
+ import { forwardRef, useState } from "react";
3
3
  import clsx from "clsx";
4
4
  import "./FilledButton.scss";
5
- export const FilledButton = forwardRef(({ children, startIcon, onClick, label, variant = "filled", color = "primary", size = "medium", fullWidth, className, }, ref) => {
6
- return (_jsxs("button", { className: clsx("ExcButton", `ExcButton--color-${color}`, `ExcButton--variant-${variant}`, `ExcButton--size-${size}`, { "ExcButton--fullWidth": fullWidth }, className), onClick: onClick, type: "button", "aria-label": label, ref: ref, children: [startIcon && (_jsx("div", { className: "ExcButton__icon", "aria-hidden": true, children: startIcon })), variant !== "icon" && (children ?? label)] }));
5
+ import { AbortError } from "../errors";
6
+ import Spinner from "./Spinner";
7
+ import { isPromiseLike } from "../utils";
8
+ export const FilledButton = forwardRef(({ children, icon, onClick, label, variant = "filled", color = "primary", size = "medium", fullWidth, className, }, ref) => {
9
+ const [isLoading, setIsLoading] = useState(false);
10
+ const _onClick = async (event) => {
11
+ const ret = onClick?.(event);
12
+ if (isPromiseLike(ret)) {
13
+ try {
14
+ setIsLoading(true);
15
+ await ret;
16
+ }
17
+ catch (error) {
18
+ if (!(error instanceof AbortError)) {
19
+ throw error;
20
+ }
21
+ else {
22
+ console.warn(error);
23
+ }
24
+ }
25
+ finally {
26
+ setIsLoading(false);
27
+ }
28
+ }
29
+ };
30
+ return (_jsx("button", { className: clsx("ExcButton", `ExcButton--color-${color}`, `ExcButton--variant-${variant}`, `ExcButton--size-${size}`, { "ExcButton--fullWidth": fullWidth }, className), onClick: _onClick, type: "button", "aria-label": label, ref: ref, disabled: isLoading, children: _jsxs("div", { className: "ExcButton__contents", children: [isLoading && _jsx(Spinner, {}), icon && (_jsx("div", { className: "ExcButton__icon", "aria-hidden": true, children: icon })), variant !== "icon" && (children ?? label)] }) }));
7
31
  });
@@ -2,6 +2,6 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { CloseIcon } from "../icons";
3
3
  import "./FollowMode.scss";
4
4
  const FollowMode = ({ height, width, userToFollow, onDisconnect, }) => {
5
- return (_jsx("div", { style: { position: "relative" }, children: _jsx("div", { className: "follow-mode", style: { width, height }, children: _jsxs("div", { className: "follow-mode__badge", children: [_jsxs("div", { className: "follow-mode__badge__label", children: ["Following", " ", _jsx("span", { className: "follow-mode__badge__username", title: userToFollow.username, children: userToFollow.username })] }), _jsx("button", { onClick: onDisconnect, className: "follow-mode__disconnect-btn", children: CloseIcon })] }) }) }));
5
+ return (_jsx("div", { className: "follow-mode", style: { width, height }, children: _jsxs("div", { className: "follow-mode__badge", children: [_jsxs("div", { className: "follow-mode__badge__label", children: ["Following", " ", _jsx("span", { className: "follow-mode__badge__username", title: userToFollow.username, children: userToFollow.username })] }), _jsx("button", { onClick: onDisconnect, className: "follow-mode__disconnect-btn", children: CloseIcon })] }) }));
6
6
  };
7
7
  export default FollowMode;
@@ -4,11 +4,12 @@ import type { AppClassProperties, BinaryFiles, UIAppState } from "../types";
4
4
  import { NonDeletedExcalidrawElement } from "../element/types";
5
5
  import "./ImageExportDialog.scss";
6
6
  export declare const ErrorCanvasPreview: () => JSX.Element;
7
- export declare const ImageExportDialog: ({ elements, appState, files, actionManager, onExportImage, onCloseRequest, }: {
7
+ export declare const ImageExportDialog: ({ elements, appState, files, actionManager, onExportImage, onCloseRequest, name, }: {
8
8
  appState: UIAppState;
9
9
  elements: readonly NonDeletedExcalidrawElement[];
10
10
  files: BinaryFiles;
11
11
  actionManager: ActionManager;
12
12
  onExportImage: AppClassProperties["onExportImage"];
13
13
  onCloseRequest: () => void;
14
+ name: string;
14
15
  }) => JSX.Element;
@@ -14,7 +14,6 @@ import { RadioGroup } from "./RadioGroup";
14
14
  import { Switch } from "./Switch";
15
15
  import { Tooltip } from "./Tooltip";
16
16
  import "./ImageExportDialog.scss";
17
- import { useAppProps } from "./App";
18
17
  import { FilledButton } from "./FilledButton";
19
18
  import { cloneJSON } from "../utils";
20
19
  import { prepareElementsForExport } from "../data";
@@ -22,10 +21,9 @@ const supportsContextFilters = "filter" in document.createElement("canvas").getC
22
21
  export const ErrorCanvasPreview = () => {
23
22
  return (_jsxs("div", { children: [_jsx("h3", { children: t("canvasError.cannotShowPreview") }), _jsx("p", { children: _jsx("span", { children: t("canvasError.canvasTooBig") }) }), _jsxs("em", { children: ["(", t("canvasError.canvasTooBigTip"), ")"] })] }));
24
23
  };
25
- const ImageExportModal = ({ appStateSnapshot, elementsSnapshot, files, actionManager, onExportImage, }) => {
24
+ const ImageExportModal = ({ appStateSnapshot, elementsSnapshot, files, actionManager, onExportImage, name, }) => {
26
25
  const hasSelection = isSomeElementSelected(elementsSnapshot, appStateSnapshot);
27
- const appProps = useAppProps();
28
- const [projectName, setProjectName] = useState(appStateSnapshot.name);
26
+ const [projectName, setProjectName] = useState(name);
29
27
  const [exportSelectionOnly, setExportSelectionOnly] = useState(hasSelection);
30
28
  const [exportWithBackground, setExportWithBackground] = useState(appStateSnapshot.exportBackground);
31
29
  const [exportDarkMode, setExportDarkMode] = useState(appStateSnapshot.exportWithDarkMode);
@@ -63,8 +61,15 @@ const ImageExportModal = ({ appStateSnapshot, elementsSnapshot, files, actionMan
63
61
  setRenderError(null);
64
62
  // if converting to blob fails, there's some problem that will
65
63
  // likely prevent preview and export (e.g. canvas too big)
66
- return canvasToBlob(canvas).then(() => {
64
+ return canvasToBlob(canvas)
65
+ .then(() => {
67
66
  previewNode.replaceChildren(canvas);
67
+ })
68
+ .catch((e) => {
69
+ if (e.name === "CANVAS_POSSIBLY_TOO_BIG") {
70
+ throw new Error(t("canvasError.canvasTooBig"));
71
+ }
72
+ throw e;
68
73
  });
69
74
  })
70
75
  .catch((error) => {
@@ -82,8 +87,7 @@ const ImageExportModal = ({ appStateSnapshot, elementsSnapshot, files, actionMan
82
87
  exportScale,
83
88
  embedScene,
84
89
  ]);
85
- return (_jsxs("div", { className: "ImageExportModal", children: [_jsx("h3", { children: t("imageExportDialog.header") }), _jsxs("div", { className: "ImageExportModal__preview", children: [_jsx("div", { className: "ImageExportModal__preview__canvas", ref: previewRef, children: renderError && _jsx(ErrorCanvasPreview, {}) }), _jsx("div", { className: "ImageExportModal__preview__filename", children: !nativeFileSystemSupported && (_jsx("input", { type: "text", className: "TextInput", value: projectName, style: { width: "30ch" }, disabled: typeof appProps.name !== "undefined" ||
86
- appStateSnapshot.viewModeEnabled, onChange: (event) => {
90
+ return (_jsxs("div", { className: "ImageExportModal", children: [_jsx("h3", { children: t("imageExportDialog.header") }), _jsxs("div", { className: "ImageExportModal__preview", children: [_jsx("div", { className: "ImageExportModal__preview__canvas", ref: previewRef, children: renderError && _jsx(ErrorCanvasPreview, {}) }), _jsx("div", { className: "ImageExportModal__preview__filename", children: !nativeFileSystemSupported && (_jsx("input", { type: "text", className: "TextInput", value: projectName, style: { width: "30ch" }, onChange: (event) => {
87
91
  setProjectName(event.target.value);
88
92
  actionManager.executeAction(actionChangeProjectName, "ui", event.target.value);
89
93
  } })) })] }), _jsxs("div", { className: "ImageExportModal__settings", children: [_jsx("h3", { children: t("imageExportDialog.header") }), hasSelection && (_jsx(ExportSetting, { label: t("imageExportDialog.label.onlySelected"), name: "exportOnlySelected", children: _jsx(Switch, { name: "exportOnlySelected", checked: exportSelectionOnly, onChange: (checked) => {
@@ -105,16 +109,16 @@ const ImageExportModal = ({ appStateSnapshot, elementsSnapshot, files, actionMan
105
109
  label: `${scale}\u00d7`,
106
110
  })) }) }), _jsxs("div", { className: "ImageExportModal__settings__buttons", children: [_jsx(FilledButton, { className: "ImageExportModal__settings__buttons__button", label: t("imageExportDialog.title.exportToPng"), onClick: () => onExportImage(EXPORT_IMAGE_TYPES.png, exportedElements, {
107
111
  exportingFrame,
108
- }), startIcon: downloadIcon, children: t("imageExportDialog.button.exportToPng") }), _jsx(FilledButton, { className: "ImageExportModal__settings__buttons__button", label: t("imageExportDialog.title.exportToSvg"), onClick: () => onExportImage(EXPORT_IMAGE_TYPES.svg, exportedElements, {
112
+ }), icon: downloadIcon, children: t("imageExportDialog.button.exportToPng") }), _jsx(FilledButton, { className: "ImageExportModal__settings__buttons__button", label: t("imageExportDialog.title.exportToSvg"), onClick: () => onExportImage(EXPORT_IMAGE_TYPES.svg, exportedElements, {
109
113
  exportingFrame,
110
- }), startIcon: downloadIcon, children: t("imageExportDialog.button.exportToSvg") }), (probablySupportsClipboardBlob || isFirefox) && (_jsx(FilledButton, { className: "ImageExportModal__settings__buttons__button", label: t("imageExportDialog.title.copyPngToClipboard"), onClick: () => onExportImage(EXPORT_IMAGE_TYPES.clipboard, exportedElements, {
114
+ }), icon: downloadIcon, children: t("imageExportDialog.button.exportToSvg") }), (probablySupportsClipboardBlob || isFirefox) && (_jsx(FilledButton, { className: "ImageExportModal__settings__buttons__button", label: t("imageExportDialog.title.copyPngToClipboard"), onClick: () => onExportImage(EXPORT_IMAGE_TYPES.clipboard, exportedElements, {
111
115
  exportingFrame,
112
- }), startIcon: copyIcon, children: t("imageExportDialog.button.copyPngToClipboard") }))] })] })] }));
116
+ }), icon: copyIcon, children: t("imageExportDialog.button.copyPngToClipboard") }))] })] })] }));
113
117
  };
114
118
  const ExportSetting = ({ label, children, tooltip, name, }) => {
115
119
  return (_jsxs("div", { className: "ImageExportModal__settings__setting", title: label, children: [_jsxs("label", { htmlFor: name, className: "ImageExportModal__settings__setting__label", children: [label, tooltip && (_jsx(Tooltip, { label: tooltip, long: true, children: helpIcon }))] }), _jsx("div", { className: "ImageExportModal__settings__setting__content", children: children })] }));
116
120
  };
117
- export const ImageExportDialog = ({ elements, appState, files, actionManager, onExportImage, onCloseRequest, }) => {
121
+ export const ImageExportDialog = ({ elements, appState, files, actionManager, onExportImage, onCloseRequest, name, }) => {
118
122
  // we need to take a snapshot so that the exported state can't be modified
119
123
  // while the dialog is open
120
124
  const [{ appStateSnapshot, elementsSnapshot }] = useState(() => {
@@ -123,5 +127,5 @@ export const ImageExportDialog = ({ elements, appState, files, actionManager, on
123
127
  elementsSnapshot: cloneJSON(elements),
124
128
  };
125
129
  });
126
- return (_jsx(Dialog, { onCloseRequest: onCloseRequest, size: "wide", title: false, children: _jsx(ImageExportModal, { elementsSnapshot: elementsSnapshot, appStateSnapshot: appStateSnapshot, files: files, actionManager: actionManager, onExportImage: onExportImage }) }));
130
+ return (_jsx(Dialog, { onCloseRequest: onCloseRequest, size: "wide", title: false, children: _jsx(ImageExportModal, { elementsSnapshot: elementsSnapshot, appStateSnapshot: appStateSnapshot, files: files, actionManager: actionManager, onExportImage: onExportImage, name: name }) }));
127
131
  };
@@ -18,7 +18,7 @@ const JSONExportModal = ({ elements, appState, setAppState, files, actionManager
18
18
  } })] })), onExportToBackend && (_jsxs(Card, { color: "pink", children: [_jsx("div", { className: "Card-icon", children: LinkIcon }), _jsx("h2", { children: t("exportDialog.link_title") }), _jsx("div", { className: "Card-details", children: t("exportDialog.link_details") }), _jsx(ToolButton, { className: "Card-button", type: "button", title: t("exportDialog.link_button"), "aria-label": t("exportDialog.link_button"), showAriaLabel: true, onClick: async () => {
19
19
  try {
20
20
  trackEvent("export", "link", `ui (${getFrame()})`);
21
- await onExportToBackend(elements, appState, files, canvas);
21
+ await onExportToBackend(elements, appState, files);
22
22
  onCloseRequest();
23
23
  }
24
24
  catch (error) {
@@ -1,5 +1,5 @@
1
1
  /// <reference types="react" />
2
- import "../ToolIcon.scss";
2
+ import "./ToolIcon.scss";
3
3
  type LaserPointerIconProps = {
4
4
  title?: string;
5
5
  name?: string;
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import "../ToolIcon.scss";
2
+ import "./ToolIcon.scss";
3
3
  import clsx from "clsx";
4
- import { laserPointerToolIcon } from "../icons";
4
+ import { laserPointerToolIcon } from "./icons";
5
5
  const DEFAULT_SIZE = "small";
6
6
  export const LaserPointerButton = (props) => {
7
7
  return (_jsxs("label", { className: clsx("ToolIcon ToolIcon__LaserPointer", `ToolIcon_size_${DEFAULT_SIZE}`, {
@@ -45,7 +45,7 @@ import "./Toolbar.scss";
45
45
  import { mutateElement } from "../element/mutateElement";
46
46
  import { ShapeCache } from "../scene/ShapeCache";
47
47
  import Scene from "../scene/Scene";
48
- import { LaserPointerButton } from "./LaserTool/LaserPointerButton";
48
+ import { LaserPointerButton } from "./LaserPointerButton";
49
49
  import { MagicSettings } from "./MagicSettings";
50
50
  import { TTDDialog } from "./TTDDialog/TTDDialog";
51
51
  const DefaultMainMenu = ({ UIOptions }) => {
@@ -69,7 +69,7 @@ const LayerUI = ({ actionManager, appState, files, setAppState, elements, canvas
69
69
  appState.openDialog?.name !== "imageExport") {
70
70
  return null;
71
71
  }
72
- return (_jsx(ImageExportDialog, { elements: elements, appState: appState, files: files, actionManager: actionManager, onExportImage: onExportImage, onCloseRequest: () => setAppState({ openDialog: null }) }));
72
+ return (_jsx(ImageExportDialog, { elements: elements, appState: appState, files: files, actionManager: actionManager, onExportImage: onExportImage, onCloseRequest: () => setAppState({ openDialog: null }), name: app.getName() }));
73
73
  };
74
74
  const renderCanvasActions = () => (_jsxs("div", { style: { position: "relative" }, children: [_jsx(tunnels.MainMenuTunnel.Out, {}), renderWelcomeScreen && _jsx(tunnels.WelcomeScreenMenuHintTunnel.Out, {})] }));
75
75
  const renderSelectedShapeActions = () => (_jsx(Section, { heading: "selectedShapeActions", className: clsx("selected-shape-actions zen-mode-transition", {
@@ -78,7 +78,7 @@ const LayerUI = ({ actionManager, appState, files, setAppState, elements, canvas
78
78
  // we want to make sure this doesn't overflow so subtracting the
79
79
  // approximate height of hamburgerMenu + footer
80
80
  maxHeight: `${appState.height - 166}px`,
81
- }, children: _jsx(SelectedShapeActions, { appState: appState, elements: elements, renderAction: actionManager.renderAction }) }) }));
81
+ }, children: _jsx(SelectedShapeActions, { appState: appState, elementsMap: app.scene.getNonDeletedElementsMap(), renderAction: actionManager.renderAction }) }) }));
82
82
  const renderFixedSideContainer = () => {
83
83
  const shouldRenderSelectedShapeActions = showSelectedShapeActions(appState, elements);
84
84
  return (_jsx(FixedSideContainer, { side: "top", children: _jsxs("div", { className: "App-menu App-menu_top", children: [_jsxs(Stack.Col, { gap: 6, className: clsx("App-menu_top__left"), children: [renderCanvasActions(), shouldRenderSelectedShapeActions && renderSelectedShapeActions()] }), !appState.viewModeEnabled && (_jsx(Section, { heading: "shapes", className: "shapes-section", children: (heading) => (_jsxs("div", { style: { position: "relative" }, children: [renderWelcomeScreen && (_jsx(tunnels.WelcomeScreenToolbarHintTunnel.Out, {})), _jsx(Stack.Col, { gap: 4, align: "start", children: _jsxs(Stack.Row, { gap: 1, className: clsx("App-toolbar-container", {
@@ -35,7 +35,7 @@ export const MobileMenu = ({ appState, elements, actionManager, setAppState, onL
35
35
  marginRight: SCROLLBAR_WIDTH + SCROLLBAR_MARGIN * 2,
36
36
  }, children: _jsxs(Island, { padding: 0, children: [appState.openMenu === "shape" &&
37
37
  !appState.viewModeEnabled &&
38
- showSelectedShapeActions(appState, elements) ? (_jsx(Section, { className: "App-mobile-menu", heading: "selectedShapeActions", children: _jsx(SelectedShapeActions, { appState: appState, elements: elements, renderAction: actionManager.renderAction }) })) : null, _jsxs("footer", { className: "App-toolbar", children: [renderAppToolbar(), appState.scrolledOutside &&
38
+ showSelectedShapeActions(appState, elements) ? (_jsx(Section, { className: "App-mobile-menu", heading: "selectedShapeActions", children: _jsx(SelectedShapeActions, { appState: appState, elementsMap: app.scene.getNonDeletedElementsMap(), renderAction: actionManager.renderAction }) })) : null, _jsxs("footer", { className: "App-toolbar", children: [renderAppToolbar(), appState.scrolledOutside &&
39
39
  !appState.openMenu &&
40
40
  !appState.openSidebar && (_jsx("button", { className: "scroll-back-to-content", onClick: () => {
41
41
  setAppState((appState) => ({
@@ -5,7 +5,6 @@ type Props = {
5
5
  value: string;
6
6
  onChange: (value: string) => void;
7
7
  label: string;
8
- isNameEditable: boolean;
9
8
  ignoreFocus?: boolean;
10
9
  };
11
10
  export declare const ProjectName: (props: Props) => JSX.Element;
@@ -26,5 +26,5 @@ export const ProjectName = (props) => {
26
26
  event.currentTarget.blur();
27
27
  }
28
28
  };
29
- return (_jsxs("div", { className: "ProjectName", children: [_jsx("label", { className: "ProjectName-label", htmlFor: "filename", children: `${props.label}${props.isNameEditable ? "" : ":"}` }), props.isNameEditable ? (_jsx("input", { type: "text", className: "TextInput", onBlur: handleBlur, onKeyDown: handleKeyDown, id: `${id}-filename`, value: fileName, onChange: (event) => setFileName(event.target.value) })) : (_jsx("span", { className: "TextInput TextInput--readonly", id: `${id}-filename`, children: props.value }))] }));
29
+ return (_jsxs("div", { className: "ProjectName", children: [_jsx("label", { className: "ProjectName-label", htmlFor: "filename", children: `${props.label}:` }), _jsx("input", { type: "text", className: "TextInput", onBlur: handleBlur, onKeyDown: handleKeyDown, id: `${id}-filename`, value: fileName, onChange: (event) => setFileName(event.target.value) })] }));
30
30
  };
@@ -0,0 +1,8 @@
1
+ /// <reference types="react" />
2
+ import { Trail } from "../animated-trail";
3
+ import "./SVGLayer.scss";
4
+ type SVGLayerProps = {
5
+ trails: Trail[];
6
+ };
7
+ export declare const SVGLayer: ({ trails }: SVGLayerProps) => JSX.Element;
8
+ export {};
@@ -0,0 +1,20 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useEffect, useRef } from "react";
3
+ import "./SVGLayer.scss";
4
+ export const SVGLayer = ({ trails }) => {
5
+ const svgRef = useRef(null);
6
+ useEffect(() => {
7
+ if (svgRef.current) {
8
+ for (const trail of trails) {
9
+ trail.start(svgRef.current);
10
+ }
11
+ }
12
+ return () => {
13
+ for (const trail of trails) {
14
+ trail.stop();
15
+ }
16
+ };
17
+ // eslint-disable-next-line react-hooks/exhaustive-deps
18
+ }, trails);
19
+ return (_jsx("div", { className: "SVGLayer", children: _jsx("svg", { ref: svgRef }) }));
20
+ };
@@ -16,18 +16,18 @@ export const ShareableLinkDialog = ({ link, onCloseRequest, setErrorMessage, })
16
16
  const copyRoomLink = async () => {
17
17
  try {
18
18
  await copyTextToSystemClipboard(link);
19
- setJustCopied(true);
20
- if (timerRef.current) {
21
- window.clearTimeout(timerRef.current);
22
- }
23
- timerRef.current = window.setTimeout(() => {
24
- setJustCopied(false);
25
- }, 3000);
26
19
  }
27
- catch (error) {
28
- setErrorMessage(error.message);
20
+ catch (e) {
21
+ setErrorMessage(t("errors.copyToSystemClipboardFailed"));
29
22
  }
23
+ setJustCopied(true);
24
+ if (timerRef.current) {
25
+ window.clearTimeout(timerRef.current);
26
+ }
27
+ timerRef.current = window.setTimeout(() => {
28
+ setJustCopied(false);
29
+ }, 3000);
30
30
  ref.current?.select();
31
31
  };
32
- return (_jsx(Dialog, { onCloseRequest: onCloseRequest, title: false, size: "small", children: _jsxs("div", { className: "ShareableLinkDialog", children: [_jsx("h3", { children: "Shareable link" }), _jsxs("div", { className: "ShareableLinkDialog__linkRow", children: [_jsx(TextField, { ref: ref, label: "Link", readonly: true, fullWidth: true, value: link, selectOnRender: true }), _jsxs(Popover.Root, { open: justCopied, children: [_jsx(Popover.Trigger, { asChild: true, children: _jsx(FilledButton, { size: "large", label: "Copy link", startIcon: copyIcon, onClick: copyRoomLink }) }), _jsxs(Popover.Content, { onOpenAutoFocus: (event) => event.preventDefault(), onCloseAutoFocus: (event) => event.preventDefault(), className: "ShareableLinkDialog__popover", side: "top", align: "end", sideOffset: 5.5, children: [tablerCheckIcon, " copied"] })] })] }), _jsxs("div", { className: "ShareableLinkDialog__description", children: ["\uD83D\uDD12 ", t("alerts.uploadedSecurly")] })] }) }));
32
+ return (_jsx(Dialog, { onCloseRequest: onCloseRequest, title: false, size: "small", children: _jsxs("div", { className: "ShareableLinkDialog", children: [_jsx("h3", { children: "Shareable link" }), _jsxs("div", { className: "ShareableLinkDialog__linkRow", children: [_jsx(TextField, { ref: ref, label: "Link", readonly: true, fullWidth: true, value: link, selectOnRender: true }), _jsxs(Popover.Root, { open: justCopied, children: [_jsx(Popover.Trigger, { asChild: true, children: _jsx(FilledButton, { size: "large", label: "Copy link", icon: copyIcon, onClick: copyRoomLink }) }), _jsxs(Popover.Content, { onOpenAutoFocus: (event) => event.preventDefault(), onCloseAutoFocus: (event) => event.preventDefault(), className: "ShareableLinkDialog__popover", side: "top", align: "end", sideOffset: 5.5, children: [tablerCheckIcon, " copied"] })] })] }), _jsxs("div", { className: "ShareableLinkDialog__description", children: ["\uD83D\uDD12 ", t("alerts.uploadedSecurly")] })] }) }));
33
33
  };
@@ -10,7 +10,7 @@ type StackProps = {
10
10
  ref: React.RefObject<HTMLDivElement>;
11
11
  };
12
12
  declare const _default: {
13
- Row: React.ForwardRefExoticComponent<Pick<StackProps, "children" | "style" | "align" | "gap" | "className" | "justifyContent"> & React.RefAttributes<HTMLDivElement>>;
14
- Col: React.ForwardRefExoticComponent<Pick<StackProps, "children" | "style" | "align" | "gap" | "className" | "justifyContent"> & React.RefAttributes<HTMLDivElement>>;
13
+ Row: React.ForwardRefExoticComponent<Pick<StackProps, "children" | "style" | "gap" | "className" | "align" | "justifyContent"> & React.RefAttributes<HTMLDivElement>>;
14
+ Col: React.ForwardRefExoticComponent<Pick<StackProps, "children" | "style" | "gap" | "className" | "align" | "justifyContent"> & React.RefAttributes<HTMLDivElement>>;
15
15
  };
16
16
  export default _default;
@@ -2,6 +2,7 @@ import { DEFAULT_EXPORT_PADDING, DEFAULT_FONT_SIZE, EDITOR_LS_KEYS, } from "../.
2
2
  import { convertToExcalidrawElements, exportToCanvas } from "../../index";
3
3
  import { canvasToBlob } from "../../data/blob";
4
4
  import { EditorLocalStorage } from "../../data/EditorLocalStorage";
5
+ import { t } from "../../i18n";
5
6
  const resetPreview = ({ canvasRef, setError, }) => {
6
7
  const canvasNode = canvasRef.current;
7
8
  if (!canvasNode) {
@@ -55,7 +56,15 @@ export const convertMermaidToExcalidraw = async ({ canvasRef, mermaidToExcalidra
55
56
  });
56
57
  // if converting to blob fails, there's some problem that will
57
58
  // likely prevent preview and export (e.g. canvas too big)
58
- await canvasToBlob(canvas);
59
+ try {
60
+ await canvasToBlob(canvas);
61
+ }
62
+ catch (e) {
63
+ if (e.name === "CANVAS_POSSIBLY_TOO_BIG") {
64
+ throw new Error(t("canvasError.canvasTooBig"));
65
+ }
66
+ throw e;
67
+ }
59
68
  parent.style.background = "var(--default-bg-color)";
60
69
  canvasNode.replaceChildren(canvas);
61
70
  }
@@ -1,7 +1,6 @@
1
1
  import { KeyboardEvent } from "react";
2
2
  import "./TextField.scss";
3
3
  type TextFieldProps = {
4
- value?: string;
5
4
  onChange?: (value: string) => void;
6
5
  onClick?: () => void;
7
6
  onKeyDown?: (event: KeyboardEvent<HTMLInputElement>) => void;
@@ -11,6 +10,10 @@ type TextFieldProps = {
11
10
  label?: string;
12
11
  placeholder?: string;
13
12
  isRedacted?: boolean;
14
- };
13
+ } & ({
14
+ value: string;
15
+ } | {
16
+ defaultValue: string;
17
+ });
15
18
  export declare const TextField: import("react").ForwardRefExoticComponent<TextFieldProps & import("react").RefAttributes<HTMLInputElement>>;
16
19
  export {};
@@ -4,7 +4,7 @@ import clsx from "clsx";
4
4
  import "./TextField.scss";
5
5
  import { Button } from "./Button";
6
6
  import { eyeIcon, eyeClosedIcon } from "./icons";
7
- export const TextField = forwardRef(({ value, onChange, label, fullWidth, placeholder, readonly, selectOnRender, onKeyDown, isRedacted = false, }, ref) => {
7
+ export const TextField = forwardRef(({ onChange, label, fullWidth, placeholder, readonly, selectOnRender, onKeyDown, isRedacted = false, ...rest }, ref) => {
8
8
  const innerRef = useRef(null);
9
9
  useImperativeHandle(ref, () => innerRef.current);
10
10
  useLayoutEffect(() => {
@@ -20,6 +20,9 @@ export const TextField = forwardRef(({ value, onChange, label, fullWidth, placeh
20
20
  }, children: [_jsx("div", { className: "ExcTextField__label", children: label }), _jsxs("div", { className: clsx("ExcTextField__input", {
21
21
  "ExcTextField__input--readonly": readonly,
22
22
  }), children: [_jsx("input", { className: clsx({
23
- "is-redacted": value && isRedacted && !isTemporarilyUnredacted,
24
- }), readOnly: readonly, value: value, placeholder: placeholder, ref: innerRef, onChange: (event) => onChange?.(event.target.value), onKeyDown: onKeyDown }), isRedacted && (_jsx(Button, { onSelect: () => setIsTemporarilyUnredacted(!isTemporarilyUnredacted), style: { border: 0, userSelect: "none" }, children: isTemporarilyUnredacted ? eyeClosedIcon : eyeIcon }))] })] }));
23
+ "is-redacted": "value" in rest &&
24
+ rest.value &&
25
+ isRedacted &&
26
+ !isTemporarilyUnredacted,
27
+ }), readOnly: readonly, value: "value" in rest ? rest.value : undefined, defaultValue: "defaultValue" in rest ? rest.defaultValue : undefined, placeholder: placeholder, ref: innerRef, onChange: (event) => onChange?.(event.target.value), onKeyDown: onKeyDown }), isRedacted && (_jsx(Button, { onSelect: () => setIsTemporarilyUnredacted(!isTemporarilyUnredacted), style: { border: 0, userSelect: "none" }, children: isTemporarilyUnredacted ? eyeClosedIcon : eyeIcon }))] })] }));
25
28
  });
@@ -1,8 +1,9 @@
1
- /// <reference types="react" />
1
+ import { CSSProperties } from "react";
2
2
  import "./Toast.scss";
3
- export declare const Toast: ({ message, onClose, closable, duration, }: {
3
+ export declare const Toast: ({ message, onClose, closable, duration, style, }: {
4
4
  message: string;
5
5
  onClose: () => void;
6
6
  closable?: boolean | undefined;
7
7
  duration?: number | undefined;
8
+ style?: CSSProperties | undefined;
8
9
  }) => JSX.Element;
@@ -6,7 +6,7 @@ import { ToolButton } from "./ToolButton";
6
6
  const DEFAULT_TOAST_TIMEOUT = 5000;
7
7
  export const Toast = ({ message, onClose, closable = false,
8
8
  // To prevent autoclose, pass duration as Infinity
9
- duration = DEFAULT_TOAST_TIMEOUT, }) => {
9
+ duration = DEFAULT_TOAST_TIMEOUT, style, }) => {
10
10
  const timerRef = useRef(0);
11
11
  const shouldAutoClose = duration !== Infinity;
12
12
  const scheduleTimeout = useCallback(() => {
@@ -26,5 +26,5 @@ duration = DEFAULT_TOAST_TIMEOUT, }) => {
26
26
  ? () => clearTimeout(timerRef?.current)
27
27
  : undefined;
28
28
  const onMouseLeave = shouldAutoClose ? scheduleTimeout : undefined;
29
- return (_jsxs("div", { className: "Toast", onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, children: [_jsx("p", { className: "Toast__message", children: message }), closable && (_jsx(ToolButton, { icon: CloseIcon, "aria-label": "close", type: "icon", onClick: onClose, className: "close" }))] }));
29
+ return (_jsxs("div", { className: "Toast", onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, style: style, children: [_jsx("p", { className: "Toast__message", children: message }), closable && (_jsx(ToolButton, { icon: CloseIcon, "aria-label": "close", type: "icon", onClick: onClose, className: "close" }))] }));
30
30
  };
@@ -5,6 +5,7 @@ import clsx from "clsx";
5
5
  import { useExcalidrawContainer } from "./App";
6
6
  import { AbortError } from "../errors";
7
7
  import Spinner from "./Spinner";
8
+ import { isPromiseLike } from "../utils";
8
9
  export const ToolButton = React.forwardRef((props, ref) => {
9
10
  const { id: excalId } = useExcalidrawContainer();
10
11
  const innerRef = React.useRef(null);
@@ -14,7 +15,7 @@ export const ToolButton = React.forwardRef((props, ref) => {
14
15
  const isMountedRef = useRef(true);
15
16
  const onClick = async (event) => {
16
17
  const ret = "onClick" in props && props.onClick?.(event);
17
- if (ret && "then" in ret) {
18
+ if (isPromiseLike(ret)) {
18
19
  try {
19
20
  setIsLoading(true);
20
21
  await ret;
@@ -1,12 +1,12 @@
1
1
  import React from "react";
2
2
  import type { DOMAttributes } from "react";
3
3
  import type { InteractiveCanvasAppState } from "../../types";
4
- import type { RenderInteractiveSceneCallback } from "../../scene/types";
4
+ import type { RenderableElementsMap, RenderInteractiveSceneCallback } from "../../scene/types";
5
5
  import type { NonDeletedExcalidrawElement } from "../../element/types";
6
6
  type InteractiveCanvasProps = {
7
7
  containerRef: React.RefObject<HTMLDivElement>;
8
8
  canvas: HTMLCanvasElement | null;
9
- elements: readonly NonDeletedExcalidrawElement[];
9
+ elementsMap: RenderableElementsMap;
10
10
  visibleElements: readonly NonDeletedExcalidrawElement[];
11
11
  selectedElements: readonly NonDeletedExcalidrawElement[];
12
12
  versionNonce: number | undefined;
@@ -1,9 +1,10 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import React, { useEffect, useRef } from "react";
3
- import { renderInteractiveScene } from "../../renderer/renderScene";
4
- import { isRenderThrottlingEnabled, isShallowEqual, sceneCoordsToViewportCoords, } from "../../utils";
3
+ import { isShallowEqual, sceneCoordsToViewportCoords } from "../../utils";
5
4
  import { CURSOR_TYPE } from "../../constants";
6
5
  import { t } from "../../i18n";
6
+ import { isRenderThrottlingEnabled } from "../../reactUtils";
7
+ import { renderInteractiveScene } from "../../renderer/interactiveScene";
7
8
  const InteractiveCanvas = (props) => {
8
9
  const isComponentMounted = useRef(false);
9
10
  useEffect(() => {
@@ -45,7 +46,7 @@ const InteractiveCanvas = (props) => {
45
46
  "#6965db";
46
47
  renderInteractiveScene({
47
48
  canvas: props.canvas,
48
- elements: props.elements,
49
+ elementsMap: props.elementsMap,
49
50
  visibleElements: props.visibleElements,
50
51
  selectedElements: props.selectedElements,
51
52
  scale: window.devicePixelRatio,
@@ -103,10 +104,10 @@ const areEqual = (prevProps, nextProps) => {
103
104
  if (prevProps.selectionNonce !== nextProps.selectionNonce ||
104
105
  prevProps.versionNonce !== nextProps.versionNonce ||
105
106
  prevProps.scale !== nextProps.scale ||
106
- // we need to memoize on element arrays because they may have renewed
107
+ // we need to memoize on elementsMap because they may have renewed
107
108
  // even if versionNonce didn't change (e.g. we filter elements out based
108
109
  // on appState)
109
- prevProps.elements !== nextProps.elements ||
110
+ prevProps.elementsMap !== nextProps.elementsMap ||
110
111
  prevProps.visibleElements !== nextProps.visibleElements ||
111
112
  prevProps.selectedElements !== nextProps.selectedElements) {
112
113
  return false;
@@ -1,12 +1,13 @@
1
1
  import React from "react";
2
2
  import { RoughCanvas } from "roughjs/bin/canvas";
3
3
  import type { StaticCanvasAppState } from "../../types";
4
- import type { StaticCanvasRenderConfig } from "../../scene/types";
5
- import type { NonDeletedExcalidrawElement } from "../../element/types";
4
+ import type { RenderableElementsMap, StaticCanvasRenderConfig } from "../../scene/types";
5
+ import type { NonDeletedExcalidrawElement, NonDeletedSceneElementsMap } from "../../element/types";
6
6
  type StaticCanvasProps = {
7
7
  canvas: HTMLCanvasElement;
8
8
  rc: RoughCanvas;
9
- elements: readonly NonDeletedExcalidrawElement[];
9
+ elementsMap: RenderableElementsMap;
10
+ allElementsMap: NonDeletedSceneElementsMap;
10
11
  visibleElements: readonly NonDeletedExcalidrawElement[];
11
12
  versionNonce: number | undefined;
12
13
  selectionNonce: number | undefined;
@@ -1,7 +1,8 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import React, { useEffect, useRef } from "react";
3
- import { renderStaticScene } from "../../renderer/renderScene";
4
- import { isRenderThrottlingEnabled, isShallowEqual } from "../../utils";
3
+ import { renderStaticScene } from "../../renderer/staticScene";
4
+ import { isShallowEqual } from "../../utils";
5
+ import { isRenderThrottlingEnabled } from "../../reactUtils";
5
6
  const StaticCanvas = (props) => {
6
7
  const wrapperRef = useRef(null);
7
8
  const isComponentMounted = useRef(false);
@@ -38,7 +39,8 @@ const StaticCanvas = (props) => {
38
39
  canvas,
39
40
  rc: props.rc,
40
41
  scale: props.scale,
41
- elements: props.elements,
42
+ elementsMap: props.elementsMap,
43
+ allElementsMap: props.allElementsMap,
42
44
  visibleElements: props.visibleElements,
43
45
  appState: props.appState,
44
46
  renderConfig: props.renderConfig,
@@ -70,10 +72,10 @@ const getRelevantAppStateProps = (appState) => ({
70
72
  const areEqual = (prevProps, nextProps) => {
71
73
  if (prevProps.versionNonce !== nextProps.versionNonce ||
72
74
  prevProps.scale !== nextProps.scale ||
73
- // we need to memoize on element arrays because they may have renewed
75
+ // we need to memoize on elementsMap because they may have renewed
74
76
  // even if versionNonce didn't change (e.g. we filter elements out based
75
77
  // on appState)
76
- prevProps.elements !== nextProps.elements ||
78
+ prevProps.elementsMap !== nextProps.elementsMap ||
77
79
  prevProps.visibleElements !== nextProps.visibleElements) {
78
80
  return false;
79
81
  }
@@ -3,15 +3,35 @@ import { Island } from "../Island";
3
3
  import { useDevice } from "../App";
4
4
  import clsx from "clsx";
5
5
  import Stack from "../Stack";
6
- import { useRef } from "react";
6
+ import { useEffect, useRef } from "react";
7
7
  import { DropdownMenuContentPropsContext } from "./common";
8
8
  import { useOutsideClick } from "../../hooks/useOutsideClick";
9
+ import { KEYS } from "../../keys";
10
+ import { EVENT } from "../../constants";
11
+ import { useStable } from "../../hooks/useStable";
9
12
  const MenuContent = ({ children, onClickOutside, className = "", onSelect, style, }) => {
10
13
  const device = useDevice();
11
14
  const menuRef = useRef(null);
15
+ const callbacksRef = useStable({ onClickOutside });
12
16
  useOutsideClick(menuRef, () => {
13
- onClickOutside?.();
17
+ callbacksRef.onClickOutside?.();
14
18
  });
19
+ useEffect(() => {
20
+ const onKeyDown = (event) => {
21
+ if (event.key === KEYS.ESCAPE) {
22
+ event.stopImmediatePropagation();
23
+ callbacksRef.onClickOutside?.();
24
+ }
25
+ };
26
+ document.addEventListener(EVENT.KEYDOWN, onKeyDown, {
27
+ // so that we can stop propagation of the event before it reaches
28
+ // event handlers that were bound before this one
29
+ capture: true,
30
+ });
31
+ return () => {
32
+ document.removeEventListener(EVENT.KEYDOWN, onKeyDown);
33
+ };
34
+ }, [callbacksRef]);
15
35
  const classNames = clsx(`dropdown-menu ${className}`, {
16
36
  "dropdown-menu--mobile": device.editor.isMobile,
17
37
  }).trim();
@@ -3,4 +3,4 @@ export declare const DropdownMenuContentPropsContext: React.Context<{
3
3
  onSelect?: ((event: Event) => void) | undefined;
4
4
  }>;
5
5
  export declare const getDropdownMenuItemClassName: (className?: string, selected?: boolean) => string;
6
- export declare const useHandleDropdownMenuItemClick: (origOnClick: React.MouseEventHandler<HTMLAnchorElement | HTMLButtonElement> | undefined, onSelect: ((event: Event) => void) | undefined) => (event: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement, MouseEvent>) => void;
6
+ export declare const useHandleDropdownMenuItemClick: (origOnClick: React.MouseEventHandler<HTMLAnchorElement | HTMLButtonElement> | undefined, onSelect: ((event: Event) => void) | undefined) => (event: React.MouseEvent<HTMLAnchorElement | HTMLButtonElement, MouseEvent>) => void;