@excalidraw/excalidraw 0.18.0-7ea3229 → 0.18.0-816c81c

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 (105) hide show
  1. package/CHANGELOG.md +81 -0
  2. package/README.md +111 -14
  3. package/dist/dev/{chunk-FXVS2QTZ.js → chunk-LWYHXCPK.js} +33 -58
  4. package/dist/dev/chunk-LWYHXCPK.js.map +7 -0
  5. package/dist/dev/{chunk-IFMURN5W.js → chunk-PNUNMPKU.js} +25 -5
  6. package/dist/dev/chunk-PNUNMPKU.js.map +7 -0
  7. package/dist/dev/components/TTDDialog/CodeMirrorEditor-XRUBL3LG.js +259 -0
  8. package/dist/dev/components/TTDDialog/CodeMirrorEditor-XRUBL3LG.js.map +7 -0
  9. package/dist/dev/data/{image-X6URJSP5.js → image-3J4DLBV6.js} +2 -2
  10. package/dist/dev/index.css +255 -75
  11. package/dist/dev/index.css.map +3 -3
  12. package/dist/dev/index.js +5378 -3320
  13. package/dist/dev/index.js.map +4 -4
  14. package/dist/dev/locales/{en-ZZQASRYX.js → en-YPPLK6NW.js} +4 -2
  15. package/dist/prod/chunk-27N2SPOM.js +4 -0
  16. package/dist/prod/chunk-ETSVUAFD.js +12 -0
  17. package/dist/prod/components/TTDDialog/CodeMirrorEditor-UCMRAMCV.js +1 -0
  18. package/dist/prod/data/{image-N3OFZNE6.js → image-32MOCVDX.js} +1 -1
  19. package/dist/prod/index.css +1 -1
  20. package/dist/prod/index.js +37 -30
  21. package/dist/prod/locales/en-CTDJDZ6K.js +1 -0
  22. package/dist/types/common/src/appEventBus.d.ts +27 -0
  23. package/dist/types/common/src/colors.d.ts +1 -1
  24. package/dist/types/common/src/index.d.ts +2 -0
  25. package/dist/types/common/src/utils.d.ts +1 -3
  26. package/dist/types/common/src/versionedSnapshotStore.d.ts +17 -0
  27. package/dist/types/element/src/Scene.d.ts +2 -0
  28. package/dist/types/element/src/arrowheads.d.ts +3 -0
  29. package/dist/types/element/src/binding.d.ts +3 -4
  30. package/dist/types/element/src/bounds.d.ts +1 -1
  31. package/dist/types/element/src/elbowArrow.d.ts +2 -0
  32. package/dist/types/element/src/index.d.ts +1 -0
  33. package/dist/types/element/src/linearElementEditor.d.ts +3 -0
  34. package/dist/types/element/src/mutateElement.d.ts +2 -0
  35. package/dist/types/element/src/types.d.ts +5 -2
  36. package/dist/types/element/src/utils.d.ts +1 -1
  37. package/dist/types/excalidraw/actions/actionAddToLibrary.d.ts +23 -29
  38. package/dist/types/excalidraw/actions/actionBoundText.d.ts +16 -20
  39. package/dist/types/excalidraw/actions/actionCanvas.d.ts +97 -121
  40. package/dist/types/excalidraw/actions/actionClipboard.d.ts +16 -20
  41. package/dist/types/excalidraw/actions/actionCropEditor.d.ts +8 -10
  42. package/dist/types/excalidraw/actions/actionDeleteSelected.d.ts +24 -30
  43. package/dist/types/excalidraw/actions/actionElementLink.d.ts +4 -10
  44. package/dist/types/excalidraw/actions/actionElementLock.d.ts +16 -20
  45. package/dist/types/excalidraw/actions/actionEmbeddable.d.ts +8 -10
  46. package/dist/types/excalidraw/actions/actionExport.d.ts +60 -344
  47. package/dist/types/excalidraw/actions/actionFrame.d.ts +32 -40
  48. package/dist/types/excalidraw/actions/actionGroup.d.ts +16 -20
  49. package/dist/types/excalidraw/actions/actionLinearEditor.d.ts +8 -10
  50. package/dist/types/excalidraw/actions/actionLink.d.ts +8 -10
  51. package/dist/types/excalidraw/actions/actionMenu.d.ts +4 -10
  52. package/dist/types/excalidraw/actions/actionProperties.d.ts +16 -20
  53. package/dist/types/excalidraw/actions/actionSelectAll.d.ts +8 -10
  54. package/dist/types/excalidraw/actions/actionStyles.d.ts +7 -9
  55. package/dist/types/excalidraw/actions/actionToggleArrowBinding.d.ts +172 -0
  56. package/dist/types/excalidraw/actions/actionToggleGridMode.d.ts +8 -10
  57. package/dist/types/excalidraw/actions/actionToggleMidpointSnapping.d.ts +172 -0
  58. package/dist/types/excalidraw/actions/actionToggleObjectsSnapMode.d.ts +8 -10
  59. package/dist/types/excalidraw/actions/actionToggleSearchMenu.d.ts +4 -10
  60. package/dist/types/excalidraw/actions/actionToggleStats.d.ts +8 -10
  61. package/dist/types/excalidraw/actions/actionToggleViewMode.d.ts +8 -10
  62. package/dist/types/excalidraw/actions/actionToggleZenMode.d.ts +8 -10
  63. package/dist/types/excalidraw/actions/index.d.ts +2 -0
  64. package/dist/types/excalidraw/actions/types.d.ts +1 -1
  65. package/dist/types/excalidraw/appState.d.ts +4 -2
  66. package/dist/types/excalidraw/charts/charts.bar.d.ts +2 -0
  67. package/dist/types/excalidraw/charts/charts.constants.d.ts +48 -0
  68. package/dist/types/excalidraw/charts/charts.helpers.d.ts +32 -0
  69. package/dist/types/excalidraw/charts/charts.line.d.ts +2 -0
  70. package/dist/types/excalidraw/charts/charts.parse.d.ts +10 -0
  71. package/dist/types/excalidraw/charts/charts.radar.d.ts +2 -0
  72. package/dist/types/excalidraw/charts/charts.types.d.ts +18 -0
  73. package/dist/types/excalidraw/charts/index.d.ts +7 -0
  74. package/dist/types/excalidraw/clipboard.d.ts +2 -5
  75. package/dist/types/excalidraw/components/App.d.ts +33 -11
  76. package/dist/types/excalidraw/components/AppStateObserver.d.ts +37 -0
  77. package/dist/types/excalidraw/components/IconPicker.d.ts +14 -9
  78. package/dist/types/excalidraw/components/PasteChartDialog.d.ts +4 -5
  79. package/dist/types/excalidraw/components/TTDDialog/CodeMirrorEditor.d.ts +11 -0
  80. package/dist/types/excalidraw/components/TTDDialog/TTDDialogInput.d.ts +3 -3
  81. package/dist/types/excalidraw/components/TTDDialog/TTDDialogOutput.d.ts +4 -1
  82. package/dist/types/excalidraw/components/TTDDialog/mermaid-lang-lite.d.ts +2 -0
  83. package/dist/types/excalidraw/components/TTDDialog/utils/TTDStreamFetch.d.ts +1 -1
  84. package/dist/types/excalidraw/components/TTDDialog/utils/mermaidAutoFix.d.ts +1 -0
  85. package/dist/types/excalidraw/components/TTDDialog/utils/mermaidError.d.ts +10 -0
  86. package/dist/types/excalidraw/components/Toast.d.ts +8 -4
  87. package/dist/types/excalidraw/components/icons.d.ts +17 -8
  88. package/dist/types/excalidraw/components/main-menu/DefaultItems.d.ts +2 -0
  89. package/dist/types/excalidraw/data/blob.d.ts +25 -30
  90. package/dist/types/excalidraw/data/filesystem.d.ts +3 -5
  91. package/dist/types/excalidraw/data/index.d.ts +2 -3
  92. package/dist/types/excalidraw/data/json.d.ts +28 -22
  93. package/dist/types/excalidraw/data/resave.d.ts +7 -2
  94. package/dist/types/excalidraw/hooks/useAppStateValue.d.ts +29 -0
  95. package/dist/types/excalidraw/index.d.ts +23 -3
  96. package/dist/types/excalidraw/types.d.ts +84 -13
  97. package/package.json +12 -7
  98. package/dist/dev/chunk-FXVS2QTZ.js.map +0 -7
  99. package/dist/dev/chunk-IFMURN5W.js.map +0 -7
  100. package/dist/prod/chunk-MSBJ7C4T.js +0 -12
  101. package/dist/prod/chunk-RFLYRLPI.js +0 -4
  102. package/dist/prod/locales/en-RQF5X6GM.js +0 -1
  103. package/dist/types/excalidraw/charts.d.ts +0 -27
  104. /package/dist/dev/data/{image-X6URJSP5.js.map → image-3J4DLBV6.js.map} +0 -0
  105. /package/dist/dev/locales/{en-ZZQASRYX.js.map → en-YPPLK6NW.js.map} +0 -0
