@excalidraw/excalidraw 0.18.0-2874f9e → 0.18.0-2a82821

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 (158) hide show
  1. package/CHANGELOG.md +88 -0
  2. package/README.md +111 -14
  3. package/dist/dev/{chunk-IFMURN5W.js → chunk-KY5OFS4H.js} +31 -5
  4. package/dist/dev/chunk-KY5OFS4H.js.map +7 -0
  5. package/dist/dev/{chunk-FXVS2QTZ.js → chunk-T3GRJXT6.js} +239 -90
  6. package/dist/dev/chunk-T3GRJXT6.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-7TCIBRTP.js} +2 -2
  10. package/dist/dev/index.css +280 -82
  11. package/dist/dev/index.css.map +3 -3
  12. package/dist/dev/index.js +7831 -4445
  13. package/dist/dev/index.js.map +4 -4
  14. package/dist/dev/locales/{en-ZZQASRYX.js → en-BYFCZL7X.js} +4 -2
  15. package/dist/prod/chunk-2HD5NY2D.js +4 -0
  16. package/dist/prod/chunk-RLJP2BVF.js +12 -0
  17. package/dist/prod/components/TTDDialog/CodeMirrorEditor-UCMRAMCV.js +1 -0
  18. package/dist/prod/data/{image-N3OFZNE6.js → image-2UP6PNYP.js} +1 -1
  19. package/dist/prod/index.css +1 -1
  20. package/dist/prod/index.js +39 -30
  21. package/dist/prod/locales/en-W2XZHOH3.js +1 -0
  22. package/dist/types/common/src/appEventBus.d.ts +27 -0
  23. package/dist/types/common/src/colors.d.ts +2 -2
  24. package/dist/types/common/src/constants.d.ts +9 -7
  25. package/dist/types/common/src/index.d.ts +2 -0
  26. package/dist/types/common/src/utils.d.ts +1 -3
  27. package/dist/types/common/src/versionedSnapshotStore.d.ts +17 -0
  28. package/dist/types/element/src/Scene.d.ts +7 -3
  29. package/dist/types/element/src/arrowheads.d.ts +3 -0
  30. package/dist/types/element/src/binding.d.ts +3 -4
  31. package/dist/types/element/src/bounds.d.ts +22 -3
  32. package/dist/types/element/src/comparisons.d.ts +1 -0
  33. package/dist/types/element/src/duplicate.d.ts +1 -0
  34. package/dist/types/element/src/elbowArrow.d.ts +2 -0
  35. package/dist/types/element/src/frame.d.ts +7 -6
  36. package/dist/types/element/src/index.d.ts +1 -0
  37. package/dist/types/element/src/linearElementEditor.d.ts +5 -2
  38. package/dist/types/element/src/mutateElement.d.ts +2 -0
  39. package/dist/types/element/src/newElement.d.ts +1 -0
  40. package/dist/types/element/src/selection.d.ts +7 -3
  41. package/dist/types/element/src/shape.d.ts +1 -1
  42. package/dist/types/element/src/textElement.d.ts +1 -1
  43. package/dist/types/element/src/textWrapping.d.ts +26 -0
  44. package/dist/types/element/src/typeChecks.d.ts +1 -0
  45. package/dist/types/element/src/types.d.ts +11 -2
  46. package/dist/types/element/src/utils.d.ts +2 -2
  47. package/dist/types/excalidraw/actions/actionAddToLibrary.d.ts +35 -38
  48. package/dist/types/excalidraw/actions/actionBoundText.d.ts +25 -27
  49. package/dist/types/excalidraw/actions/actionCanvas.d.ts +144 -156
  50. package/dist/types/excalidraw/actions/actionClipboard.d.ts +24 -26
  51. package/dist/types/excalidraw/actions/actionCropEditor.d.ts +12 -13
  52. package/dist/types/excalidraw/actions/actionDeleteSelected.d.ts +36 -39
  53. package/dist/types/excalidraw/actions/actionDeselect.d.ts +160 -0
  54. package/dist/types/excalidraw/actions/actionElementLink.d.ts +8 -13
  55. package/dist/types/excalidraw/actions/actionElementLock.d.ts +24 -26
  56. package/dist/types/excalidraw/actions/actionEmbeddable.d.ts +12 -13
  57. package/dist/types/excalidraw/actions/actionExport.d.ts +67 -349
  58. package/dist/types/excalidraw/actions/actionFrame.d.ts +49 -52
  59. package/dist/types/excalidraw/actions/actionGroup.d.ts +25 -27
  60. package/dist/types/excalidraw/actions/actionLinearEditor.d.ts +13 -13
  61. package/dist/types/excalidraw/actions/actionLink.d.ts +12 -13
  62. package/dist/types/excalidraw/actions/actionMenu.d.ts +8 -13
  63. package/dist/types/excalidraw/actions/actionProperties.d.ts +36 -29
  64. package/dist/types/excalidraw/actions/actionSelectAll.d.ts +12 -13
  65. package/dist/types/excalidraw/actions/actionStyles.d.ts +12 -12
  66. package/dist/types/excalidraw/actions/actionTextAutoResize.d.ts +3 -3
  67. package/dist/types/excalidraw/actions/actionToggleArrowBinding.d.ts +173 -0
  68. package/dist/types/excalidraw/actions/actionToggleGridMode.d.ts +12 -13
  69. package/dist/types/excalidraw/actions/actionToggleMidpointSnapping.d.ts +173 -0
  70. package/dist/types/excalidraw/actions/actionToggleObjectsSnapMode.d.ts +12 -13
  71. package/dist/types/excalidraw/actions/actionToggleSearchMenu.d.ts +8 -13
  72. package/dist/types/excalidraw/actions/actionToggleStats.d.ts +12 -13
  73. package/dist/types/excalidraw/actions/actionToggleViewMode.d.ts +12 -13
  74. package/dist/types/excalidraw/actions/actionToggleZenMode.d.ts +12 -13
  75. package/dist/types/excalidraw/actions/index.d.ts +4 -1
  76. package/dist/types/excalidraw/actions/types.d.ts +1 -1
  77. package/dist/types/excalidraw/{animated-trail.d.ts → animatedTrail.d.ts} +4 -3
  78. package/dist/types/excalidraw/appState.d.ts +6 -2
  79. package/dist/types/excalidraw/charts/charts.bar.d.ts +2 -0
  80. package/dist/types/excalidraw/charts/charts.constants.d.ts +48 -0
  81. package/dist/types/excalidraw/charts/charts.helpers.d.ts +32 -0
  82. package/dist/types/excalidraw/charts/charts.line.d.ts +2 -0
  83. package/dist/types/excalidraw/charts/charts.parse.d.ts +10 -0
  84. package/dist/types/excalidraw/charts/charts.radar.d.ts +2 -0
  85. package/dist/types/excalidraw/charts/charts.types.d.ts +18 -0
  86. package/dist/types/excalidraw/charts/index.d.ts +7 -0
  87. package/dist/types/excalidraw/clipboard.d.ts +2 -5
  88. package/dist/types/excalidraw/components/ActiveConfirmDialog.d.ts +1 -1
  89. package/dist/types/excalidraw/components/App.d.ts +54 -14
  90. package/dist/types/excalidraw/components/AppStateObserver.d.ts +37 -0
  91. package/dist/types/excalidraw/components/ColorPicker/colorPickerUtils.d.ts +1 -1
  92. package/dist/types/excalidraw/components/CommandPalette/defaultCommandPaletteItems.d.ts +1 -2
  93. package/dist/types/excalidraw/components/ConvertElementTypePopup.d.ts +1 -1
  94. package/dist/types/excalidraw/components/EyeDropper.d.ts +1 -1
  95. package/dist/types/excalidraw/components/IconPicker.d.ts +14 -9
  96. package/dist/types/excalidraw/components/LibraryMenu.d.ts +1 -1
  97. package/dist/types/excalidraw/components/OverwriteConfirm/OverwriteConfirmState.d.ts +1 -1
  98. package/dist/types/excalidraw/components/PasteChartDialog.d.ts +4 -5
  99. package/dist/types/excalidraw/components/Range.d.ts +10 -4
  100. package/dist/types/excalidraw/components/SVGLayer.d.ts +1 -1
  101. package/dist/types/excalidraw/components/SearchMenu.d.ts +1 -1
  102. package/dist/types/excalidraw/components/Sidebar/Sidebar.d.ts +1 -1
  103. package/dist/types/excalidraw/components/TTDDialog/CodeMirrorEditor.d.ts +11 -0
  104. package/dist/types/excalidraw/components/TTDDialog/TTDContext.d.ts +4 -4
  105. package/dist/types/excalidraw/components/TTDDialog/TTDDialogInput.d.ts +3 -3
  106. package/dist/types/excalidraw/components/TTDDialog/TTDDialogOutput.d.ts +4 -1
  107. package/dist/types/excalidraw/components/TTDDialog/mermaid-lang-lite.d.ts +2 -0
  108. package/dist/types/excalidraw/components/TTDDialog/useTTDChatStorage.d.ts +3 -3
  109. package/dist/types/excalidraw/components/TTDDialog/utils/TTDStreamFetch.d.ts +1 -1
  110. package/dist/types/excalidraw/components/TTDDialog/utils/mermaidAutoFix.d.ts +1 -0
  111. package/dist/types/excalidraw/components/TTDDialog/utils/mermaidError.d.ts +10 -0
  112. package/dist/types/excalidraw/components/Toast.d.ts +8 -4
  113. package/dist/types/excalidraw/components/canvases/InteractiveCanvas.d.ts +2 -1
  114. package/dist/types/excalidraw/components/canvases/NewElementCanvas.d.ts +1 -0
  115. package/dist/types/excalidraw/components/canvases/StaticCanvas.d.ts +1 -1
  116. package/dist/types/excalidraw/components/dropdownMenu/DropdownMenuItemContentRadio.d.ts +2 -1
  117. package/dist/types/excalidraw/components/icons.d.ts +19 -8
  118. package/dist/types/excalidraw/components/main-menu/DefaultItems.d.ts +9 -3
  119. package/dist/types/excalidraw/components/shapes.d.ts +7 -0
  120. package/dist/types/excalidraw/data/blob.d.ts +31 -34
  121. package/dist/types/excalidraw/data/filesystem.d.ts +3 -5
  122. package/dist/types/excalidraw/data/index.d.ts +2 -3
  123. package/dist/types/excalidraw/data/json.d.ts +30 -23
  124. package/dist/types/excalidraw/data/library.d.ts +1 -1
  125. package/dist/types/excalidraw/data/resave.d.ts +7 -2
  126. package/dist/types/excalidraw/eraser/index.d.ts +2 -3
  127. package/dist/types/excalidraw/hooks/useAppStateValue.d.ts +29 -0
  128. package/dist/types/excalidraw/hooks/useLibraryItemSvg.d.ts +1 -1
  129. package/dist/types/excalidraw/index.d.ts +27 -4
  130. package/dist/types/excalidraw/{laser-trails.d.ts → laserTrails.d.ts} +5 -7
  131. package/dist/types/excalidraw/lasso/index.d.ts +2 -3
  132. package/dist/types/excalidraw/renderer/animation.d.ts +4 -1
  133. package/dist/types/excalidraw/scene/Renderer.d.ts +426 -19
  134. package/dist/types/excalidraw/scene/index.d.ts +1 -1
  135. package/dist/types/excalidraw/textAutoResizeHandle.d.ts +15 -0
  136. package/dist/types/excalidraw/types.d.ts +110 -18
  137. package/dist/types/excalidraw/wysiwyg/textWysiwyg.d.ts +5 -1
  138. package/dist/types/fractional-indexing/src/index.d.ts +29 -0
  139. package/dist/types/laser-pointer/src/index.d.ts +2 -0
  140. package/dist/types/laser-pointer/src/math.d.ts +16 -0
  141. package/dist/types/laser-pointer/src/simplify.d.ts +2 -0
  142. package/dist/types/laser-pointer/src/state.d.ts +35 -0
  143. package/dist/types/math/src/constants.d.ts +0 -1
  144. package/dist/types/math/src/curve.d.ts +4 -1
  145. package/dist/types/math/src/point.d.ts +2 -1
  146. package/dist/types/utils/src/index.d.ts +1 -2
  147. package/package.json +12 -8
  148. package/dist/dev/chunk-FXVS2QTZ.js.map +0 -7
  149. package/dist/dev/chunk-IFMURN5W.js.map +0 -7
  150. package/dist/prod/chunk-MSBJ7C4T.js +0 -12
  151. package/dist/prod/chunk-RFLYRLPI.js +0 -4
  152. package/dist/prod/locales/en-RQF5X6GM.js +0 -1
  153. package/dist/types/excalidraw/animation-frame-handler.d.ts +0 -16
  154. package/dist/types/excalidraw/charts.d.ts +0 -27
  155. package/dist/types/utils/src/bbox.d.ts +0 -9
  156. package/dist/types/utils/src/withinBounds.d.ts +0 -19
  157. /package/dist/dev/data/{image-X6URJSP5.js.map → image-7TCIBRTP.js.map} +0 -0
  158. /package/dist/dev/locales/{en-ZZQASRYX.js.map → en-BYFCZL7X.js.map} +0 -0