package/CHANGELOG.md CHANGED
@@ -11,6 +11,87 @@ The change should be grouped under one of the below section and must contain PR
11
11
  Please add the latest change on the top under the correct section.
12
12
  -->
13
13
 
14
+ ## Unreleased
15
+
16
+ ## Excalidraw API
17
+
18
+ ### Breaking changes
19
+
20
+ - Renamed the `excalidrawAPI` prop to `onExcalidrawAPI`.
21
+ - `onExcalidrawAPI` is now called on mount (instead of during constructor), and later on unmount (with `null` value). The API may be removed altogether in the future (you can use `onMount` & `onUmount` to manage the `ExcalidrawAPI` object (e.g. to cache it to a global state), already).
22
+
23
+ ### Features
24
+
25
+ - Added `ExcalidrawAPI.isDestroyed` flag. Set to `true` once the editor unmounts. Calling any `get*` method, `onStateChange`, or `onEvent` on a destroyed API instance will throw in development and `console.error` in production. The `ExcalidrawAPI` will be reset to `null` on umount, but to be extra safe, you should check `ExcalidrawAPI.isDestroyed` before calling these methods to guard against subtle race conditions in your code.
26
+
27
+ - Added `onMount`, `onInitialize`, and `onUnmount` props. `onMount` receives `{ excalidrawAPI, container }` once the editor root is mounted. `onInitialize` fires once the initial scene has loaded. `onUnmount` fires just before unmounting.
28
+
29
+ - Same events are also accessible imperatively through `api.onEvent(...)`.
30
+
31
+ ```tsx
32
+ <Excalidraw
33
+ onExcalidrawAPI={(api) => {
34
+ api.onEvent("editor:mount", ({ excalidrawAPI, container }) => {
35
+ console.log(container);
36
+ });
37
+
38
+ api.onEvent("editor:initialize").then((readyApi) => {
39
+ readyApi.scrollToContent();
40
+ });
41
+ }}
42
+ />
43
+ ```
44
+
45
+ Note that in future releases, most, if not all, `excalidrawAPI.on*` subscriptions will be removed in favor of `excalidrawAPI.onEvent(name)`.
46
+
47
+ - Also added `"editor:unmount"` lifecycle event, only accessible via `api.onEvent("editor:unmount")`.
48
+
49
+ - Exported `<ExcalidrawAPIProvider/>`, `useExcalidrawAPI()`, `useAppStateValue(prop | props | selectorFunction)`, and `useOnExcalidrawStateChange(prop | props | selectorFunction, callback)` from the package. The imperative API also now exposes `onStateChange(prop | props | selectorFunction, callback?)`, and `onEvent(name, callback)`.
50
+
51
+ ```tsx
52
+ <ExcalidrawAPIProvider>
53
+ <Excalidraw />
54
+ <Logger />
55
+ </ExcalidrawAPIProvider>;
56
+
57
+ function Logger() {
58
+ // initially null before the ExcalidrawAPIProvider initializes ater
59
+ // <Excalidraw/> renders
60
+ // When <Excalidraw/> unmounts, is reset back to null
61
+ const api = useExcalidrawAPI();
62
+
63
+ useAppStateValue("viewModeEnabled", (viewModeEnabled) => {
64
+ console.log("view mode changed:", viewModeEnabled);
65
+ });
66
+
67
+ React.useEffect(() => {
68
+ if (api) {
69
+ console.log("editor instance id:", api.id);
70
+ }
71
+ }, [api]);
72
+
73
+ return null;
74
+ }
75
+ ```
76
+
77
+ - Added `onExport` so host apps can delay JSON export until async work completes. The handler receives the export data plus an `AbortSignal`, and may return a `Promise` or an async generator that yields progress updates for the built-in toast UI.
78
+
79
+ ```tsx
80
+ <Excalidraw
81
+ onExport={async function* (_type, { files }, { signal }) {
82
+ yield { type: "progress", message: "Waiting for images..." };
83
+
84
+ await waitForImagesToLoad(files, signal);
85
+
86
+ if (signal.aborted) {
87
+ return;
88
+ }
89
+
90
+ yield { type: "progress", message: "Export ready", progress: 1 };
91
+ }}
92
+ />
93
+ ```
94
+
14
95
  ## Excalidraw Library
15
96
 
16
97
  ## 0.18.0 (2025-03-11)
package/README.md CHANGED
@@ -1,10 +1,10 @@
1
1
  # Excalidraw
2
2
 
3
- **Excalidraw** is exported as a component to be directly embedded in your project.
3
+ **Excalidraw** is exported as a React component that you can embed directly in your app.
4
4
 
5
5
  ## Installation
6
6
 
7
- Use `npm` or `yarn` to install the package.
7
+ Install the package together with its React peer dependencies.
8
8
 
9
9
  ```bash
10
10
  npm install react react-dom @excalidraw/excalidraw
@@ -12,34 +12,131 @@ npm install react react-dom @excalidraw/excalidraw
12
12
  yarn add react react-dom @excalidraw/excalidraw
13
13
  ```
14
14
 
15
- > **Note**: If you don't want to wait for the next stable release and try out the unreleased changes, use `@excalidraw/excalidraw@next`.
15
+ > **Note**: If you want to try unreleased changes, use `@excalidraw/excalidraw@next`.
16
16
 
17
- #### Self-hosting fonts
17
+ ## Quick start
18
18
 
19
- By default, Excalidraw will try to download all the used fonts from the [CDN](https://esm.run/@excalidraw/excalidraw/dist/prod).
19
+ The minimum working setup has two easy-to-miss requirements:
20
20
 
21
- For self-hosting purposes, you'll have to copy the content of the folder `node_modules/@excalidraw/excalidraw/dist/prod/fonts` to the path where your assets should be served from (i.e. `public/` directory in your project). In that case, you should also set `window.EXCALIDRAW_ASSET_PATH` to the very same path, i.e. `/` in case it's in the root:
21
+ 1. Import the package CSS:
22
22
 
23
- ```js
24
- <script>window.EXCALIDRAW_ASSET_PATH = "/";</script>
23
+ ```ts
24
+ import "@excalidraw/excalidraw/index.css";
25
25
  ```
26
26
 
27
- ### Dimensions of Excalidraw
27
+ 2. Render Excalidraw inside a container with a non-zero height.
28
28
 
29
- Excalidraw takes _100%_ of `width` and `height` of the containing block so make sure the container in which you render Excalidraw has non zero dimensions.
29
+ ```tsx
30
+ import { Excalidraw } from "@excalidraw/excalidraw";
31
+ import "@excalidraw/excalidraw/index.css";
32
+
33
+ export default function App() {
34
+ return (
35
+ <div style={{ height: "100vh" }}>
36
+ <Excalidraw />
37
+ </div>
38
+ );
39
+ }
40
+ ```
41
+
42
+ Excalidraw fills `100%` of the width and height of its parent. If the parent has no height, the canvas will not be visible.
43
+
44
+ ## Next.js / SSR frameworks
45
+
46
+ Excalidraw should be rendered on the client. In SSR frameworks such as Next.js, use a client component and load it dynamically with SSR disabled.
47
+
48
+ ```tsx
49
+ // app/components/ExcalidrawClient.tsx
50
+ "use client";
51
+
52
+ import { Excalidraw } from "@excalidraw/excalidraw";
53
+ import "@excalidraw/excalidraw/index.css";
54
+
55
+ export default function ExcalidrawClient() {
56
+ return (
57
+ <div style={{ height: "100vh" }}>
58
+ <Excalidraw />
59
+ </div>
60
+ );
61
+ }
62
+ ```
63
+
64
+ ```tsx
65
+ // app/page.tsx
66
+ import dynamic from "next/dynamic";
67
+
68
+ const ExcalidrawClient = dynamic(
69
+ () => import("./components/ExcalidrawClient"),
70
+ { ssr: false },
71
+ );
72
+
73
+ export default function Page() {
74
+ return <ExcalidrawClient />;
75
+ }
76
+ ```
77
+
78
+ See the local examples for complete setups:
79
+
80
+ - [examples/with-nextjs](https://github.com/excalidraw/excalidraw/tree/master/examples/with-nextjs)
81
+ - [examples/with-script-in-browser](https://github.com/excalidraw/excalidraw/tree/master/examples/with-script-in-browser)
82
+
83
+ ## LLM / agent tips
84
+
85
+ If an LLM or coding agent is setting up Excalidraw, these shortcuts usually save more time than re-prompting:
86
+
87
+ - Start with a plain `<Excalidraw />` in a `100vh` container. Add refs, `initialData`, persistence, or custom UI only after the base embed works.
88
+ - If the canvas is blank, check the CSS import and parent height first. Those are the two most common integration failures.
89
+ - In Next.js or other SSR frameworks, assume client-only rendering first. Use `"use client"` and `dynamic(..., { ssr: false })` before debugging hydration or `window is not defined` errors.
90
+ - If imports or entrypoints are unclear, inspect `node_modules/@excalidraw/excalidraw/package.json`. The installed package exports are the source of truth.
91
+ - Do not set `window.EXCALIDRAW_ASSET_PATH` unless you are intentionally self-hosting fonts/assets.
92
+ - When docs and generated code drift, copy the nearest working example from this repo, especially `examples/with-nextjs` or `examples/with-script-in-browser`.
93
+
94
+ ## Migrating to `@excalidraw/excalidraw@0.18.x`
95
+
96
+ Version `0.18.x` removes the old `types/`-prefixed deep import paths. If you were importing types from `@excalidraw/excalidraw/types/...`, switch to the new type-only subpaths below.
97
+
98
+ | Old path | New path |
99
+ | --- | --- |
100
+ | `@excalidraw/excalidraw/types/data/transform.js` | `@excalidraw/excalidraw/element/transform` |
101
+ | `@excalidraw/excalidraw/types/data/types.js` | `@excalidraw/excalidraw/data/types` |
102
+ | `@excalidraw/excalidraw/types/element/types.js` | `@excalidraw/excalidraw/element/types` |
103
+ | `@excalidraw/excalidraw/types/utility-types.js` | `@excalidraw/excalidraw/common/utility-types` |
104
+ | `@excalidraw/excalidraw/types/types.js` | `@excalidraw/excalidraw/types` |
105
+
106
+ Drop the `.js` extension. The new package `exports` map resolves these paths without it.
107
+
108
+ These deep subpaths are for `import type` only. Runtime imports should come from the package root, plus `@excalidraw/excalidraw/index.css` for styles.
109
+
110
+ For example:
111
+
112
+ ```ts
113
+ import { exportToSvg } from "@excalidraw/excalidraw";
114
+ ```
115
+
116
+ ## Self-hosting fonts
117
+
118
+ By default, Excalidraw downloads the fonts it needs from the [CDN](https://esm.run/@excalidraw/excalidraw/dist/prod).
119
+
120
+ For self-hosting, copy the contents of `node_modules/@excalidraw/excalidraw/dist/prod/fonts` into the path where your app serves static assets, for example `public/`. Then set `window.EXCALIDRAW_ASSET_PATH` to that same path:
121
+
122
+ ```html
123
+ <script>
124
+ window.EXCALIDRAW_ASSET_PATH = "/";
125
+ </script>
126
+ ```
30
127
 
31
128
  ## Demo
32
129
 
33
- Go to [CodeSandbox](https://codesandbox.io/p/sandbox/github/excalidraw/excalidraw/tree/master/examples/with-script-in-browser) example.
130
+ Try the [CodeSandbox example](https://codesandbox.io/p/sandbox/github/excalidraw/excalidraw/tree/master/examples/with-script-in-browser).
34
131
 
35
132
  ## Integration
36
133
 
37
- Head over to the [docs](https://docs.excalidraw.com/docs/@excalidraw/excalidraw/integration).
134
+ Read the [integration docs](https://docs.excalidraw.com/docs/@excalidraw/excalidraw/integration).
38
135
 
39
136
  ## API
40
137
 
41
- Head over to the [docs](https://docs.excalidraw.com/docs/@excalidraw/excalidraw/api).
138
+ Read the [API docs](https://docs.excalidraw.com/docs/@excalidraw/excalidraw/api).
42
139
 
43
140
  ## Contributing
44
141
 
45
- Head over to the [docs](https://docs.excalidraw.com/docs/@excalidraw/excalidraw/contributing).
142
+ Read the [contributing docs](https://docs.excalidraw.com/docs/@excalidraw/excalidraw/contributing).
@@ -41,7 +41,6 @@ var getDefaultAppState = () => {
41
41
  showWelcomeScreen: false,
42
42
  theme: THEME.LIGHT,
43
43
  collaborators: /* @__PURE__ */ new Map(),
44
- currentChartType: "bar",
45
44
  currentItemBackgroundColor: DEFAULT_ELEMENT_PROPS.backgroundColor,
46
45
  currentItemEndArrowhead: "arrow",
47
46
  currentItemFillStyle: DEFAULT_ELEMENT_PROPS.fillStyle,
@@ -85,6 +84,8 @@ var getDefaultAppState = () => {
85
84
  gridStep: DEFAULT_GRID_STEP,
86
85
  gridModeEnabled: false,
87
86
  isBindingEnabled: true,
87
+ bindingPreference: "enabled",
88
+ isMidpointSnappingEnabled: true,
88
89
  defaultSidebarDockedPreference: false,
89
90
  isLoading: false,
90
91
  isResizing: false,
@@ -97,7 +98,6 @@ var getDefaultAppState = () => {
97
98
  openPopup: null,
98
99
  openSidebar: null,
99
100
  openDialog: null,
100
- pasteDialog: { shown: false, data: null },
101
101
  previousSelectedElementIds: {},
102
102
  resizingElement: null,
103
103
  scrolledOutside: false,
@@ -148,7 +148,6 @@ var APP_STATE_STORAGE_CONF = /* @__PURE__ */ ((config) => config)({
148
148
  showWelcomeScreen: { browser: true, export: false, server: false },
149
149
  theme: { browser: true, export: false, server: false },
150
150
  collaborators: { browser: false, export: false, server: false },
151
- currentChartType: { browser: true, export: false, server: false },
152
151
  currentItemBackgroundColor: { browser: true, export: false, server: false },
153
152
  currentItemEndArrowhead: { browser: true, export: false, server: false },
154
153
  currentItemFillStyle: { browser: true, export: false, server: false },
@@ -191,7 +190,9 @@ var APP_STATE_STORAGE_CONF = /* @__PURE__ */ ((config) => config)({
191
190
  gridStep: { browser: true, export: true, server: true },
192
191
  gridModeEnabled: { browser: true, export: true, server: true },
193
192
  height: { browser: false, export: false, server: false },
194
- isBindingEnabled: { browser: false, export: false, server: false },
193
+ isBindingEnabled: { browser: true, export: false, server: false },
194
+ bindingPreference: { browser: true, export: false, server: false },
195
+ isMidpointSnappingEnabled: { browser: true, export: false, server: false },
195
196
  defaultSidebarDockedPreference: {
196
197
  browser: true,
197
198
  export: false,
@@ -210,7 +211,6 @@ var APP_STATE_STORAGE_CONF = /* @__PURE__ */ ((config) => config)({
210
211
  openPopup: { browser: false, export: false, server: false },
211
212
  openSidebar: { browser: true, export: false, server: false },
212
213
  openDialog: { browser: false, export: false, server: false },
213
- pasteDialog: { browser: false, export: false, server: false },
214
214
  previousSelectedElementIds: { browser: true, export: false, server: false },
215
215
  resizingElement: { browser: false, export: false, server: false },
216
216
  scrolledOutside: { browser: true, export: false, server: false },
@@ -535,7 +535,6 @@ var decode = (data) => {
535
535
 
536
536
  // data/json.ts
537
537
  import {
538
- DEFAULT_FILENAME,
539
538
  EXPORT_DATA_TYPES,
540
539
  getExportSource,
541
540
  MIME_TYPES as MIME_TYPES2,
@@ -548,8 +547,7 @@ import {
548
547
  fileSave as _fileSave,
549
548
  supported as nativeFileSystemSupported
550
549
  } from "browser-fs-access";
551
- import { EVENT, MIME_TYPES, debounce } from "@excalidraw/common";
552
- var INPUT_CHANGE_INTERVAL_MS = 5e3;
550
+ import { MIME_TYPES } from "@excalidraw/common";
553
551
  var fileOpen = async (opts) => {
554
552
  const mimeTypes = opts.extensions?.reduce((mimeTypes2, type) => {
555
553
  mimeTypes2.push(MIME_TYPES[type]);
@@ -565,39 +563,7 @@ var fileOpen = async (opts) => {
565
563
  description: opts.description,
566
564
  extensions,
567
565
  mimeTypes,
568
- multiple: opts.multiple ?? false,
569
- legacySetup: (resolve, reject, input) => {
570
- const scheduleRejection = debounce(reject, INPUT_CHANGE_INTERVAL_MS);
571
- const focusHandler = () => {
572
- checkForFile();
573
- document.addEventListener(EVENT.KEYUP, scheduleRejection);
574
- document.addEventListener(EVENT.POINTER_UP, scheduleRejection);
575
- scheduleRejection();
576
- };
577
- const checkForFile = () => {
578
- if (input.files?.length) {
579
- const ret = opts.multiple ? [...input.files] : input.files[0];
580
- resolve(ret);
581
- }
582
- };
583
- requestAnimationFrame(() => {
584
- window.addEventListener(EVENT.FOCUS, focusHandler);
585
- });
586
- const interval = window.setInterval(() => {
587
- checkForFile();
588
- }, INPUT_CHANGE_INTERVAL_MS);
589
- return (rejectPromise) => {
590
- clearInterval(interval);
591
- scheduleRejection.cancel();
592
- window.removeEventListener(EVENT.FOCUS, focusHandler);
593
- document.removeEventListener(EVENT.KEYUP, scheduleRejection);
594
- document.removeEventListener(EVENT.POINTER_UP, scheduleRejection);
595
- if (rejectPromise) {
596
- console.warn("Opening the file was canceled (legacy-fs).");
597
- rejectPromise(new AbortError());
598
- }
599
- };
600
- }
566
+ multiple: opts.multiple ?? false
601
567
  });
602
568
  if (Array.isArray(files)) {
603
569
  return await Promise.all(
@@ -615,7 +581,8 @@ var fileSave = (blob, opts) => {
615
581
  extensions: [`.${opts.extension}`],
616
582
  mimeTypes: opts.mimeTypes
617
583
  },
618
- opts.fileHandle
584
+ opts.fileHandle,
585
+ false
619
586
  );
620
587
  };
621
588
 
@@ -643,18 +610,24 @@ var serializeAsJSON = (elements, appState, files, type) => {
643
610
  };
644
611
  return JSON.stringify(data, null, 2);
645
612
  };
646
- var saveAsJSON = async (elements, appState, files, name = appState.name || DEFAULT_FILENAME) => {
647
- const serialized = serializeAsJSON(elements, appState, files, "local");
648
- const blob = new Blob([serialized], {
649
- type: MIME_TYPES2.excalidraw
613
+ var saveAsJSON = async ({
614
+ data,
615
+ filename,
616
+ fileHandle
617
+ }) => {
618
+ const blob = Promise.resolve(data).then(({ elements, appState, files }) => {
619
+ const serialized = serializeAsJSON(elements, appState, files, "local");
620
+ return new Blob([serialized], {
621
+ type: MIME_TYPES2.excalidraw
622
+ });
650
623
  });
651
- const fileHandle = await fileSave(blob, {
652
- name,
624
+ const savedFileHandle = await fileSave(blob, {
625
+ name: filename,
653
626
  extension: "excalidraw",
654
627
  description: "Excalidraw file",
655
- fileHandle: isImageFileHandle(appState.fileHandle) ? null : appState.fileHandle
628
+ fileHandle: isImageFileHandle(fileHandle) ? null : fileHandle
656
629
  });
657
- return { fileHandle };
630
+ return { fileHandle: savedFileHandle };
658
631
  };
659
632
  var loadFromJSON = async (localAppState, localElements) => {
660
633
  const file = await fileOpen({
@@ -778,7 +751,7 @@ import { promiseTry as promiseTry2, LOCAL_FONT_PROTOCOL as LOCAL_FONT_PROTOCOL2
778
751
  import { isServerEnv, promiseTry } from "@excalidraw/common";
779
752
 
780
753
  // workers.ts
781
- import { debounce as debounce2 } from "@excalidraw/common";
754
+ import { debounce } from "@excalidraw/common";
782
755
  var IdleWorker = class {
783
756
  constructor(workerUrl) {
784
757
  __publicField(this, "instance");
@@ -852,7 +825,7 @@ var WorkerPool = class _WorkerPool {
852
825
  */
853
826
  async createWorker() {
854
827
  const worker = new IdleWorker(this.workerUrl);
855
- worker.debounceTerminate = debounce2((reject) => {
828
+ worker.debounceTerminate = debounce((reject) => {
856
829
  worker.instance.terminate();
857
830
  if (this.idleWorkers.has(worker)) {
858
831
  this.idleWorkers.delete(worker);
@@ -3545,8 +3518,7 @@ var _renderStaticScene = ({
3545
3518
  var renderStaticSceneThrottled = throttleRAF(
3546
3519
  (config) => {
3547
3520
  _renderStaticScene(config);
3548
- },
3549
- { trailing: true }
3521
+ }
3550
3522
  );
3551
3523
  var renderStaticScene = (renderConfig, throttle) => {
3552
3524
  if (throttle) {
@@ -4508,6 +4480,7 @@ import {
4508
4480
  import {
4509
4481
  calculateFixedPointForNonElbowArrowBinding,
4510
4482
  getNonDeletedElements,
4483
+ normalizeArrowhead,
4511
4484
  isPointInElement,
4512
4485
  isValidPolygon,
4513
4486
  projectFixedPointOntoDiagonal
@@ -4736,7 +4709,8 @@ var restoreElement = (element, targetElementsMap, existingElementsMap, opts) =>
4736
4709
  });
4737
4710
  case "line":
4738
4711
  case "draw":
4739
- const { startArrowhead = null, endArrowhead = null } = element;
4712
+ const startArrowhead = normalizeArrowhead(element.startArrowhead);
4713
+ const endArrowhead = normalizeArrowhead(element.endArrowhead);
4740
4714
  let x = element.x;
4741
4715
  let y = element.y;
4742
4716
  let points = (
@@ -4761,7 +4735,8 @@ var restoreElement = (element, targetElementsMap, existingElementsMap, opts) =>
4761
4735
  ...getSizeFromPoints(points)
4762
4736
  });
4763
4737
  case "arrow": {
4764
- const { startArrowhead: startArrowhead2 = null, endArrowhead: endArrowhead2 = "arrow" } = element;
4738
+ const startArrowhead2 = normalizeArrowhead(element.startArrowhead);
4739
+ const endArrowhead2 = element.endArrowhead === void 0 ? "arrow" : normalizeArrowhead(element.endArrowhead);
4765
4740
  const x2 = element.x;
4766
4741
  const y2 = element.y;
4767
4742
  const points2 = (
@@ -5102,7 +5077,7 @@ var parseFileContents = async (blob) => {
5102
5077
  let contents;
5103
5078
  if (blob.type === MIME_TYPES6.png) {
5104
5079
  try {
5105
- return await (await import("./data/image-X6URJSP5.js")).decodePngMetadata(blob);
5080
+ return await (await import("./data/image-3J4DLBV6.js")).decodePngMetadata(blob);
5106
5081
  } catch (error) {
5107
5082
  if (error.message === "INVALID") {
5108
5083
  throw new ImageSceneDataError(
@@ -5536,4 +5511,4 @@ export {
5536
5511
  createFile,
5537
5512
  normalizeFile
5538
5513
  };
5539
- //# sourceMappingURL=chunk-FXVS2QTZ.js.map
5514
+ //# sourceMappingURL=chunk-LWYHXCPK.js.map