@@ -27,6 +27,7 @@ import {
27
27
  DEFAULT_ELEMENT_PROPS,
28
28
  DEFAULT_FONT_FAMILY,
29
29
  DEFAULT_FONT_SIZE,
30
+ DEFAULT_ELEMENT_STROKE_WIDTH_KEY,
30
31
  DEFAULT_TEXT_ALIGN,
31
32
  DEFAULT_GRID_SIZE,
32
33
  EXPORT_SCALES,
@@ -41,7 +42,6 @@ var getDefaultAppState = () => {
41
42
  showWelcomeScreen: false,
42
43
  theme: THEME.LIGHT,
43
44
  collaborators: /* @__PURE__ */ new Map(),
44
- currentChartType: "bar",
45
45
  currentItemBackgroundColor: DEFAULT_ELEMENT_PROPS.backgroundColor,
46
46
  currentItemEndArrowhead: "arrow",
47
47
  currentItemFillStyle: DEFAULT_ELEMENT_PROPS.fillStyle,
@@ -49,12 +49,13 @@ var getDefaultAppState = () => {
49
49
  currentItemFontSize: DEFAULT_FONT_SIZE,
50
50
  currentItemOpacity: DEFAULT_ELEMENT_PROPS.opacity,
51
51
  currentItemRoughness: DEFAULT_ELEMENT_PROPS.roughness,
52
+ currentItemStrokeVariability: "constant",
52
53
  currentItemStartArrowhead: null,
53
54
  currentItemStrokeColor: DEFAULT_ELEMENT_PROPS.strokeColor,
54
55
  currentItemRoundness: isTestEnv() ? "sharp" : "round",
55
56
  currentItemArrowType: ARROW_TYPE.round,
56
57
  currentItemStrokeStyle: DEFAULT_ELEMENT_PROPS.strokeStyle,
57
- currentItemStrokeWidth: DEFAULT_ELEMENT_PROPS.strokeWidth,
58
+ currentItemStrokeWidthKey: DEFAULT_ELEMENT_STROKE_WIDTH_KEY,
58
59
  currentItemTextAlign: DEFAULT_TEXT_ALIGN,
59
60
  currentHoveredFontFamily: null,
60
61
  cursorButton: "up",
@@ -85,6 +86,8 @@ var getDefaultAppState = () => {
85
86
  gridStep: DEFAULT_GRID_STEP,
86
87
  gridModeEnabled: false,
87
88
  isBindingEnabled: true,
89
+ bindingPreference: "enabled",
90
+ isMidpointSnappingEnabled: true,
88
91
  defaultSidebarDockedPreference: false,
89
92
  isLoading: false,
90
93
  isResizing: false,
@@ -97,7 +100,6 @@ var getDefaultAppState = () => {
97
100
  openPopup: null,
98
101
  openSidebar: null,
99
102
  openDialog: null,
100
- pasteDialog: { shown: false, data: null },
101
103
  previousSelectedElementIds: {},
102
104
  resizingElement: null,
103
105
  scrolledOutside: false,
@@ -113,7 +115,6 @@ var getDefaultAppState = () => {
113
115
  open: false,
114
116
  panels: STATS_PANELS.generalStats | STATS_PANELS.elementProperties
115
117
  },
116
- startBoundElement: null,
117
118
  suggestedBinding: null,
118
119
  frameRendering: { enabled: true, clip: true, name: true, outline: true },
119
120
  frameToHighlight: null,
@@ -141,14 +142,14 @@ var getDefaultAppState = () => {
141
142
  searchMatches: null,
142
143
  lockedMultiSelections: {},
143
144
  activeLockedId: null,
144
- bindMode: "orbit"
145
+ bindMode: "orbit",
146
+ boxSelectionMode: "contain"
145
147
  };
146
148
  };
147
149
  var APP_STATE_STORAGE_CONF = /* @__PURE__ */ ((config) => config)({
148
150
  showWelcomeScreen: { browser: true, export: false, server: false },
149
151
  theme: { browser: true, export: false, server: false },
150
152
  collaborators: { browser: false, export: false, server: false },
151
- currentChartType: { browser: true, export: false, server: false },
152
153
  currentItemBackgroundColor: { browser: true, export: false, server: false },
153
154
  currentItemEndArrowhead: { browser: true, export: false, server: false },
154
155
  currentItemFillStyle: { browser: true, export: false, server: false },
@@ -166,10 +167,15 @@ var APP_STATE_STORAGE_CONF = /* @__PURE__ */ ((config) => config)({
166
167
  },
167
168
  currentItemOpacity: { browser: true, export: false, server: false },
168
169
  currentItemRoughness: { browser: true, export: false, server: false },
170
+ currentItemStrokeVariability: {
171
+ browser: true,
172
+ export: false,
173
+ server: false
174
+ },
169
175
  currentItemStartArrowhead: { browser: true, export: false, server: false },
170
176
  currentItemStrokeColor: { browser: true, export: false, server: false },
171
177
  currentItemStrokeStyle: { browser: true, export: false, server: false },
172
- currentItemStrokeWidth: { browser: true, export: false, server: false },
178
+ currentItemStrokeWidthKey: { browser: true, export: false, server: false },
173
179
  currentItemTextAlign: { browser: true, export: false, server: false },
174
180
  currentHoveredFontFamily: { browser: false, export: false, server: false },
175
181
  cursorButton: { browser: true, export: false, server: false },
@@ -191,7 +197,10 @@ var APP_STATE_STORAGE_CONF = /* @__PURE__ */ ((config) => config)({
191
197
  gridStep: { browser: true, export: true, server: true },
192
198
  gridModeEnabled: { browser: true, export: true, server: true },
193
199
  height: { browser: false, export: false, server: false },
194
- isBindingEnabled: { browser: false, export: false, server: false },
200
+ isBindingEnabled: { browser: true, export: false, server: false },
201
+ boxSelectionMode: { browser: true, export: false, server: false },
202
+ bindingPreference: { browser: true, export: false, server: false },
203
+ isMidpointSnappingEnabled: { browser: true, export: false, server: false },
195
204
  defaultSidebarDockedPreference: {
196
205
  browser: true,
197
206
  export: false,
@@ -210,7 +219,6 @@ var APP_STATE_STORAGE_CONF = /* @__PURE__ */ ((config) => config)({
210
219
  openPopup: { browser: false, export: false, server: false },
211
220
  openSidebar: { browser: true, export: false, server: false },
212
221
  openDialog: { browser: false, export: false, server: false },
213
- pasteDialog: { browser: false, export: false, server: false },
214
222
  previousSelectedElementIds: { browser: true, export: false, server: false },
215
223
  resizingElement: { browser: false, export: false, server: false },
216
224
  scrolledOutside: { browser: true, export: false, server: false },
@@ -227,7 +235,6 @@ var APP_STATE_STORAGE_CONF = /* @__PURE__ */ ((config) => config)({
227
235
  selectionElement: { browser: false, export: false, server: false },
228
236
  shouldCacheIgnoreZoom: { browser: true, export: false, server: false },
229
237
  stats: { browser: true, export: false, server: false },
230
- startBoundElement: { browser: false, export: false, server: false },
231
238
  suggestedBinding: { browser: false, export: false, server: false },
232
239
  frameRendering: { browser: false, export: false, server: false },
233
240
  frameToHighlight: { browser: false, export: false, server: false },
@@ -416,6 +423,7 @@ import {
416
423
  hasBackground,
417
424
  hasStrokeWidth,
418
425
  hasStrokeStyle,
426
+ hasFreedrawMode,
419
427
  canHaveArrowheads,
420
428
  canChangeRoundness
421
429
  } from "@excalidraw/element";
@@ -535,7 +543,6 @@ var decode = (data) => {
535
543
 
536
544
  // data/json.ts
537
545
  import {
538
- DEFAULT_FILENAME,
539
546
  EXPORT_DATA_TYPES,
540
547
  getExportSource,
541
548
  MIME_TYPES as MIME_TYPES2,
@@ -548,8 +555,7 @@ import {
548
555
  fileSave as _fileSave,
549
556
  supported as nativeFileSystemSupported
550
557
  } from "browser-fs-access";
551
- import { EVENT, MIME_TYPES, debounce } from "@excalidraw/common";
552
- var INPUT_CHANGE_INTERVAL_MS = 5e3;
558
+ import { MIME_TYPES } from "@excalidraw/common";
553
559
  var fileOpen = async (opts) => {
554
560
  const mimeTypes = opts.extensions?.reduce((mimeTypes2, type) => {
555
561
  mimeTypes2.push(MIME_TYPES[type]);
@@ -565,39 +571,7 @@ var fileOpen = async (opts) => {
565
571
  description: opts.description,
566
572
  extensions,
567
573
  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
- }
574
+ multiple: opts.multiple ?? false
601
575
  });
602
576
  if (Array.isArray(files)) {
603
577
  return await Promise.all(
@@ -615,7 +589,8 @@ var fileSave = (blob, opts) => {
615
589
  extensions: [`.${opts.extension}`],
616
590
  mimeTypes: opts.mimeTypes
617
591
  },
618
- opts.fileHandle
592
+ opts.fileHandle,
593
+ false
619
594
  );
620
595
  };
621
596
 
@@ -643,18 +618,24 @@ var serializeAsJSON = (elements, appState, files, type) => {
643
618
  };
644
619
  return JSON.stringify(data, null, 2);
645
620
  };
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
621
+ var saveAsJSON = async ({
622
+ data,
623
+ filename,
624
+ fileHandle
625
+ }) => {
626
+ const blob = Promise.resolve(data).then(({ elements, appState, files }) => {
627
+ const serialized = serializeAsJSON(elements, appState, files, "local");
628
+ return new Blob([serialized], {
629
+ type: MIME_TYPES2.excalidraw
630
+ });
650
631
  });
651
- const fileHandle = await fileSave(blob, {
652
- name,
632
+ const savedFileHandle = await fileSave(blob, {
633
+ name: filename,
653
634
  extension: "excalidraw",
654
635
  description: "Excalidraw file",
655
- fileHandle: isImageFileHandle(appState.fileHandle) ? null : appState.fileHandle
636
+ fileHandle: isImageFileHandle(fileHandle) ? null : fileHandle
656
637
  });
657
- return { fileHandle };
638
+ return { fileHandle: savedFileHandle };
658
639
  };
659
640
  var loadFromJSON = async (localAppState, localElements) => {
660
641
  const file = await fileOpen({
@@ -778,7 +759,7 @@ import { promiseTry as promiseTry2, LOCAL_FONT_PROTOCOL as LOCAL_FONT_PROTOCOL2
778
759
  import { isServerEnv, promiseTry } from "@excalidraw/common";
779
760
 
780
761
  // workers.ts
781
- import { debounce as debounce2 } from "@excalidraw/common";
762
+ import { debounce } from "@excalidraw/common";
782
763
  var IdleWorker = class {
783
764
  constructor(workerUrl) {
784
765
  __publicField(this, "instance");
@@ -852,7 +833,7 @@ var WorkerPool = class _WorkerPool {
852
833
  */
853
834
  async createWorker() {
854
835
  const worker = new IdleWorker(this.workerUrl);
855
- worker.debounceTerminate = debounce2((reject) => {
836
+ worker.debounceTerminate = debounce((reject) => {
856
837
  worker.instance.terminate();
857
838
  if (this.idleWorkers.has(worker)) {
858
839
  this.idleWorkers.delete(worker);
@@ -3208,7 +3189,10 @@ var bootstrapCanvas = ({
3208
3189
  context.clearRect(0, 0, normalizedWidth, normalizedHeight);
3209
3190
  }
3210
3191
  context.save();
3211
- context.fillStyle = theme === THEME2.DARK ? applyDarkModeFilter(viewBackgroundColor) : viewBackgroundColor;
3192
+ context.fillStyle = applyDarkModeFilter(
3193
+ viewBackgroundColor,
3194
+ theme === THEME2.DARK
3195
+ );
3212
3196
  context.fillRect(0, 0, normalizedWidth, normalizedHeight);
3213
3197
  context.restore();
3214
3198
  } else {
@@ -3545,8 +3529,7 @@ var _renderStaticScene = ({
3545
3529
  var renderStaticSceneThrottled = throttleRAF(
3546
3530
  (config) => {
3547
3531
  _renderStaticScene(config);
3548
- },
3549
- { trailing: true }
3532
+ }
3550
3533
  );
3551
3534
  var renderStaticScene = (renderConfig, throttle) => {
3552
3535
  if (throttle) {
@@ -3776,6 +3759,11 @@ var renderElementToSvg = (element, elementsMap, rsvg, svgRoot, files, offsetX, o
3776
3759
  );
3777
3760
  offsetX = offsetX || 0;
3778
3761
  offsetY = offsetY || 0;
3762
+ maskPath.setAttribute("maskUnits", "userSpaceOnUse");
3763
+ maskPath.setAttribute("x", "0");
3764
+ maskPath.setAttribute("y", "0");
3765
+ maskPath.setAttribute("width", `${element.width + 100 + offsetX}`);
3766
+ maskPath.setAttribute("height", `${element.height + 100 + offsetY}`);
3779
3767
  maskRectVisible.setAttribute("x", "0");
3780
3768
  maskRectVisible.setAttribute("y", "0");
3781
3769
  maskRectVisible.setAttribute("fill", "#fff");
@@ -3856,7 +3844,10 @@ var renderElementToSvg = (element, elementsMap, rsvg, svgRoot, files, offsetX, o
3856
3844
  const path = svgRoot.ownerDocument.createElementNS(SVG_NS, "path");
3857
3845
  path.setAttribute(
3858
3846
  "fill",
3859
- renderConfig.theme === THEME4.DARK ? applyDarkModeFilter3(element.strokeColor) : element.strokeColor
3847
+ applyDarkModeFilter3(
3848
+ element.strokeColor,
3849
+ renderConfig.theme === THEME4.DARK
3850
+ )
3860
3851
  );
3861
3852
  path.setAttribute("d", shape);
3862
3853
  wrapper.appendChild(path);
@@ -4027,7 +4018,10 @@ var renderElementToSvg = (element, elementsMap, rsvg, svgRoot, files, offsetX, o
4027
4018
  rect.setAttribute("fill", "none");
4028
4019
  rect.setAttribute(
4029
4020
  "stroke",
4030
- renderConfig.theme === THEME4.DARK ? applyDarkModeFilter3(FRAME_STYLE2.strokeColor) : FRAME_STYLE2.strokeColor
4021
+ applyDarkModeFilter3(
4022
+ FRAME_STYLE2.strokeColor,
4023
+ renderConfig.theme === THEME4.DARK
4024
+ )
4031
4025
  );
4032
4026
  rect.setAttribute("stroke-width", FRAME_STYLE2.strokeWidth.toString());
4033
4027
  addToRoot(rect, element);
@@ -4067,7 +4061,10 @@ var renderElementToSvg = (element, elementsMap, rsvg, svgRoot, files, offsetX, o
4067
4061
  text.setAttribute("font-size", `${element.fontSize}px`);
4068
4062
  text.setAttribute(
4069
4063
  "fill",
4070
- renderConfig.theme === THEME4.DARK ? applyDarkModeFilter3(element.strokeColor) : element.strokeColor
4064
+ applyDarkModeFilter3(
4065
+ element.strokeColor,
4066
+ renderConfig.theme === THEME4.DARK
4067
+ )
4071
4068
  );
4072
4069
  text.setAttribute("text-anchor", textAnchor);
4073
4070
  text.setAttribute("style", "white-space: pre;");
@@ -4209,7 +4206,11 @@ var prepareElementsForRender = ({
4209
4206
  }) => {
4210
4207
  let nextElements;
4211
4208
  if (exportingFrame) {
4212
- nextElements = getElementsOverlappingFrame(elements, exportingFrame);
4209
+ nextElements = getElementsOverlappingFrame(
4210
+ elements,
4211
+ exportingFrame,
4212
+ arrayToMap(elements)
4213
+ );
4213
4214
  } else if (frameRendering.enabled && frameRendering.name) {
4214
4215
  nextElements = addFrameLabelsAsTextElements(elements, {
4215
4216
  exportWithDarkMode
@@ -4399,7 +4400,7 @@ var exportToSvg = async (elements, appState, files, opts) => {
4399
4400
  rect.setAttribute("height", `${height}`);
4400
4401
  rect.setAttribute(
4401
4402
  "fill",
4402
- exportWithDarkMode ? applyDarkModeFilter4(viewBackgroundColor) : viewBackgroundColor
4403
+ applyDarkModeFilter4(viewBackgroundColor, exportWithDarkMode)
4403
4404
  );
4404
4405
  svgRoot.appendChild(rect);
4405
4406
  }
@@ -4486,9 +4487,10 @@ var getExportSize = (elements, exportPadding, scale) => {
4486
4487
  };
4487
4488
 
4488
4489
  // data/restore.ts
4489
- import { isFiniteNumber, pointFrom as pointFrom2 } from "@excalidraw/math";
4490
+ import { isFiniteNumber, isValidPoint, pointFrom as pointFrom2 } from "@excalidraw/math";
4490
4491
  import {
4491
4492
  DEFAULT_FONT_FAMILY as DEFAULT_FONT_FAMILY2,
4493
+ DEFAULT_STROKE_STREAMLINE,
4492
4494
  DEFAULT_TEXT_ALIGN as DEFAULT_TEXT_ALIGN2,
4493
4495
  DEFAULT_VERTICAL_ALIGN,
4494
4496
  FONT_FAMILY as FONT_FAMILY3,
@@ -4503,11 +4505,14 @@ import {
4503
4505
  arrayToMap as arrayToMap2,
4504
4506
  getSizeFromPoints,
4505
4507
  normalizeLink as normalizeLink2,
4506
- getLineHeight
4508
+ getLineHeight,
4509
+ STROKE_WIDTH,
4510
+ STROKE_WIDTH_KEYS
4507
4511
  } from "@excalidraw/common";
4508
4512
  import {
4509
4513
  calculateFixedPointForNonElbowArrowBinding,
4510
4514
  getNonDeletedElements,
4515
+ normalizeArrowhead,
4511
4516
  isPointInElement,
4512
4517
  isValidPolygon,
4513
4518
  projectFixedPointOntoDiagonal
@@ -4534,6 +4539,46 @@ import { syncInvalidIndices as syncInvalidIndices2 } from "@excalidraw/element";
4534
4539
  import { refreshTextDimensions } from "@excalidraw/element";
4535
4540
  import { getNormalizedDimensions } from "@excalidraw/element";
4536
4541
  import { isInvisiblySmallElement } from "@excalidraw/element";
4542
+ var MAX_ARROW_PX = 75e3;
4543
+ var restoreLinearElementPoints = (points, width, height) => {
4544
+ const restoredPoints = Array.isArray(points) ? points.reduce((acc, point) => {
4545
+ if (isValidPoint(point)) {
4546
+ acc.push(pointFrom2(point[0], point[1]));
4547
+ }
4548
+ return acc;
4549
+ }, []) : [];
4550
+ return restoredPoints.length < 2 ? [
4551
+ pointFrom2(0, 0),
4552
+ pointFrom2(
4553
+ isFiniteNumber(width) ? width : 0,
4554
+ isFiniteNumber(height) ? height : 0
4555
+ )
4556
+ ] : restoredPoints;
4557
+ };
4558
+ var restoreFreedrawPoints = (points, pressures) => {
4559
+ if (!Array.isArray(points)) {
4560
+ return {
4561
+ points: [],
4562
+ pressures: []
4563
+ };
4564
+ }
4565
+ const pressureValues = Array.isArray(pressures) ? pressures : [];
4566
+ const restoredPoints = [];
4567
+ const restoredPressures = [];
4568
+ points.forEach((point, index) => {
4569
+ if (isValidPoint(point)) {
4570
+ restoredPoints.push(pointFrom2(point[0], point[1]));
4571
+ if (index in pressureValues) {
4572
+ const pressure = pressureValues[index];
4573
+ restoredPressures.push(isFiniteNumber(pressure) ? pressure : 0.5);
4574
+ }
4575
+ }
4576
+ });
4577
+ return {
4578
+ points: restoredPoints,
4579
+ pressures: restoredPressures
4580
+ };
4581
+ };
4537
4582
  var AllowedExcalidrawActiveTools = {
4538
4583
  selection: true,
4539
4584
  lasso: true,
@@ -4553,6 +4598,23 @@ var AllowedExcalidrawActiveTools = {
4553
4598
  laser: false,
4554
4599
  magicframe: false
4555
4600
  };
4601
+ var ALLOWED_STROKE_VARIABILITIES = /* @__PURE__ */ new Set([
4602
+ "constant",
4603
+ "variable"
4604
+ ]);
4605
+ var restoreStrokeVariability = (variability, defaultValue) => {
4606
+ return typeof variability === "string" && ALLOWED_STROKE_VARIABILITIES.has(variability) ? variability : defaultValue;
4607
+ };
4608
+ var getStrokeWidthKey = (strokeWidth) => {
4609
+ return isFiniteNumber(strokeWidth) ? STROKE_WIDTH_KEYS.find((key) => STROKE_WIDTH[key] === strokeWidth) ?? null : null;
4610
+ };
4611
+ var restoreFreedrawStrokeOptions = (strokeOptions) => {
4612
+ const options = strokeOptions && typeof strokeOptions === "object" ? strokeOptions : null;
4613
+ return {
4614
+ variability: restoreStrokeVariability(options?.variability, "variable"),
4615
+ streamline: isFiniteNumber(options?.streamline) ? options?.streamline : DEFAULT_STROKE_STREAMLINE
4616
+ };
4617
+ };
4556
4618
  var getFontFamilyByName = (fontFamilyName) => {
4557
4619
  if (Object.keys(FONT_FAMILY3).includes(fontFamilyName)) {
4558
4620
  return FONT_FAMILY3[fontFamilyName];
@@ -4626,7 +4688,9 @@ var repairBinding = (element, binding, targetElementsMap, existingElementsMap, s
4626
4688
  fixedPoint
4627
4689
  };
4628
4690
  }
4629
- console.error(`could not repair binding for element`);
4691
+ console.error(
4692
+ `Could not repair binding for element "${boundElement?.id}" out of (${elementsMap?.size}) elements`
4693
+ );
4630
4694
  } catch (error) {
4631
4695
  console.error("Error repairing binding:", error);
4632
4696
  }
@@ -4721,10 +4785,15 @@ var restoreElement = (element, targetElementsMap, existingElementsMap, opts) =>
4721
4785
  }
4722
4786
  return element;
4723
4787
  case "freedraw": {
4788
+ const { points: points2, pressures } = restoreFreedrawPoints(
4789
+ element.points,
4790
+ element.pressures
4791
+ );
4724
4792
  return restoreElementWithProperties(element, {
4725
- points: element.points,
4793
+ points: points2,
4726
4794
  simulatePressure: element.simulatePressure,
4727
- pressures: element.pressures
4795
+ strokeOptions: restoreFreedrawStrokeOptions(element.strokeOptions),
4796
+ pressures
4728
4797
  });
4729
4798
  }
4730
4799
  case "image":
@@ -4736,15 +4805,22 @@ var restoreElement = (element, targetElementsMap, existingElementsMap, opts) =>
4736
4805
  });
4737
4806
  case "line":
4738
4807
  case "draw":
4739
- const { startArrowhead = null, endArrowhead = null } = element;
4808
+ const startArrowhead = normalizeArrowhead(element.startArrowhead);
4809
+ const endArrowhead = normalizeArrowhead(element.endArrowhead);
4740
4810
  let x = element.x;
4741
4811
  let y = element.y;
4742
- let points = (
4743
- // migrate old arrow model to new one
4744
- !Array.isArray(element.points) || element.points.length < 2 ? [pointFrom2(0, 0), pointFrom2(element.width, element.height)] : element.points
4812
+ let points = restoreLinearElementPoints(
4813
+ element.points,
4814
+ element.width,
4815
+ element.height
4745
4816
  );
4746
4817
  if (points[0][0] !== 0 || points[0][1] !== 0) {
4747
- ({ points, x, y } = LinearElementEditor2.getNormalizeElementPointsAndCoords(element));
4818
+ ({ points, x, y } = LinearElementEditor2.getNormalizeElementPointsAndCoords({
4819
+ ...element,
4820
+ points,
4821
+ x: x ?? 0,
4822
+ y: y ?? 0
4823
+ }));
4748
4824
  }
4749
4825
  return restoreElementWithProperties(element, {
4750
4826
  type: "line",
@@ -4756,29 +4832,37 @@ var restoreElement = (element, targetElementsMap, existingElementsMap, opts) =>
4756
4832
  x,
4757
4833
  y,
4758
4834
  ...isLineElement(element) ? {
4759
- polygon: isValidPolygon(element.points) ? element.polygon ?? false : false
4835
+ polygon: isValidPolygon(points) ? element.polygon ?? false : false
4760
4836
  } : {},
4761
4837
  ...getSizeFromPoints(points)
4762
4838
  });
4763
4839
  case "arrow": {
4764
- const { startArrowhead: startArrowhead2 = null, endArrowhead: endArrowhead2 = "arrow" } = element;
4840
+ const startArrowhead2 = normalizeArrowhead(element.startArrowhead);
4841
+ const endArrowhead2 = element.endArrowhead === void 0 ? "arrow" : normalizeArrowhead(element.endArrowhead);
4765
4842
  const x2 = element.x;
4766
4843
  const y2 = element.y;
4767
- const points2 = (
4768
- // migrate old arrow model to new one
4769
- !Array.isArray(element.points) || element.points.length < 2 ? [pointFrom2(0, 0), pointFrom2(element.width, element.height)] : element.points
4844
+ const points2 = restoreLinearElementPoints(
4845
+ element.points,
4846
+ element.width,
4847
+ element.height
4770
4848
  );
4849
+ const elementWithRestoredPoints = {
4850
+ ...element,
4851
+ points: points2,
4852
+ x: x2 ?? 0,
4853
+ y: y2 ?? 0
4854
+ };
4771
4855
  const base = {
4772
4856
  type: element.type,
4773
4857
  startBinding: repairBinding(
4774
- element,
4858
+ elementWithRestoredPoints,
4775
4859
  element.startBinding,
4776
4860
  targetElementsMap,
4777
4861
  existingElementsMap,
4778
4862
  "start"
4779
4863
  ),
4780
4864
  endBinding: repairBinding(
4781
- element,
4865
+ elementWithRestoredPoints,
4782
4866
  element.endBinding,
4783
4867
  targetElementsMap,
4784
4868
  existingElementsMap,
@@ -4787,8 +4871,8 @@ var restoreElement = (element, targetElementsMap, existingElementsMap, opts) =>
4787
4871
  startArrowhead: startArrowhead2,
4788
4872
  endArrowhead: endArrowhead2,
4789
4873
  points: points2,
4790
- x: x2,
4791
- y: y2,
4874
+ x: x2 ?? 0,
4875
+ y: y2 ?? 0,
4792
4876
  elbowed: element.elbowed,
4793
4877
  ...getSizeFromPoints(points2)
4794
4878
  };
@@ -4799,12 +4883,30 @@ var restoreElement = (element, targetElementsMap, existingElementsMap, opts) =>
4799
4883
  startIsSpecial: element.startIsSpecial,
4800
4884
  endIsSpecial: element.endIsSpecial
4801
4885
  }) : restoreElementWithProperties(element, base);
4802
- return {
4886
+ const normalizedRestoredElement = {
4803
4887
  ...restoredElement,
4804
4888
  ...LinearElementEditor2.getNormalizeElementPointsAndCoords(
4805
4889
  restoredElement
4806
4890
  )
4807
4891
  };
4892
+ if (normalizedRestoredElement.width > MAX_ARROW_PX || normalizedRestoredElement.height > MAX_ARROW_PX) {
4893
+ console.error(
4894
+ `Removing extremely large arrow ${normalizedRestoredElement.id} (type: ${isElbowArrow(normalizedRestoredElement) ? "elbow" : "simple"}, width: ${normalizedRestoredElement.width}, height: ${normalizedRestoredElement.height}, x: ${normalizedRestoredElement.x}, y: ${normalizedRestoredElement.y})`
4895
+ );
4896
+ return {
4897
+ ...normalizedRestoredElement,
4898
+ x: 0,
4899
+ y: 0,
4900
+ width: 100,
4901
+ height: 100,
4902
+ points: [
4903
+ pointFrom2(0, 0),
4904
+ pointFrom2(100, 100)
4905
+ ],
4906
+ isDeleted: true
4907
+ };
4908
+ }
4909
+ return normalizedRestoredElement;
4808
4910
  }
4809
4911
  case "ellipse":
4810
4912
  case "rectangle":
@@ -5029,6 +5131,13 @@ var restoreAppState = (appState, localAppState) => {
5029
5131
  const localValue = localAppState ? localAppState[key] : void 0;
5030
5132
  nextAppState[key] = suppliedValue !== void 0 ? suppliedValue : localValue !== void 0 ? localValue : defaultValue;
5031
5133
  }
5134
+ const boxSelectionMode = appState.boxSelectionMode ?? localAppState?.boxSelectionMode;
5135
+ if (boxSelectionMode !== void 0) {
5136
+ nextAppState.boxSelectionMode = boxSelectionMode;
5137
+ }
5138
+ if (appState.currentItemStrokeWidth !== void 0) {
5139
+ nextAppState.currentItemStrokeWidthKey = getStrokeWidthKey(appState.currentItemStrokeWidth) ?? defaultAppState.currentItemStrokeWidthKey;
5140
+ }
5032
5141
  return {
5033
5142
  ...nextAppState,
5034
5143
  cursorButton: localAppState?.cursorButton || "up",
@@ -5102,7 +5211,7 @@ var parseFileContents = async (blob) => {
5102
5211
  let contents;
5103
5212
  if (blob.type === MIME_TYPES6.png) {
5104
5213
  try {
5105
- return await (await import("./data/image-X6URJSP5.js")).decodePngMetadata(blob);
5214
+ return await (await import("./data/image-7TCIBRTP.js")).decodePngMetadata(blob);
5106
5215
  } catch (error) {
5107
5216
  if (error.message === "INVALID") {
5108
5217
  throw new ImageSceneDataError(
@@ -5289,10 +5398,52 @@ var getDataURL_sync = (data, mimeType) => {
5289
5398
  var dataURLToString = (dataURL) => {
5290
5399
  return base64ToString(dataURL.slice(dataURL.indexOf(",") + 1));
5291
5400
  };
5401
+ var getImageFileDimensions = async (file) => {
5402
+ const browserURL = typeof window !== "undefined" ? window.URL : void 0;
5403
+ let objectURL = null;
5404
+ let imageSource;
5405
+ try {
5406
+ imageSource = browserURL?.createObjectURL ? objectURL = browserURL.createObjectURL(file) : await getDataURL(file);
5407
+ } catch {
5408
+ objectURL = null;
5409
+ imageSource = await getDataURL(file);
5410
+ }
5411
+ return new Promise((resolve, reject) => {
5412
+ const image = new Image();
5413
+ const cleanup = () => {
5414
+ image.onload = null;
5415
+ image.onerror = null;
5416
+ if (objectURL && browserURL?.revokeObjectURL) {
5417
+ browserURL.revokeObjectURL(objectURL);
5418
+ }
5419
+ };
5420
+ image.onload = () => {
5421
+ cleanup();
5422
+ resolve({
5423
+ width: image.naturalWidth || image.width,
5424
+ height: image.naturalHeight || image.height
5425
+ });
5426
+ };
5427
+ image.onerror = (error) => {
5428
+ cleanup();
5429
+ reject(error);
5430
+ };
5431
+ image.src = imageSource;
5432
+ });
5433
+ };
5292
5434
  var resizeImageFile = async (file, opts) => {
5293
5435
  if (file.type === MIME_TYPES6.svg) {
5294
5436
  return file;
5295
5437
  }
5438
+ if (!isSupportedImageFile(file)) {
5439
+ throw new Error("Error: unsupported file type", { cause: "UNSUPPORTED" });
5440
+ }
5441
+ if (!opts.outputType || opts.outputType === file.type) {
5442
+ const dimensions = await getImageFileDimensions(file);
5443
+ if (Math.max(dimensions.width, dimensions.height) <= opts.maxWidthOrHeight) {
5444
+ return file;
5445
+ }
5446
+ }
5296
5447
  const [pica, imageBlobReduce] = await Promise.all([
5297
5448
  import("pica").then((res) => res.default),
5298
5449
  // a wrapper for pica for better API
@@ -5310,9 +5461,6 @@ var resizeImageFile = async (file, opts) => {
5310
5461
  });
5311
5462
  };
5312
5463
  }
5313
- if (!isSupportedImageFile(file)) {
5314
- throw new Error("Error: unsupported file type", { cause: "UNSUPPORTED" });
5315
- }
5316
5464
  return new File(
5317
5465
  [await reduce.toBlob(file, { max: opts.maxWidthOrHeight, alpha: true })],
5318
5466
  file.name,
@@ -5478,6 +5626,7 @@ export {
5478
5626
  hasBackground,
5479
5627
  hasStrokeWidth,
5480
5628
  hasStrokeStyle,
5629
+ hasFreedrawMode,
5481
5630
  canHaveArrowheads,
5482
5631
  canChangeRoundness,
5483
5632
  AbortError,
@@ -5536,4 +5685,4 @@ export {
5536
5685
  createFile,
5537
5686
  normalizeFile
5538
5687
  };
5539
- //# sourceMappingURL=chunk-FXVS2QTZ.js.map
5688
+ //# sourceMappingURL=chunk-T3GRJXT6.js.map