@myoc/excalidraw 0.19.511 → 0.19.513

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 (32) hide show
  1. package/CHANGELOG.md +106 -0
  2. package/dist/dev/{chunk-WGF6T3RR.js → chunk-BI6BDZVY.js} +72 -16
  3. package/dist/dev/chunk-BI6BDZVY.js.map +7 -0
  4. package/dist/dev/{chunk-G3MPOS33.js → chunk-FW62QUKV.js} +2 -2
  5. package/dist/dev/data/{image-UBAFGYUH.js → image-WGZL7YPK.js} +3 -3
  6. package/dist/dev/index.js +999 -983
  7. package/dist/dev/index.js.map +4 -4
  8. package/dist/dev/subset-shared.chunk.js +1 -1
  9. package/dist/dev/subset-worker.chunk.js +1 -1
  10. package/dist/prod/chunk-56AUOKVR.js +4 -0
  11. package/dist/prod/{chunk-L47KOK35.js → chunk-NVT4BTJO.js} +1 -1
  12. package/dist/prod/data/image-ZQZIDAZL.js +1 -0
  13. package/dist/prod/index.js +22 -22
  14. package/dist/prod/subset-shared.chunk.js +1 -1
  15. package/dist/prod/subset-worker.chunk.js +1 -1
  16. package/dist/types/common/src/constants.d.ts +1 -0
  17. package/dist/types/excalidraw/{animated-trail.d.ts → animatedTrail.d.ts} +4 -3
  18. package/dist/types/excalidraw/components/App.d.ts +6 -8
  19. package/dist/types/excalidraw/components/SVGLayer.d.ts +1 -1
  20. package/dist/types/excalidraw/eraser/index.d.ts +2 -3
  21. package/dist/types/excalidraw/{laser-trails.d.ts → laserTrails.d.ts} +5 -7
  22. package/dist/types/excalidraw/lasso/index.d.ts +2 -3
  23. package/dist/types/excalidraw/renderer/animation.d.ts +4 -1
  24. package/dist/types/excalidraw/types.d.ts +13 -1
  25. package/dist/types/math/src/point.d.ts +1 -0
  26. package/package.json +4 -4
  27. package/dist/dev/chunk-WGF6T3RR.js.map +0 -7
  28. package/dist/prod/chunk-FDFMDTNR.js +0 -4
  29. package/dist/prod/data/image-TSPDSW4O.js +0 -1
  30. package/dist/types/excalidraw/animation-frame-handler.d.ts +0 -16
  31. /package/dist/dev/{chunk-G3MPOS33.js.map → chunk-FW62QUKV.js.map} +0 -0
  32. /package/dist/dev/data/{image-UBAFGYUH.js.map → image-WGZL7YPK.js.map} +0 -0
package/dist/dev/index.js CHANGED
@@ -57,10 +57,10 @@ import {
57
57
  saveAsJSON,
58
58
  serializeAsJSON,
59
59
  strokeRectWithRotation_simple
60
- } from "./chunk-WGF6T3RR.js";
60
+ } from "./chunk-BI6BDZVY.js";
61
61
  import {
62
62
  define_import_meta_env_default
63
- } from "./chunk-G3MPOS33.js";
63
+ } from "./chunk-FW62QUKV.js";
64
64
  import {
65
65
  en_default
66
66
  } from "./chunk-ZGRXNVW4.js";
@@ -81,264 +81,266 @@ import React42, {
81
81
  useRef as useRef31,
82
82
  useState as useState33
83
83
  } from "react";
84
- import { DEFAULT_UI_OPTIONS, isShallowEqual as isShallowEqual9 } from "@excalidraw/common";
84
+ import {
85
+ DEFAULT_IMAGE_OPTIONS,
86
+ DEFAULT_UI_OPTIONS,
87
+ isShallowEqual as isShallowEqual9
88
+ } from "@excalidraw/common";
85
89
 
86
90
  // components/App.tsx
87
91
  import clsx57 from "clsx";
88
92
  import throttle2 from "lodash.throttle";
93
+ import { nanoid } from "nanoid";
89
94
  import React40, { useContext as useContext3 } from "react";
90
95
  import { flushSync as flushSync2 } from "react-dom";
91
96
  import rough3 from "roughjs/bin/rough";
92
- import { nanoid } from "nanoid";
93
97
  import {
94
98
  clamp as clamp8,
95
- pointFrom as pointFrom34,
96
99
  pointDistance as pointDistance9,
97
- vector as vector3,
100
+ pointFrom as pointFrom34,
98
101
  pointRotateRads as pointRotateRads23,
99
- vectorFromPoint as vectorFromPoint10,
100
- vectorSubtract as vectorSubtract2,
102
+ vector as vector3,
101
103
  vectorDot,
102
- vectorNormalize as vectorNormalize5
104
+ vectorFromPoint as vectorFromPoint10,
105
+ vectorNormalize as vectorNormalize5,
106
+ vectorSubtract as vectorSubtract2
103
107
  } from "@excalidraw/math";
104
108
  import {
105
- COLOR_PALETTE as COLOR_PALETTE6,
106
- CODES as CODES11,
107
- shouldResizeFromCenter,
108
- shouldMaintainAspectRatio,
109
- shouldRotateWithDiscreteAngle as shouldRotateWithDiscreteAngle3,
110
- isArrowKey as isArrowKey2,
111
- KEYS as KEYS50,
109
+ addEventListener as addEventListener2,
112
110
  APP_NAME,
111
+ AppEventBus,
112
+ applyDarkModeFilter as applyDarkModeFilter4,
113
+ arrayToMap as arrayToMap30,
114
+ ARROW_TYPE as ARROW_TYPE2,
115
+ BIND_MODE_TIMEOUT as BIND_MODE_TIMEOUT2,
116
+ CLASSES as CLASSES10,
117
+ CODES as CODES11,
118
+ COLOR_PALETTE as COLOR_PALETTE6,
119
+ createUserAgentDescriptor,
113
120
  CURSOR_TYPE as CURSOR_TYPE4,
121
+ debounce as debounce3,
122
+ DEFAULT_COLLISION_THRESHOLD,
123
+ DEFAULT_REDUCED_GLOBAL_ALPHA as DEFAULT_REDUCED_GLOBAL_ALPHA2,
124
+ DEFAULT_TEXT_ALIGN as DEFAULT_TEXT_ALIGN2,
114
125
  DEFAULT_TRANSFORM_HANDLE_SPACING as DEFAULT_TRANSFORM_HANDLE_SPACING3,
115
- DEFAULT_MAX_IMAGE_WIDTH_OR_HEIGHT,
116
126
  DEFAULT_VERTICAL_ALIGN,
127
+ deriveStylesPanelMode as deriveStylesPanelMode2,
128
+ distance as distance2,
129
+ DOUBLE_TAP_POSITION_THRESHOLD,
117
130
  DRAGGING_THRESHOLD as DRAGGING_THRESHOLD3,
131
+ easeOut as easeOut4,
132
+ easeToValuesRAF,
118
133
  ELEMENT_SHIFT_TRANSLATE_AMOUNT,
119
134
  ELEMENT_TRANSLATE_AMOUNT,
135
+ Emitter as Emitter2,
120
136
  EVENT as EVENT10,
121
137
  FRAME_STYLE as FRAME_STYLE4,
138
+ getDateTime,
139
+ getFeatureFlag as getFeatureFlag4,
140
+ getFontString as getFontString11,
141
+ getFormFactor,
142
+ getGridPoint as getGridPoint2,
143
+ getLineHeight as getLineHeight6,
144
+ getNearestScrollableContainer,
122
145
  IMAGE_MIME_TYPES as IMAGE_MIME_TYPES2,
123
146
  IMAGE_RENDER_TIMEOUT,
147
+ invariant as invariant16,
148
+ isArrowKey as isArrowKey2,
149
+ isBrave,
150
+ isDevEnv as isDevEnv9,
151
+ isInputLike,
152
+ isIOS,
153
+ isLocalLink as isLocalLink2,
154
+ isSafari as isSafari2,
155
+ isSelectionLikeTool,
156
+ isShallowEqual as isShallowEqual8,
157
+ isTestEnv as isTestEnv5,
158
+ isToolIcon,
159
+ isTransparent as isTransparent6,
160
+ isWritableElement as isWritableElement4,
161
+ KEYS as KEYS50,
124
162
  LINE_CONFIRM_THRESHOLD as LINE_CONFIRM_THRESHOLD2,
125
- MAX_ALLOWED_FILE_BYTES,
163
+ loadDesktopUIModePreference,
164
+ matchKey as matchKey3,
126
165
  MIME_TYPES as MIME_TYPES7,
166
+ MINIMUM_ARROW_SIZE,
127
167
  MQ_RIGHT_SIDEBAR_MIN_WIDTH,
168
+ muteFSAbortError,
169
+ normalizeEOL as normalizeEOL2,
170
+ normalizeLink as normalizeLink3,
171
+ oneOf,
128
172
  POINTER_BUTTON as POINTER_BUTTON2,
173
+ POINTER_EVENTS,
174
+ randomInteger as randomInteger4,
129
175
  ROUNDNESS as ROUNDNESS7,
176
+ sceneCoordsToViewportCoords as sceneCoordsToViewportCoords7,
130
177
  SCROLL_TIMEOUT,
178
+ setDesktopUIMode,
179
+ shouldMaintainAspectRatio,
180
+ shouldResizeFromCenter,
181
+ shouldRotateWithDiscreteAngle as shouldRotateWithDiscreteAngle3,
182
+ supportsResizeObserver as supportsResizeObserver2,
131
183
  TAP_TWICE_TIMEOUT,
132
184
  TEXT_TO_CENTER_SNAP_THRESHOLD,
133
185
  THEME as THEME17,
134
- TOUCH_CTX_MENU_TIMEOUT,
135
- VERTICAL_ALIGN as VERTICAL_ALIGN5,
136
- YOUTUBE_STATES,
137
- ZOOM_STEP as ZOOM_STEP2,
138
- POINTER_EVENTS,
139
186
  TOOL_TYPE as TOOL_TYPE3,
140
- supportsResizeObserver as supportsResizeObserver2,
141
- DEFAULT_COLLISION_THRESHOLD,
142
- DEFAULT_TEXT_ALIGN as DEFAULT_TEXT_ALIGN2,
143
- ARROW_TYPE as ARROW_TYPE2,
144
- DEFAULT_REDUCED_GLOBAL_ALPHA as DEFAULT_REDUCED_GLOBAL_ALPHA2,
145
- isLocalLink as isLocalLink2,
146
- normalizeLink as normalizeLink3,
187
+ TOUCH_CTX_MENU_TIMEOUT,
147
188
  toValidURL,
148
- getGridPoint as getGridPoint2,
149
- getLineHeight as getLineHeight6,
150
- debounce as debounce3,
151
- distance as distance2,
152
- getFontString as getFontString11,
153
- getNearestScrollableContainer,
154
- isInputLike,
155
- isToolIcon,
156
- isWritableElement as isWritableElement4,
157
- sceneCoordsToViewportCoords as sceneCoordsToViewportCoords7,
158
189
  tupleToCoors,
159
- viewportCoordsToSceneCoords as viewportCoordsToSceneCoords3,
160
- wrapEvent as wrapEvent2,
161
- updateObject as updateObject2,
162
190
  updateActiveTool as updateActiveTool8,
163
- isTransparent as isTransparent6,
164
- easeToValuesRAF,
165
- muteFSAbortError,
166
- isTestEnv as isTestEnv5,
167
- isDevEnv as isDevEnv9,
168
- easeOut as easeOut4,
191
+ updateObject as updateObject2,
169
192
  updateStable,
170
- addEventListener as addEventListener2,
171
- normalizeEOL as normalizeEOL2,
172
- getDateTime,
173
- isShallowEqual as isShallowEqual8,
174
- arrayToMap as arrayToMap30,
175
- applyDarkModeFilter as applyDarkModeFilter4,
176
- AppEventBus,
177
- randomInteger as randomInteger4,
178
- CLASSES as CLASSES10,
179
- Emitter as Emitter2,
180
- MINIMUM_ARROW_SIZE,
181
- DOUBLE_TAP_POSITION_THRESHOLD,
182
- BIND_MODE_TIMEOUT as BIND_MODE_TIMEOUT2,
183
- invariant as invariant16,
184
- getFeatureFlag as getFeatureFlag4,
185
- createUserAgentDescriptor,
186
- getFormFactor,
187
- deriveStylesPanelMode as deriveStylesPanelMode2,
188
- isIOS,
189
- isBrave,
190
- isSafari as isSafari2,
191
- loadDesktopUIModePreference,
192
- setDesktopUIMode,
193
- isSelectionLikeTool,
194
- oneOf,
195
- matchKey as matchKey3
193
+ VERTICAL_ALIGN as VERTICAL_ALIGN5,
194
+ viewportCoordsToSceneCoords as viewportCoordsToSceneCoords3,
195
+ wrapEvent as wrapEvent2,
196
+ YOUTUBE_STATES,
197
+ ZOOM_STEP as ZOOM_STEP2
196
198
  } from "@excalidraw/common";
197
199
  import {
198
- getObservedAppState,
199
- getCommonBounds as getCommonBounds11,
200
- getElementAbsoluteCoords as getElementAbsoluteCoords8,
200
+ updateImageCache as _updateImageCache,
201
+ addElementsToFrame as addElementsToFrame2,
202
+ bindOrUnbindBindingElement as bindOrUnbindBindingElement2,
201
203
  bindOrUnbindBindingElements as bindOrUnbindBindingElements2,
202
- fixBindingsAfterDeletion as fixBindingsAfterDeletion2,
203
- getHoveredElementForBinding as getHoveredElementForBinding2,
204
- isBindingEnabled as isBindingEnabled2,
205
- updateBoundElements as updateBoundElements4,
206
- newElementWith as newElementWith10,
207
- newFrameElement as newFrameElement2,
208
- newFreeDrawElement,
209
- newEmbeddableElement,
210
- newMagicFrameElement,
211
- newIframeElement,
212
- newArrowElement as newArrowElement2,
213
- newElement as newElement6,
214
- newImageElement,
215
- newLinearElement as newLinearElement5,
216
- newTextElement as newTextElement5,
217
- refreshTextDimensions,
204
+ calculateFixedPointForNonElbowArrowBinding as calculateFixedPointForNonElbowArrowBinding2,
205
+ CaptureUpdateAction as CaptureUpdateAction41,
206
+ convertToExcalidrawElements,
207
+ createSrcDoc,
208
+ cropElement,
218
209
  deepCopyElement as deepCopyElement4,
210
+ doBoundsIntersect as doBoundsIntersect4,
211
+ dragNewElement,
212
+ dragSelectedElements,
219
213
  duplicateElements as duplicateElements2,
214
+ editGroupForSelectedElement,
215
+ elementOverlapsWithFrame as elementOverlapsWithFrame2,
216
+ embeddableURLValidator as embeddableURLValidator2,
217
+ excludeElementsInFramesFromSelection,
218
+ filterElementsEligibleAsFrameChildren,
219
+ fixBindingsAfterDeletion as fixBindingsAfterDeletion2,
220
+ FlowChartCreator,
221
+ FlowChartNavigator,
222
+ getActiveTextElement as getActiveTextElement2,
223
+ getApproxMinLineHeight,
224
+ getApproxMinLineWidth as getApproxMinLineWidth2,
225
+ getBoundTextElement as getBoundTextElement15,
226
+ getCommonBounds as getCommonBounds11,
227
+ getCommonFrameId as getCommonFrameId2,
228
+ getContainerCenter,
229
+ getContainerElement as getContainerElement5,
230
+ getContainingFrame as getContainingFrame3,
231
+ getCornerRadius as getCornerRadius2,
232
+ getCursorForResizingElement,
233
+ getDragOffsetXY,
234
+ getElementAbsoluteCoords as getElementAbsoluteCoords8,
235
+ getElementBounds as getElementBounds5,
236
+ getElementsInGroup as getElementsInGroup10,
237
+ getElementsInNewFrame,
238
+ getElementsInResizingFrame as getElementsInResizingFrame4,
239
+ getElementsOverlappingFrame as getElementsOverlappingFrame2,
240
+ getElementWithTransformHandleType,
241
+ getEmbedLink as getEmbedLink2,
242
+ getFrameChildren as getFrameChildren6,
243
+ getFrameChildrenInsertionIndex as getFrameChildrenInsertionIndex2,
244
+ getFrameLikeTitle,
245
+ getHoveredElementForBinding as getHoveredElementForBinding2,
246
+ getInitializedImageElements,
247
+ getLineHeightInPx as getLineHeightInPx3,
248
+ getLinkDirectionFromKey,
249
+ getMinTextElementWidth,
250
+ getNormalizedDimensions,
251
+ getObservedAppState,
252
+ getRenderOpacity,
253
+ getResizeArrowDirection,
254
+ getResizeOffsetXY,
255
+ getSelectedGroupIdForElement,
256
+ getSelectedGroupIds as getSelectedGroupIds4,
257
+ getSelectionStateForElements as getSelectionStateForElements2,
258
+ getSnapOutlineMidPoint as getSnapOutlineMidPoint2,
259
+ getTransformHandleTypeFromCoords,
260
+ getUncroppedWidthAndHeight as getUncroppedWidthAndHeight4,
261
+ getVisibleSceneBounds,
262
+ handleFocusPointDrag,
263
+ handleFocusPointHover,
264
+ handleFocusPointPointerDown,
265
+ handleFocusPointPointerUp,
266
+ hasBoundingBox as hasBoundingBox2,
220
267
  hasBoundTextElement as hasBoundTextElement9,
268
+ hitElementBoundingBox as hitElementBoundingBox2,
269
+ hitElementBoundingBoxOnly,
270
+ hitElementBoundText,
271
+ hitElementItself as hitElementItself3,
221
272
  isArrowElement as isArrowElement14,
273
+ isBindableElement as isBindableElement3,
222
274
  isBindingElement as isBindingElement4,
223
275
  isBindingElementType,
276
+ isBindingEnabled as isBindingEnabled2,
224
277
  isBoundToContainer as isBoundToContainer9,
278
+ isCursorInFrame,
279
+ isElbowArrow as isElbowArrow10,
280
+ isElementCompletelyInViewport as isElementCompletelyInViewport2,
281
+ isElementInFrame,
282
+ isElementInGroup as isElementInGroup2,
283
+ isElementInViewport as isElementInViewport3,
284
+ isElementLink as isElementLink2,
285
+ isEligibleFrameChildType,
286
+ isEmbeddableElement as isEmbeddableElement4,
287
+ isFlowchartNodeElement as isFlowchartNodeElement2,
225
288
  isFrameLikeElement as isFrameLikeElement15,
289
+ isIframeElement as isIframeElement2,
290
+ isIframeLikeElement as isIframeLikeElement2,
226
291
  isImageElement as isImageElement9,
227
- isEmbeddableElement as isEmbeddableElement4,
228
292
  isInitializedImageElement as isInitializedImageElement3,
293
+ isInvisiblySmallElement as isInvisiblySmallElement3,
229
294
  isLinearElement as isLinearElement12,
230
295
  isLinearElementType as isLinearElementType2,
231
- isUsingAdaptiveRadius as isUsingAdaptiveRadius4,
232
- isIframeElement as isIframeElement2,
233
- isIframeLikeElement as isIframeLikeElement2,
296
+ isLineElement as isLineElement8,
234
297
  isMagicFrameElement as isMagicFrameElement2,
298
+ isMeasureTextSupported,
299
+ isNonDeletedElement,
300
+ isPathALoop as isPathALoop3,
301
+ isPointInElement as isPointInElement3,
302
+ isSelectedViaGroup as isSelectedViaGroup2,
303
+ isSimpleArrow,
235
304
  isTextBindableContainer as isTextBindableContainer3,
236
- isElbowArrow as isElbowArrow10,
237
- isFlowchartNodeElement as isFlowchartNodeElement2,
238
- isBindableElement as isBindableElement3,
239
305
  isTextElement as isTextElement19,
240
- getNormalizedDimensions,
241
- isElementCompletelyInViewport as isElementCompletelyInViewport2,
242
- isElementInViewport as isElementInViewport3,
243
- isInvisiblySmallElement as isInvisiblySmallElement3,
244
- getCornerRadius as getCornerRadius2,
245
- isPathALoop as isPathALoop3,
246
- createSrcDoc,
247
- embeddableURLValidator as embeddableURLValidator2,
306
+ isUsingAdaptiveRadius as isUsingAdaptiveRadius4,
307
+ isValidTextContainer,
308
+ makeNextSelectedElementIds as makeNextSelectedElementIds3,
309
+ maxBindingDistance_simple as maxBindingDistance_simple3,
310
+ maybeHandleArrowPointlikeDrag,
248
311
  maybeParseEmbedSrc,
249
- getEmbedLink as getEmbedLink2,
250
- getInitializedImageElements,
312
+ measureText as measureText8,
313
+ mutateElement as mutateElement6,
314
+ newArrowElement as newArrowElement2,
315
+ newElement as newElement6,
316
+ newElementWith as newElementWith10,
317
+ newEmbeddableElement,
318
+ newFrameElement as newFrameElement2,
319
+ newFreeDrawElement,
320
+ newIframeElement,
321
+ newImageElement,
322
+ newLinearElement as newLinearElement5,
323
+ newMagicFrameElement,
324
+ newTextElement as newTextElement5,
251
325
  normalizeSVG,
252
- updateImageCache as _updateImageCache,
253
- getBoundTextElement as getBoundTextElement15,
254
- getContainerCenter,
255
- getContainerElement as getContainerElement5,
256
- isValidTextContainer,
326
+ normalizeText as normalizeText2,
327
+ parseElementLinkFromURL,
328
+ positionElementsOnGrid,
257
329
  redrawTextBoundingBox as redrawTextBoundingBox8,
258
- hasBoundingBox as hasBoundingBox2,
259
- getCommonFrameId as getCommonFrameId2,
260
- getFrameChildren as getFrameChildren6,
261
- getFrameChildrenInsertionIndex as getFrameChildrenInsertionIndex2,
262
- isCursorInFrame,
263
- addElementsToFrame as addElementsToFrame2,
264
- replaceAllElementsInFrame as replaceAllElementsInFrame4,
330
+ refreshTextDimensions,
265
331
  removeElementsFromFrame as removeElementsFromFrame2,
266
- getElementsInResizingFrame as getElementsInResizingFrame4,
267
- getElementsInNewFrame,
268
- getContainingFrame as getContainingFrame3,
269
- elementOverlapsWithFrame as elementOverlapsWithFrame2,
270
- updateFrameMembershipOfSelectedElements as updateFrameMembershipOfSelectedElements6,
271
- isElementInFrame,
272
- getFrameLikeTitle,
273
- getElementsOverlappingFrame as getElementsOverlappingFrame2,
274
- filterElementsEligibleAsFrameChildren,
275
- hitElementBoundText,
276
- hitElementBoundingBoxOnly,
277
- hitElementItself as hitElementItself3,
278
- getVisibleSceneBounds,
279
- FlowChartCreator,
280
- FlowChartNavigator,
281
- getLinkDirectionFromKey,
282
- cropElement,
283
- wrapText as wrapText5,
284
- isElementLink as isElementLink2,
285
- parseElementLinkFromURL,
286
- isMeasureTextSupported,
287
- normalizeText as normalizeText2,
288
- measureText as measureText8,
289
- getLineHeightInPx as getLineHeightInPx3,
290
- getApproxMinLineWidth as getApproxMinLineWidth2,
291
- getApproxMinLineHeight,
292
- getMinTextElementWidth,
293
- ShapeCache as ShapeCache4,
294
- getRenderOpacity,
295
- editGroupForSelectedElement,
296
- getElementsInGroup as getElementsInGroup10,
297
- getSelectedGroupIdForElement,
298
- getSelectedGroupIds as getSelectedGroupIds4,
299
- isElementInGroup as isElementInGroup2,
300
- isSelectedViaGroup as isSelectedViaGroup2,
332
+ replaceAllElementsInFrame as replaceAllElementsInFrame4,
333
+ Scene,
301
334
  selectGroupsForSelectedElements as selectGroupsForSelectedElements7,
335
+ ShapeCache as ShapeCache4,
336
+ Store,
337
+ StoreDelta as StoreDelta2,
302
338
  syncInvalidIndices,
303
339
  syncMovedIndices as syncMovedIndices5,
304
- excludeElementsInFramesFromSelection,
305
- getSelectionStateForElements as getSelectionStateForElements2,
306
- makeNextSelectedElementIds as makeNextSelectedElementIds3,
307
- getResizeOffsetXY,
308
- getResizeArrowDirection,
309
340
  transformElements,
310
- getCursorForResizingElement,
311
- getElementWithTransformHandleType,
312
- getTransformHandleTypeFromCoords,
313
- dragNewElement,
314
- dragSelectedElements,
315
- getDragOffsetXY,
316
- isNonDeletedElement,
317
- Scene,
318
- Store,
319
- CaptureUpdateAction as CaptureUpdateAction41,
320
- hitElementBoundingBox as hitElementBoundingBox2,
321
- isLineElement as isLineElement8,
322
- isSimpleArrow,
323
- StoreDelta as StoreDelta2,
324
- positionElementsOnGrid,
325
- calculateFixedPointForNonElbowArrowBinding as calculateFixedPointForNonElbowArrowBinding2,
326
- bindOrUnbindBindingElement as bindOrUnbindBindingElement2,
327
- mutateElement as mutateElement6,
328
- getElementBounds as getElementBounds5,
329
- doBoundsIntersect as doBoundsIntersect4,
330
- isPointInElement as isPointInElement3,
331
- maxBindingDistance_simple as maxBindingDistance_simple3,
332
- convertToExcalidrawElements,
333
- getSnapOutlineMidPoint as getSnapOutlineMidPoint2,
334
- handleFocusPointDrag,
335
- handleFocusPointHover,
336
- handleFocusPointPointerDown,
337
- handleFocusPointPointerUp,
338
- maybeHandleArrowPointlikeDrag,
339
- getUncroppedWidthAndHeight as getUncroppedWidthAndHeight4,
340
- getActiveTextElement as getActiveTextElement2,
341
- isEligibleFrameChildType
341
+ updateBoundElements as updateBoundElements4,
342
+ updateFrameMembershipOfSelectedElements as updateFrameMembershipOfSelectedElements6,
343
+ wrapText as wrapText5
342
344
  } from "@excalidraw/element";
343
345
  import { LinearElementEditor as LinearElementEditor11 } from "@excalidraw/element/linearElementEditor";
344
346
  import { findShapeByKey } from "@excalidraw/element/shapes";
@@ -9609,7 +9611,7 @@ var exportCanvas = async (type, elements, appState, files, {
9609
9611
  let blob = canvasToBlob(tempCanvas);
9610
9612
  if (appState.exportEmbedScene) {
9611
9613
  blob = blob.then(
9612
- (blob2) => import("./data/image-UBAFGYUH.js").then(
9614
+ (blob2) => import("./data/image-WGZL7YPK.js").then(
9613
9615
  ({ encodePngMetadata: encodePngMetadata2 }) => encodePngMetadata2({
9614
9616
  blob: blob2,
9615
9617
  metadata: serializeAsJSON(elements, appState, files, "local")
@@ -15012,74 +15014,668 @@ var ActionManager = class {
15012
15014
  }
15013
15015
  };
15014
15016
 
15015
- // animation-frame-handler.ts
15016
- var AnimationFrameHandler = class {
15017
- constructor() {
15018
- __publicField(this, "targets", /* @__PURE__ */ new WeakMap());
15019
- __publicField(this, "rafIds", /* @__PURE__ */ new WeakMap());
15017
+ // gesture.ts
15018
+ var getCenter = (pointers) => {
15019
+ const allCoords = Array.from(pointers.values());
15020
+ return {
15021
+ x: sum(allCoords, (coords) => coords.x) / allCoords.length,
15022
+ y: sum(allCoords, (coords) => coords.y) / allCoords.length
15023
+ };
15024
+ };
15025
+ var getDistance = ([a, b]) => Math.hypot(a.x - b.x, a.y - b.y);
15026
+ var sum = (array, mapper) => array.reduce((acc, item) => acc + mapper(item), 0);
15027
+
15028
+ // components/ElementCanvasButtons.tsx
15029
+ import { sceneCoordsToViewportCoords as sceneCoordsToViewportCoords2 } from "@excalidraw/common";
15030
+ import { getElementAbsoluteCoords as getElementAbsoluteCoords4 } from "@excalidraw/element";
15031
+ import { jsx as jsx57 } from "react/jsx-runtime";
15032
+ var CONTAINER_PADDING = 5;
15033
+ var getContainerCoords2 = (element, appState, elementsMap) => {
15034
+ const [x1, y1] = getElementAbsoluteCoords4(element, elementsMap);
15035
+ const { x: viewportX, y: viewportY } = sceneCoordsToViewportCoords2(
15036
+ { sceneX: x1 + element.width, sceneY: y1 },
15037
+ appState
15038
+ );
15039
+ const x = viewportX - appState.offsetLeft + 10;
15040
+ const y = viewportY - appState.offsetTop;
15041
+ return { x, y };
15042
+ };
15043
+ var ElementCanvasButtons = ({
15044
+ children,
15045
+ element,
15046
+ elementsMap
15047
+ }) => {
15048
+ const appState = useExcalidrawAppState();
15049
+ if (appState.contextMenu || appState.newElement || appState.resizingElement || appState.isRotating || appState.openMenu || appState.viewModeEnabled) {
15050
+ return null;
15020
15051
  }
15021
- register(key, callback) {
15022
- this.targets.set(key, { callback, stopped: true });
15052
+ const { x, y } = getContainerCoords2(element, appState, elementsMap);
15053
+ return /* @__PURE__ */ jsx57(
15054
+ "div",
15055
+ {
15056
+ className: "excalidraw-canvas-buttons",
15057
+ style: {
15058
+ top: `${y}px`,
15059
+ left: `${x}px`,
15060
+ // width: CONTAINER_WIDTH,
15061
+ padding: CONTAINER_PADDING
15062
+ },
15063
+ children
15064
+ }
15065
+ );
15066
+ };
15067
+
15068
+ // laserTrails.ts
15069
+ import { DEFAULT_LASER_COLOR, easeOut } from "@excalidraw/common";
15070
+
15071
+ // animatedTrail.ts
15072
+ import { LaserPointer } from "@excalidraw/laser-pointer";
15073
+ import {
15074
+ SVG_NS,
15075
+ getSvgPathFromStroke as getSvgPathFromStroke2,
15076
+ sceneCoordsToViewportCoords as sceneCoordsToViewportCoords3
15077
+ } from "@excalidraw/common";
15078
+
15079
+ // reactUtils.ts
15080
+ import { version as ReactVersion } from "react";
15081
+ import { unstable_batchedUpdates } from "react-dom";
15082
+ import { throttleRAF } from "@excalidraw/common";
15083
+ var withBatchedUpdates = (func) => (event) => {
15084
+ unstable_batchedUpdates(func, event);
15085
+ };
15086
+ var withBatchedUpdatesThrottled = (func) => {
15087
+ return throttleRAF((event) => {
15088
+ unstable_batchedUpdates(func, event);
15089
+ });
15090
+ };
15091
+ var isRenderThrottlingEnabled = (() => {
15092
+ let IS_REACT_18_AND_UP;
15093
+ try {
15094
+ const version = ReactVersion.split(".");
15095
+ IS_REACT_18_AND_UP = Number(version[0]) > 17;
15096
+ } catch {
15097
+ IS_REACT_18_AND_UP = false;
15023
15098
  }
15024
- start(key) {
15025
- const target = this.targets.get(key);
15026
- if (!target) {
15099
+ let hasWarned = false;
15100
+ return () => {
15101
+ if (window.EXCALIDRAW_THROTTLE_RENDER === true) {
15102
+ if (!IS_REACT_18_AND_UP) {
15103
+ if (!hasWarned) {
15104
+ hasWarned = true;
15105
+ console.warn(
15106
+ "Excalidraw: render throttling is disabled on React versions < 18."
15107
+ );
15108
+ }
15109
+ return false;
15110
+ }
15111
+ return true;
15112
+ }
15113
+ return false;
15114
+ };
15115
+ })();
15116
+
15117
+ // renderer/animation.ts
15118
+ var _AnimationController = class _AnimationController {
15119
+ static start(key, animation) {
15120
+ if (_AnimationController.animations.has(key)) {
15027
15121
  return;
15028
15122
  }
15029
- if (this.rafIds.has(key)) {
15123
+ const initialState = animation({
15124
+ deltaTime: 0,
15125
+ state: void 0
15126
+ });
15127
+ if (initialState) {
15128
+ _AnimationController.animations.set(key, {
15129
+ animation,
15130
+ lastTime: 0,
15131
+ state: initialState
15132
+ });
15133
+ _AnimationController.scheduleNextFrame();
15134
+ }
15135
+ }
15136
+ static scheduleNextFrame() {
15137
+ if (_AnimationController.scheduledFrame) {
15030
15138
  return;
15031
15139
  }
15032
- this.targets.set(key, { ...target, stopped: false });
15033
- this.scheduleFrame(key);
15140
+ if (isRenderThrottlingEnabled()) {
15141
+ _AnimationController.scheduledFrame = {
15142
+ id: requestAnimationFrame(_AnimationController.tick),
15143
+ type: "raf"
15144
+ };
15145
+ } else {
15146
+ _AnimationController.scheduledFrame = {
15147
+ id: setTimeout(_AnimationController.tick, 0),
15148
+ type: "timeout"
15149
+ };
15150
+ }
15151
+ }
15152
+ static cancelScheduledFrame() {
15153
+ if (!_AnimationController.scheduledFrame) {
15154
+ return;
15155
+ }
15156
+ if (_AnimationController.scheduledFrame.type === "raf") {
15157
+ cancelAnimationFrame(_AnimationController.scheduledFrame.id);
15158
+ } else {
15159
+ clearTimeout(_AnimationController.scheduledFrame.id);
15160
+ }
15161
+ _AnimationController.scheduledFrame = null;
15034
15162
  }
15035
- stop(key) {
15036
- const target = this.targets.get(key);
15037
- if (target && !target.stopped) {
15038
- this.targets.set(key, { ...target, stopped: true });
15163
+ static cancelScheduledFrameIfIdle() {
15164
+ if (_AnimationController.animations.size > 0) {
15165
+ return false;
15039
15166
  }
15040
- this.cancelFrame(key);
15167
+ _AnimationController.cancelScheduledFrame();
15168
+ return true;
15041
15169
  }
15042
- constructFrame(key) {
15043
- return (timestamp) => {
15044
- const target = this.targets.get(key);
15045
- if (!target) {
15170
+ static tick() {
15171
+ _AnimationController.scheduledFrame = null;
15172
+ if (_AnimationController.animations.size > 0) {
15173
+ for (const [key, animation] of _AnimationController.animations) {
15174
+ const now = performance.now();
15175
+ const deltaTime = animation.lastTime === 0 ? 0 : now - animation.lastTime;
15176
+ const state = animation.animation({
15177
+ deltaTime,
15178
+ state: animation.state
15179
+ });
15180
+ if (!state) {
15181
+ _AnimationController.animations.delete(key);
15182
+ if (_AnimationController.cancelScheduledFrameIfIdle()) {
15183
+ return;
15184
+ }
15185
+ } else {
15186
+ animation.lastTime = now;
15187
+ animation.state = state;
15188
+ }
15189
+ }
15190
+ if (_AnimationController.cancelScheduledFrameIfIdle()) {
15046
15191
  return;
15047
15192
  }
15048
- const shouldAbort = this.onFrame(target, timestamp);
15049
- if (!target.stopped && !shouldAbort) {
15050
- this.scheduleFrame(key);
15051
- } else {
15052
- this.cancelFrame(key);
15193
+ _AnimationController.scheduleNextFrame();
15194
+ }
15195
+ }
15196
+ static running(key) {
15197
+ return _AnimationController.animations.has(key);
15198
+ }
15199
+ static cancel(key) {
15200
+ _AnimationController.animations.delete(key);
15201
+ _AnimationController.cancelScheduledFrameIfIdle();
15202
+ }
15203
+ };
15204
+ __publicField(_AnimationController, "scheduledFrame", null);
15205
+ __publicField(_AnimationController, "animations", /* @__PURE__ */ new Map());
15206
+ var AnimationController = _AnimationController;
15207
+
15208
+ // animatedTrail.ts
15209
+ var _AnimatedTrail = class _AnimatedTrail {
15210
+ constructor(app, options) {
15211
+ this.app = app;
15212
+ this.options = options;
15213
+ __publicField(this, "currentTrail");
15214
+ __publicField(this, "pastTrails", []);
15215
+ __publicField(this, "container");
15216
+ __publicField(this, "trailElement");
15217
+ __publicField(this, "trailAnimation");
15218
+ __publicField(this, "key");
15219
+ this.key = `animated-trail-${_AnimatedTrail.counter++}`;
15220
+ this.trailElement = document.createElementNS(SVG_NS, "path");
15221
+ if (this.options.animateTrail) {
15222
+ this.trailAnimation = document.createElementNS(SVG_NS, "animate");
15223
+ this.trailAnimation.setAttribute("attributeName", "stroke-dashoffset");
15224
+ this.trailElement.setAttribute("stroke-dasharray", "7 7");
15225
+ this.trailElement.setAttribute("stroke-dashoffset", "10");
15226
+ this.trailAnimation.setAttribute("from", "0");
15227
+ this.trailAnimation.setAttribute("to", `-14`);
15228
+ this.trailAnimation.setAttribute("dur", "0.3s");
15229
+ this.trailElement.appendChild(this.trailAnimation);
15230
+ }
15231
+ }
15232
+ get hasCurrentTrail() {
15233
+ return !!this.currentTrail;
15234
+ }
15235
+ hasLastPoint(x, y) {
15236
+ if (this.currentTrail) {
15237
+ const len = this.currentTrail.originalPoints.length;
15238
+ return this.currentTrail.originalPoints[len - 1][0] === x && this.currentTrail.originalPoints[len - 1][1] === y;
15239
+ }
15240
+ return false;
15241
+ }
15242
+ cleanup() {
15243
+ this.pastTrails = [];
15244
+ this.currentTrail = void 0;
15245
+ if (this.trailElement.parentNode === this.container) {
15246
+ this.container?.removeChild(this.trailElement);
15247
+ }
15248
+ }
15249
+ start(container) {
15250
+ if (container) {
15251
+ this.container = container;
15252
+ }
15253
+ if (this.trailElement.parentNode !== this.container && this.container) {
15254
+ this.container.appendChild(this.trailElement);
15255
+ }
15256
+ if (!AnimationController.running(this.key)) {
15257
+ AnimationController.start(this.key, () => {
15258
+ const needsNext = this.onFrame();
15259
+ if (needsNext) {
15260
+ return { keep: true };
15261
+ }
15262
+ this.cleanup();
15263
+ return null;
15264
+ });
15265
+ }
15266
+ }
15267
+ stop() {
15268
+ AnimationController.cancel(this.key);
15269
+ this.cleanup();
15270
+ }
15271
+ startPath(x, y) {
15272
+ this.currentTrail = new LaserPointer(this.options);
15273
+ this.currentTrail.addPoint([x, y, performance.now()]);
15274
+ this.update();
15275
+ }
15276
+ addPointToPath(x, y) {
15277
+ if (this.currentTrail) {
15278
+ this.currentTrail.addPoint([x, y, performance.now()]);
15279
+ this.update();
15280
+ }
15281
+ }
15282
+ endPath() {
15283
+ if (this.currentTrail) {
15284
+ this.currentTrail.close();
15285
+ this.currentTrail.options.keepHead = false;
15286
+ this.pastTrails.push(this.currentTrail);
15287
+ this.currentTrail = void 0;
15288
+ this.update();
15289
+ }
15290
+ }
15291
+ getCurrentTrail() {
15292
+ return this.currentTrail;
15293
+ }
15294
+ clearTrails() {
15295
+ this.pastTrails = [];
15296
+ this.currentTrail = void 0;
15297
+ this.update();
15298
+ }
15299
+ update() {
15300
+ this.start();
15301
+ if (this.trailAnimation) {
15302
+ this.trailAnimation.setAttribute("begin", "indefinite");
15303
+ this.trailAnimation.setAttribute("repeatCount", "indefinite");
15304
+ }
15305
+ }
15306
+ onFrame() {
15307
+ const paths = [];
15308
+ for (const trail of this.pastTrails) {
15309
+ paths.push(this.drawTrail(trail, this.app.state));
15310
+ }
15311
+ if (this.currentTrail) {
15312
+ const currentPath = this.drawTrail(this.currentTrail, this.app.state);
15313
+ paths.push(currentPath);
15314
+ }
15315
+ this.pastTrails = this.pastTrails.filter(
15316
+ (t2) => t2.getStrokeOutline(t2.options.size / this.app.state.zoom.value).length !== 0
15317
+ );
15318
+ if (paths.length === 0) {
15319
+ this.trailElement.setAttribute("d", "");
15320
+ return false;
15321
+ }
15322
+ const svgPaths = paths.join(" ").trim();
15323
+ this.trailElement.setAttribute("d", svgPaths);
15324
+ if (this.trailAnimation) {
15325
+ this.trailElement.setAttribute(
15326
+ "fill",
15327
+ (this.options.fill ?? (() => "black"))(this)
15328
+ );
15329
+ this.trailElement.setAttribute(
15330
+ "stroke",
15331
+ (this.options.stroke ?? (() => "black"))(this)
15332
+ );
15333
+ } else {
15334
+ this.trailElement.setAttribute(
15335
+ "fill",
15336
+ (this.options.fill ?? (() => "black"))(this)
15337
+ );
15338
+ }
15339
+ return true;
15340
+ }
15341
+ drawTrail(trail, state) {
15342
+ const _stroke = trail.getStrokeOutline(trail.options.size / state.zoom.value).map(([x, y]) => {
15343
+ const result = sceneCoordsToViewportCoords3(
15344
+ { sceneX: x, sceneY: y },
15345
+ state
15346
+ );
15347
+ return [result.x, result.y];
15348
+ });
15349
+ const stroke = this.trailAnimation ? _stroke.slice(0, _stroke.length / 2) : _stroke;
15350
+ return getSvgPathFromStroke2(stroke, true);
15351
+ }
15352
+ };
15353
+ __publicField(_AnimatedTrail, "counter", 0);
15354
+ var AnimatedTrail = _AnimatedTrail;
15355
+
15356
+ // laserTrails.ts
15357
+ var LaserTrails = class {
15358
+ constructor(app) {
15359
+ this.app = app;
15360
+ __publicField(this, "localTrail");
15361
+ __publicField(this, "collabTrails", /* @__PURE__ */ new Map());
15362
+ __publicField(this, "container");
15363
+ this.localTrail = new AnimatedTrail(app, {
15364
+ ...this.getTrailOptions(),
15365
+ fill: () => DEFAULT_LASER_COLOR
15366
+ });
15367
+ }
15368
+ getTrailOptions() {
15369
+ return {
15370
+ simplify: 0,
15371
+ streamline: 0.4,
15372
+ sizeMapping: (c) => {
15373
+ const DECAY_TIME = 1e3;
15374
+ const DECAY_LENGTH = 50;
15375
+ const t2 = Math.max(
15376
+ 0,
15377
+ 1 - (performance.now() - c.pressure) / DECAY_TIME
15378
+ );
15379
+ const l = (DECAY_LENGTH - Math.min(DECAY_LENGTH, c.totalLength - c.currentIndex)) / DECAY_LENGTH;
15380
+ return Math.min(easeOut(l), easeOut(t2));
15053
15381
  }
15054
15382
  };
15055
15383
  }
15056
- scheduleFrame(key) {
15057
- const rafId = requestAnimationFrame(this.constructFrame(key));
15058
- this.rafIds.set(key, rafId);
15384
+ startPath(x, y) {
15385
+ this.localTrail.startPath(x, y);
15386
+ }
15387
+ addPointToPath(x, y) {
15388
+ this.localTrail.addPointToPath(x, y);
15389
+ }
15390
+ endPath() {
15391
+ this.localTrail.endPath();
15392
+ }
15393
+ start(container) {
15394
+ this.container = container;
15395
+ this.localTrail.start(container);
15396
+ }
15397
+ stop() {
15398
+ this.localTrail.stop();
15399
+ this.stopCollabTrails();
15400
+ this.container = void 0;
15059
15401
  }
15060
- cancelFrame(key) {
15061
- if (this.rafIds.has(key)) {
15062
- const rafId = this.rafIds.get(key);
15063
- cancelAnimationFrame(rafId);
15402
+ stopCollabTrails(collaborators) {
15403
+ for (const [key, trail] of this.collabTrails) {
15404
+ const collaborator = collaborators?.get(key);
15405
+ if (!collaborator) {
15406
+ trail.stop();
15407
+ this.collabTrails.delete(key);
15408
+ }
15064
15409
  }
15065
- this.rafIds.delete(key);
15066
15410
  }
15067
- onFrame(target, timestamp) {
15068
- const shouldAbort = target.callback(timestamp);
15069
- return shouldAbort ?? false;
15411
+ updateCollabTrails(collaborators) {
15412
+ this.stopCollabTrails(collaborators);
15413
+ if (!this.container || collaborators.size === 0) {
15414
+ return;
15415
+ }
15416
+ for (const [key, collaborator] of collaborators.entries()) {
15417
+ if (collaborator.isCurrentUser) {
15418
+ continue;
15419
+ }
15420
+ let trail = this.collabTrails.get(key);
15421
+ if (!trail) {
15422
+ trail = new AnimatedTrail(this.app, {
15423
+ ...this.getTrailOptions(),
15424
+ fill: () => collaborator.pointer?.laserColor || getClientColor(key, collaborator)
15425
+ });
15426
+ trail.start(this.container);
15427
+ this.collabTrails.set(key, trail);
15428
+ }
15429
+ if (collaborator.pointer && collaborator.pointer.tool === "laser") {
15430
+ const buttonDown = collaborator.button === "down";
15431
+ const buttonUp = collaborator.button === "up";
15432
+ const hasTrail = trail.hasCurrentTrail;
15433
+ if (buttonDown && !hasTrail) {
15434
+ trail.startPath(collaborator.pointer.x, collaborator.pointer.y);
15435
+ }
15436
+ const lastPointOriginal = !trail.hasLastPoint(
15437
+ collaborator.pointer.x,
15438
+ collaborator.pointer.y
15439
+ );
15440
+ if (buttonDown && lastPointOriginal) {
15441
+ trail.addPointToPath(collaborator.pointer.x, collaborator.pointer.y);
15442
+ }
15443
+ if (buttonUp && hasTrail) {
15444
+ trail.addPointToPath(collaborator.pointer.x, collaborator.pointer.y);
15445
+ trail.endPath();
15446
+ }
15447
+ }
15448
+ }
15070
15449
  }
15071
15450
  };
15072
15451
 
15073
- // gesture.ts
15074
- var getCenter = (pointers) => {
15075
- const allCoords = Array.from(pointers.values());
15452
+ // scene/Renderer.ts
15453
+ import {
15454
+ getCommonFrameId,
15455
+ getFrameChildrenInsertionIndex,
15456
+ isElementInViewport as isElementInViewport2
15457
+ } from "@excalidraw/element";
15458
+ import { arrayToMap as arrayToMap24, memoize, toBrandedType } from "@excalidraw/common";
15459
+ var Renderer = class {
15460
+ constructor(scene) {
15461
+ __publicField(this, "scene");
15462
+ __publicField(this, "_getRenderableElements", memoize(
15463
+ ({
15464
+ canvasNonce,
15465
+ zoom,
15466
+ offsetLeft,
15467
+ offsetTop,
15468
+ scrollX,
15469
+ scrollY,
15470
+ height,
15471
+ width,
15472
+ editingTextElement,
15473
+ newElement: newElement7
15474
+ }) => {
15475
+ const elements = this.scene.getNonDeletedElements();
15476
+ const { elementsMap, newElementCanvasElement } = this.getRenderableElementsMap({
15477
+ elements,
15478
+ editingTextElement,
15479
+ newElement: newElement7
15480
+ });
15481
+ const visibleElements = this.getVisibleCanvasElements({
15482
+ elementsMap,
15483
+ zoom,
15484
+ offsetLeft,
15485
+ offsetTop,
15486
+ scrollX,
15487
+ scrollY,
15488
+ height,
15489
+ width
15490
+ });
15491
+ return {
15492
+ elementsMap,
15493
+ visibleElements,
15494
+ newElementCanvasElement,
15495
+ canvasNonce
15496
+ };
15497
+ }
15498
+ ));
15499
+ __publicField(this, "getRenderableElements", (opts) => {
15500
+ const { newElement: newElement7 } = opts;
15501
+ const canvasNonce = `${this.scene.getSceneNonce()}${newElement7?.frameId ? `:${newElement7.versionNonce}` : ""}`;
15502
+ const ret = this._getRenderableElements({
15503
+ canvasNonce,
15504
+ // don't spread `opts` because we don't want to memoize on some props
15505
+ zoom: opts.zoom,
15506
+ offsetLeft: opts.offsetLeft,
15507
+ offsetTop: opts.offsetTop,
15508
+ scrollX: opts.scrollX,
15509
+ scrollY: opts.scrollY,
15510
+ height: opts.height,
15511
+ width: opts.width,
15512
+ editingTextElement: opts.editingTextElement,
15513
+ newElement: opts.newElement
15514
+ });
15515
+ if (opts.frameToHighlight && opts.selectedElementsAreBeingDragged && // if all dragged elements are already in the frame, don't reorder
15516
+ getCommonFrameId(opts.selectedElements) !== opts.frameToHighlight.id) {
15517
+ const reorderedVisibleElements = this.sortSelectedElementsIntoHighlightedFrame({
15518
+ visibleElements: ret.visibleElements,
15519
+ selectedElements: opts.selectedElements,
15520
+ frameToHighlight: opts.frameToHighlight
15521
+ });
15522
+ return {
15523
+ ...ret,
15524
+ visibleElements: reorderedVisibleElements
15525
+ };
15526
+ }
15527
+ return ret;
15528
+ });
15529
+ this.scene = scene;
15530
+ }
15531
+ getVisibleCanvasElements({
15532
+ elementsMap,
15533
+ zoom,
15534
+ offsetLeft,
15535
+ offsetTop,
15536
+ scrollX,
15537
+ scrollY,
15538
+ height,
15539
+ width
15540
+ }) {
15541
+ const visibleElements = [];
15542
+ for (const element of elementsMap.values()) {
15543
+ if (isElementInViewport2(
15544
+ element,
15545
+ width,
15546
+ height,
15547
+ {
15548
+ zoom,
15549
+ offsetLeft,
15550
+ offsetTop,
15551
+ scrollX,
15552
+ scrollY
15553
+ },
15554
+ elementsMap
15555
+ )) {
15556
+ visibleElements.push(element);
15557
+ }
15558
+ }
15559
+ return visibleElements;
15560
+ }
15561
+ getRenderableElementsMap({
15562
+ elements,
15563
+ editingTextElement,
15564
+ newElement: newElement7
15565
+ }) {
15566
+ const elementsMap = toBrandedType(/* @__PURE__ */ new Map());
15567
+ const newElementCanvasElement = newElement7?.frameId ? null : newElement7;
15568
+ for (const element of elements) {
15569
+ if (newElementCanvasElement?.id === element.id) {
15570
+ continue;
15571
+ }
15572
+ if (!editingTextElement || editingTextElement.type !== "text" || element.id !== editingTextElement.id) {
15573
+ elementsMap.set(element.id, element);
15574
+ }
15575
+ }
15576
+ return { elementsMap, newElementCanvasElement };
15577
+ }
15578
+ sortSelectedElementsIntoHighlightedFrame({
15579
+ visibleElements,
15580
+ selectedElements,
15581
+ frameToHighlight
15582
+ }) {
15583
+ if (!selectedElements.length) {
15584
+ return visibleElements;
15585
+ }
15586
+ const selectedElementsMap = arrayToMap24(selectedElements);
15587
+ const deselectedElements = visibleElements.filter(
15588
+ (element) => !selectedElementsMap.has(element.id)
15589
+ );
15590
+ const insertionIndex = getFrameChildrenInsertionIndex(
15591
+ deselectedElements,
15592
+ frameToHighlight.id
15593
+ );
15594
+ if (insertionIndex === null) {
15595
+ return visibleElements;
15596
+ }
15597
+ return [
15598
+ ...deselectedElements.slice(0, insertionIndex),
15599
+ ...selectedElements,
15600
+ ...deselectedElements.slice(insertionIndex)
15601
+ ];
15602
+ }
15603
+ // NOTE Doesn't destroy everything (scene, rc, etc.) because it may not be
15604
+ // safe to break TS contract here (for upstream cases)
15605
+ destroy() {
15606
+ renderStaticSceneThrottled.cancel();
15607
+ this._getRenderableElements.clear();
15608
+ }
15609
+ };
15610
+
15611
+ // scene/scrollbars.ts
15612
+ import { getGlobalCSSVariable } from "@excalidraw/common";
15613
+ import { getCommonBounds as getCommonBounds4 } from "@excalidraw/element";
15614
+ var SCROLLBAR_MARGIN = 4;
15615
+ var SCROLLBAR_WIDTH = 6;
15616
+ var SCROLLBAR_COLOR = "rgba(0,0,0,0.3)";
15617
+ var getScrollBars = (elements, viewportWidth, viewportHeight, appState) => {
15618
+ if (!elements.size) {
15619
+ return {
15620
+ horizontal: null,
15621
+ vertical: null
15622
+ };
15623
+ }
15624
+ const [elementsMinX, elementsMinY, elementsMaxX, elementsMaxY] = getCommonBounds4(elements);
15625
+ const viewportWidthWithZoom = viewportWidth / appState.zoom.value;
15626
+ const viewportHeightWithZoom = viewportHeight / appState.zoom.value;
15627
+ const safeArea = {
15628
+ top: parseInt(getGlobalCSSVariable("sat")) || 0,
15629
+ bottom: parseInt(getGlobalCSSVariable("sab")) || 0,
15630
+ left: parseInt(getGlobalCSSVariable("sal")) || 0,
15631
+ right: parseInt(getGlobalCSSVariable("sar")) || 0
15632
+ };
15633
+ const isRTL3 = getLanguage().rtl;
15634
+ const viewportMinX = -appState.scrollX + safeArea.left;
15635
+ const viewportMinY = -appState.scrollY + safeArea.top;
15636
+ const viewportMaxX = viewportMinX + viewportWidthWithZoom - safeArea.right;
15637
+ const viewportMaxY = viewportMinY + viewportHeightWithZoom - safeArea.bottom;
15638
+ const sceneMinX = Math.min(elementsMinX, viewportMinX);
15639
+ const sceneMinY = Math.min(elementsMinY, viewportMinY);
15640
+ const sceneMaxX = Math.max(elementsMaxX, viewportMaxX);
15641
+ const sceneMaxY = Math.max(elementsMaxY, viewportMaxY);
15642
+ const sceneWidth = elementsMaxX - elementsMinX;
15643
+ const sceneHeight = elementsMaxY - elementsMinY;
15644
+ const extendedSceneWidth = sceneMaxX - sceneMinX;
15645
+ const extendedSceneHeight = sceneMaxY - sceneMinY;
15646
+ const scrollWidthOffset = Math.max(SCROLLBAR_MARGIN * 2, safeArea.left + safeArea.right) + SCROLLBAR_WIDTH * 2;
15647
+ const scrollbarWidth = viewportWidth * (viewportWidthWithZoom / extendedSceneWidth) - scrollWidthOffset;
15648
+ const scrollbarHeightOffset = Math.max(SCROLLBAR_MARGIN * 2, safeArea.top + safeArea.bottom) + SCROLLBAR_WIDTH * 2;
15649
+ const scrollbarHeight = viewportHeight * (viewportHeightWithZoom / extendedSceneHeight) - scrollbarHeightOffset;
15650
+ const horizontalDeltaMultiplier = extendedSceneWidth > sceneWidth ? extendedSceneWidth * appState.zoom.value / (scrollbarWidth + scrollWidthOffset) : viewportWidth / (scrollbarWidth + scrollWidthOffset);
15651
+ const verticalDeltaMultiplier = extendedSceneHeight > sceneHeight ? extendedSceneHeight * appState.zoom.value / (scrollbarHeight + scrollbarHeightOffset) : viewportHeight / (scrollbarHeight + scrollbarHeightOffset);
15076
15652
  return {
15077
- x: sum(allCoords, (coords) => coords.x) / allCoords.length,
15078
- y: sum(allCoords, (coords) => coords.y) / allCoords.length
15653
+ horizontal: viewportMinX === sceneMinX && viewportMaxX === sceneMaxX ? null : {
15654
+ x: Math.max(safeArea.left, SCROLLBAR_MARGIN) + SCROLLBAR_WIDTH + (viewportMinX - sceneMinX) / extendedSceneWidth * viewportWidth,
15655
+ y: viewportHeight - SCROLLBAR_WIDTH - Math.max(SCROLLBAR_MARGIN, safeArea.bottom),
15656
+ width: scrollbarWidth,
15657
+ height: SCROLLBAR_WIDTH,
15658
+ deltaMultiplier: horizontalDeltaMultiplier
15659
+ },
15660
+ vertical: viewportMinY === sceneMinY && viewportMaxY === sceneMaxY ? null : {
15661
+ x: isRTL3 ? Math.max(safeArea.left, SCROLLBAR_MARGIN) : viewportWidth - SCROLLBAR_WIDTH - Math.max(safeArea.right, SCROLLBAR_MARGIN),
15662
+ y: Math.max(safeArea.top, SCROLLBAR_MARGIN) + SCROLLBAR_WIDTH + (viewportMinY - sceneMinY) / extendedSceneHeight * viewportHeight,
15663
+ width: SCROLLBAR_WIDTH,
15664
+ height: scrollbarHeight,
15665
+ deltaMultiplier: verticalDeltaMultiplier
15666
+ }
15079
15667
  };
15080
15668
  };
15081
- var getDistance = ([a, b]) => Math.hypot(a.x - b.x, a.y - b.y);
15082
- var sum = (array, mapper) => array.reduce((acc, item) => acc + mapper(item), 0);
15669
+ var isOverScrollBars = (scrollBars, x, y) => {
15670
+ const [isOverHorizontal, isOverVertical] = [
15671
+ scrollBars.horizontal,
15672
+ scrollBars.vertical
15673
+ ].map((scrollBar) => {
15674
+ return scrollBar != null && scrollBar.x <= x && x <= scrollBar.x + scrollBar.width && scrollBar.y <= y && y <= scrollBar.y + scrollBar.height;
15675
+ });
15676
+ const isOverEither = isOverHorizontal || isOverVertical;
15677
+ return { isOverEither, isOverHorizontal, isOverVertical };
15678
+ };
15083
15679
 
15084
15680
  // snapping.ts
15085
15681
  import {
@@ -15091,9 +15687,9 @@ import {
15091
15687
  } from "@excalidraw/math";
15092
15688
  import { TOOL_TYPE, KEYS as KEYS34 } from "@excalidraw/common";
15093
15689
  import {
15094
- getCommonBounds as getCommonBounds4,
15690
+ getCommonBounds as getCommonBounds5,
15095
15691
  getDraggedElementsBounds,
15096
- getElementAbsoluteCoords as getElementAbsoluteCoords4
15692
+ getElementAbsoluteCoords as getElementAbsoluteCoords5
15097
15693
  } from "@excalidraw/element";
15098
15694
  import { isBoundToContainer as isBoundToContainer6 } from "@excalidraw/element";
15099
15695
  import { getMaximumGroups } from "@excalidraw/element";
@@ -15156,7 +15752,7 @@ var getElementsCorners = (elements, elementsMap, {
15156
15752
  let result = [];
15157
15753
  if (elements.length === 1) {
15158
15754
  const element = elements[0];
15159
- let [x1, y1, x2, y2, cx, cy] = getElementAbsoluteCoords4(
15755
+ let [x1, y1, x2, y2, cx, cy] = getElementAbsoluteCoords5(
15160
15756
  element,
15161
15757
  elementsMap
15162
15758
  );
@@ -15249,7 +15845,7 @@ var getVisibleGaps = (elements, selectedElements, appState, elementsMap) => {
15249
15845
  const referenceBounds = getMaximumGroups(referenceElements, elementsMap).filter(
15250
15846
  (elementsGroup) => !(elementsGroup.length === 1 && isBoundToContainer6(elementsGroup[0]))
15251
15847
  ).map(
15252
- (group) => getCommonBounds4(group).map(
15848
+ (group) => getCommonBounds5(group).map(
15253
15849
  (bound) => round(bound)
15254
15850
  )
15255
15851
  );
@@ -15845,7 +16441,7 @@ var snapResizingElements = (selectedElements, selectedOriginalElements, app, eve
15845
16441
  snapLines: []
15846
16442
  };
15847
16443
  }
15848
- let [minX, minY, maxX, maxY] = getCommonBounds4(selectedOriginalElements);
16444
+ let [minX, minY, maxX, maxY] = getCommonBounds5(selectedOriginalElements);
15849
16445
  if (transformHandle) {
15850
16446
  if (transformHandle.includes("e")) {
15851
16447
  maxX += dragOffset.x;
@@ -15919,7 +16515,7 @@ var snapResizingElements = (selectedElements, selectedOriginalElements, app, eve
15919
16515
  minOffset.y = 0;
15920
16516
  nearestSnapsX.length = 0;
15921
16517
  nearestSnapsY.length = 0;
15922
- const [x1, y1, x2, y2] = getCommonBounds4(selectedElements).map(
16518
+ const [x1, y1, x2, y2] = getCommonBounds5(selectedElements).map(
15923
16519
  (bound) => round(bound)
15924
16520
  );
15925
16521
  const corners = [
@@ -16057,472 +16653,6 @@ var isActiveToolNonLinearSnappable = (activeToolType) => {
16057
16653
  return activeToolType === TOOL_TYPE.rectangle || activeToolType === TOOL_TYPE.ellipse || activeToolType === TOOL_TYPE.diamond || activeToolType === TOOL_TYPE.frame || activeToolType === TOOL_TYPE.magicframe || activeToolType === TOOL_TYPE.image || activeToolType === TOOL_TYPE.text;
16058
16654
  };
16059
16655
 
16060
- // scene/Renderer.ts
16061
- import {
16062
- getCommonFrameId,
16063
- getFrameChildrenInsertionIndex,
16064
- isElementInViewport as isElementInViewport2
16065
- } from "@excalidraw/element";
16066
- import { arrayToMap as arrayToMap24, memoize, toBrandedType } from "@excalidraw/common";
16067
- var Renderer = class {
16068
- constructor(scene) {
16069
- __publicField(this, "scene");
16070
- __publicField(this, "_getRenderableElements", memoize(
16071
- ({
16072
- canvasNonce,
16073
- zoom,
16074
- offsetLeft,
16075
- offsetTop,
16076
- scrollX,
16077
- scrollY,
16078
- height,
16079
- width,
16080
- editingTextElement,
16081
- newElement: newElement7
16082
- }) => {
16083
- const elements = this.scene.getNonDeletedElements();
16084
- const { elementsMap, newElementCanvasElement } = this.getRenderableElementsMap({
16085
- elements,
16086
- editingTextElement,
16087
- newElement: newElement7
16088
- });
16089
- const visibleElements = this.getVisibleCanvasElements({
16090
- elementsMap,
16091
- zoom,
16092
- offsetLeft,
16093
- offsetTop,
16094
- scrollX,
16095
- scrollY,
16096
- height,
16097
- width
16098
- });
16099
- return {
16100
- elementsMap,
16101
- visibleElements,
16102
- newElementCanvasElement,
16103
- canvasNonce
16104
- };
16105
- }
16106
- ));
16107
- __publicField(this, "getRenderableElements", (opts) => {
16108
- const { newElement: newElement7 } = opts;
16109
- const canvasNonce = `${this.scene.getSceneNonce()}${newElement7?.frameId ? `:${newElement7.versionNonce}` : ""}`;
16110
- const ret = this._getRenderableElements({
16111
- canvasNonce,
16112
- // don't spread `opts` because we don't want to memoize on some props
16113
- zoom: opts.zoom,
16114
- offsetLeft: opts.offsetLeft,
16115
- offsetTop: opts.offsetTop,
16116
- scrollX: opts.scrollX,
16117
- scrollY: opts.scrollY,
16118
- height: opts.height,
16119
- width: opts.width,
16120
- editingTextElement: opts.editingTextElement,
16121
- newElement: opts.newElement
16122
- });
16123
- if (opts.frameToHighlight && opts.selectedElementsAreBeingDragged && // if all dragged elements are already in the frame, don't reorder
16124
- getCommonFrameId(opts.selectedElements) !== opts.frameToHighlight.id) {
16125
- const reorderedVisibleElements = this.sortSelectedElementsIntoHighlightedFrame({
16126
- visibleElements: ret.visibleElements,
16127
- selectedElements: opts.selectedElements,
16128
- frameToHighlight: opts.frameToHighlight
16129
- });
16130
- return {
16131
- ...ret,
16132
- visibleElements: reorderedVisibleElements
16133
- };
16134
- }
16135
- return ret;
16136
- });
16137
- this.scene = scene;
16138
- }
16139
- getVisibleCanvasElements({
16140
- elementsMap,
16141
- zoom,
16142
- offsetLeft,
16143
- offsetTop,
16144
- scrollX,
16145
- scrollY,
16146
- height,
16147
- width
16148
- }) {
16149
- const visibleElements = [];
16150
- for (const element of elementsMap.values()) {
16151
- if (isElementInViewport2(
16152
- element,
16153
- width,
16154
- height,
16155
- {
16156
- zoom,
16157
- offsetLeft,
16158
- offsetTop,
16159
- scrollX,
16160
- scrollY
16161
- },
16162
- elementsMap
16163
- )) {
16164
- visibleElements.push(element);
16165
- }
16166
- }
16167
- return visibleElements;
16168
- }
16169
- getRenderableElementsMap({
16170
- elements,
16171
- editingTextElement,
16172
- newElement: newElement7
16173
- }) {
16174
- const elementsMap = toBrandedType(/* @__PURE__ */ new Map());
16175
- const newElementCanvasElement = newElement7?.frameId ? null : newElement7;
16176
- for (const element of elements) {
16177
- if (newElementCanvasElement?.id === element.id) {
16178
- continue;
16179
- }
16180
- if (!editingTextElement || editingTextElement.type !== "text" || element.id !== editingTextElement.id) {
16181
- elementsMap.set(element.id, element);
16182
- }
16183
- }
16184
- return { elementsMap, newElementCanvasElement };
16185
- }
16186
- sortSelectedElementsIntoHighlightedFrame({
16187
- visibleElements,
16188
- selectedElements,
16189
- frameToHighlight
16190
- }) {
16191
- if (!selectedElements.length) {
16192
- return visibleElements;
16193
- }
16194
- const selectedElementsMap = arrayToMap24(selectedElements);
16195
- const deselectedElements = visibleElements.filter(
16196
- (element) => !selectedElementsMap.has(element.id)
16197
- );
16198
- const insertionIndex = getFrameChildrenInsertionIndex(
16199
- deselectedElements,
16200
- frameToHighlight.id
16201
- );
16202
- if (insertionIndex === null) {
16203
- return visibleElements;
16204
- }
16205
- return [
16206
- ...deselectedElements.slice(0, insertionIndex),
16207
- ...selectedElements,
16208
- ...deselectedElements.slice(insertionIndex)
16209
- ];
16210
- }
16211
- // NOTE Doesn't destroy everything (scene, rc, etc.) because it may not be
16212
- // safe to break TS contract here (for upstream cases)
16213
- destroy() {
16214
- renderStaticSceneThrottled.cancel();
16215
- this._getRenderableElements.clear();
16216
- }
16217
- };
16218
-
16219
- // components/ElementCanvasButtons.tsx
16220
- import { sceneCoordsToViewportCoords as sceneCoordsToViewportCoords2 } from "@excalidraw/common";
16221
- import { getElementAbsoluteCoords as getElementAbsoluteCoords5 } from "@excalidraw/element";
16222
- import { jsx as jsx57 } from "react/jsx-runtime";
16223
- var CONTAINER_PADDING = 5;
16224
- var getContainerCoords2 = (element, appState, elementsMap) => {
16225
- const [x1, y1] = getElementAbsoluteCoords5(element, elementsMap);
16226
- const { x: viewportX, y: viewportY } = sceneCoordsToViewportCoords2(
16227
- { sceneX: x1 + element.width, sceneY: y1 },
16228
- appState
16229
- );
16230
- const x = viewportX - appState.offsetLeft + 10;
16231
- const y = viewportY - appState.offsetTop;
16232
- return { x, y };
16233
- };
16234
- var ElementCanvasButtons = ({
16235
- children,
16236
- element,
16237
- elementsMap
16238
- }) => {
16239
- const appState = useExcalidrawAppState();
16240
- if (appState.contextMenu || appState.newElement || appState.resizingElement || appState.isRotating || appState.openMenu || appState.viewModeEnabled) {
16241
- return null;
16242
- }
16243
- const { x, y } = getContainerCoords2(element, appState, elementsMap);
16244
- return /* @__PURE__ */ jsx57(
16245
- "div",
16246
- {
16247
- className: "excalidraw-canvas-buttons",
16248
- style: {
16249
- top: `${y}px`,
16250
- left: `${x}px`,
16251
- // width: CONTAINER_WIDTH,
16252
- padding: CONTAINER_PADDING
16253
- },
16254
- children
16255
- }
16256
- );
16257
- };
16258
-
16259
- // laser-trails.ts
16260
- import { DEFAULT_LASER_COLOR, easeOut } from "@excalidraw/common";
16261
-
16262
- // animated-trail.ts
16263
- import { LaserPointer } from "@excalidraw/laser-pointer";
16264
- import {
16265
- SVG_NS,
16266
- getSvgPathFromStroke as getSvgPathFromStroke2,
16267
- sceneCoordsToViewportCoords as sceneCoordsToViewportCoords3
16268
- } from "@excalidraw/common";
16269
- var AnimatedTrail = class {
16270
- constructor(animationFrameHandler, app, options) {
16271
- this.animationFrameHandler = animationFrameHandler;
16272
- this.app = app;
16273
- this.options = options;
16274
- __publicField(this, "currentTrail");
16275
- __publicField(this, "pastTrails", []);
16276
- __publicField(this, "container");
16277
- __publicField(this, "trailElement");
16278
- __publicField(this, "trailAnimation");
16279
- this.animationFrameHandler.register(this, this.onFrame.bind(this));
16280
- this.trailElement = document.createElementNS(SVG_NS, "path");
16281
- if (this.options.animateTrail) {
16282
- this.trailAnimation = document.createElementNS(SVG_NS, "animate");
16283
- this.trailAnimation.setAttribute("attributeName", "stroke-dashoffset");
16284
- this.trailElement.setAttribute("stroke-dasharray", "7 7");
16285
- this.trailElement.setAttribute("stroke-dashoffset", "10");
16286
- this.trailAnimation.setAttribute("from", "0");
16287
- this.trailAnimation.setAttribute("to", `-14`);
16288
- this.trailAnimation.setAttribute("dur", "0.3s");
16289
- this.trailElement.appendChild(this.trailAnimation);
16290
- }
16291
- }
16292
- get hasCurrentTrail() {
16293
- return !!this.currentTrail;
16294
- }
16295
- hasLastPoint(x, y) {
16296
- if (this.currentTrail) {
16297
- const len = this.currentTrail.originalPoints.length;
16298
- return this.currentTrail.originalPoints[len - 1][0] === x && this.currentTrail.originalPoints[len - 1][1] === y;
16299
- }
16300
- return false;
16301
- }
16302
- start(container) {
16303
- if (container) {
16304
- this.container = container;
16305
- }
16306
- if (this.trailElement.parentNode !== this.container && this.container) {
16307
- this.container.appendChild(this.trailElement);
16308
- }
16309
- this.animationFrameHandler.start(this);
16310
- }
16311
- stop() {
16312
- this.animationFrameHandler.stop(this);
16313
- if (this.trailElement.parentNode === this.container) {
16314
- this.container?.removeChild(this.trailElement);
16315
- }
16316
- }
16317
- startPath(x, y) {
16318
- this.currentTrail = new LaserPointer(this.options);
16319
- this.currentTrail.addPoint([x, y, performance.now()]);
16320
- this.update();
16321
- }
16322
- addPointToPath(x, y) {
16323
- if (this.currentTrail) {
16324
- this.currentTrail.addPoint([x, y, performance.now()]);
16325
- this.update();
16326
- }
16327
- }
16328
- endPath() {
16329
- if (this.currentTrail) {
16330
- this.currentTrail.close();
16331
- this.currentTrail.options.keepHead = false;
16332
- this.pastTrails.push(this.currentTrail);
16333
- this.currentTrail = void 0;
16334
- this.update();
16335
- }
16336
- }
16337
- getCurrentTrail() {
16338
- return this.currentTrail;
16339
- }
16340
- clearTrails() {
16341
- this.pastTrails = [];
16342
- this.currentTrail = void 0;
16343
- this.update();
16344
- }
16345
- update() {
16346
- this.start();
16347
- if (this.trailAnimation) {
16348
- this.trailAnimation.setAttribute("begin", "indefinite");
16349
- this.trailAnimation.setAttribute("repeatCount", "indefinite");
16350
- }
16351
- }
16352
- onFrame() {
16353
- const paths = [];
16354
- for (const trail of this.pastTrails) {
16355
- paths.push(this.drawTrail(trail, this.app.state));
16356
- }
16357
- if (this.currentTrail) {
16358
- const currentPath = this.drawTrail(this.currentTrail, this.app.state);
16359
- paths.push(currentPath);
16360
- }
16361
- this.pastTrails = this.pastTrails.filter((trail) => {
16362
- return trail.getStrokeOutline().length !== 0;
16363
- });
16364
- if (paths.length === 0) {
16365
- this.stop();
16366
- }
16367
- const svgPaths = paths.join(" ").trim();
16368
- this.trailElement.setAttribute("d", svgPaths);
16369
- if (this.trailAnimation) {
16370
- this.trailElement.setAttribute(
16371
- "fill",
16372
- (this.options.fill ?? (() => "black"))(this)
16373
- );
16374
- this.trailElement.setAttribute(
16375
- "stroke",
16376
- (this.options.stroke ?? (() => "black"))(this)
16377
- );
16378
- } else {
16379
- this.trailElement.setAttribute(
16380
- "fill",
16381
- (this.options.fill ?? (() => "black"))(this)
16382
- );
16383
- }
16384
- }
16385
- drawTrail(trail, state) {
16386
- const _stroke = trail.getStrokeOutline(trail.options.size / state.zoom.value).map(([x, y]) => {
16387
- const result = sceneCoordsToViewportCoords3(
16388
- { sceneX: x, sceneY: y },
16389
- state
16390
- );
16391
- return [result.x, result.y];
16392
- });
16393
- const stroke = this.trailAnimation ? _stroke.slice(0, _stroke.length / 2) : _stroke;
16394
- return getSvgPathFromStroke2(stroke, true);
16395
- }
16396
- };
16397
-
16398
- // laser-trails.ts
16399
- var LaserTrails = class {
16400
- constructor(animationFrameHandler, app) {
16401
- this.animationFrameHandler = animationFrameHandler;
16402
- this.app = app;
16403
- __publicField(this, "localTrail");
16404
- __publicField(this, "collabTrails", /* @__PURE__ */ new Map());
16405
- __publicField(this, "container");
16406
- this.animationFrameHandler.register(this, this.onFrame.bind(this));
16407
- this.localTrail = new AnimatedTrail(animationFrameHandler, app, {
16408
- ...this.getTrailOptions(),
16409
- fill: () => DEFAULT_LASER_COLOR
16410
- });
16411
- }
16412
- getTrailOptions() {
16413
- return {
16414
- simplify: 0,
16415
- streamline: 0.4,
16416
- sizeMapping: (c) => {
16417
- const DECAY_TIME = 1e3;
16418
- const DECAY_LENGTH = 50;
16419
- const t2 = Math.max(
16420
- 0,
16421
- 1 - (performance.now() - c.pressure) / DECAY_TIME
16422
- );
16423
- const l = (DECAY_LENGTH - Math.min(DECAY_LENGTH, c.totalLength - c.currentIndex)) / DECAY_LENGTH;
16424
- return Math.min(easeOut(l), easeOut(t2));
16425
- }
16426
- };
16427
- }
16428
- startPath(x, y) {
16429
- this.localTrail.startPath(x, y);
16430
- }
16431
- addPointToPath(x, y) {
16432
- this.localTrail.addPointToPath(x, y);
16433
- }
16434
- endPath() {
16435
- this.localTrail.endPath();
16436
- }
16437
- start(container) {
16438
- this.container = container;
16439
- this.animationFrameHandler.start(this);
16440
- this.localTrail.start(container);
16441
- }
16442
- stop() {
16443
- this.animationFrameHandler.stop(this);
16444
- this.localTrail.stop();
16445
- }
16446
- onFrame() {
16447
- this.updateCollabTrails();
16448
- }
16449
- updateCollabTrails() {
16450
- if (!this.container || this.app.state.collaborators.size === 0) {
16451
- return;
16452
- }
16453
- for (const [key, collaborator] of this.app.state.collaborators.entries()) {
16454
- let trail;
16455
- if (!this.collabTrails.has(key)) {
16456
- trail = new AnimatedTrail(this.animationFrameHandler, this.app, {
16457
- ...this.getTrailOptions(),
16458
- fill: () => collaborator.pointer?.laserColor || getClientColor(key, collaborator)
16459
- });
16460
- trail.start(this.container);
16461
- this.collabTrails.set(key, trail);
16462
- } else {
16463
- trail = this.collabTrails.get(key);
16464
- }
16465
- if (collaborator.pointer && collaborator.pointer.tool === "laser") {
16466
- if (collaborator.button === "down" && !trail.hasCurrentTrail) {
16467
- trail.startPath(collaborator.pointer.x, collaborator.pointer.y);
16468
- }
16469
- if (collaborator.button === "down" && trail.hasCurrentTrail && !trail.hasLastPoint(collaborator.pointer.x, collaborator.pointer.y)) {
16470
- trail.addPointToPath(collaborator.pointer.x, collaborator.pointer.y);
16471
- }
16472
- if (collaborator.button === "up" && trail.hasCurrentTrail) {
16473
- trail.addPointToPath(collaborator.pointer.x, collaborator.pointer.y);
16474
- trail.endPath();
16475
- }
16476
- }
16477
- }
16478
- for (const key of this.collabTrails.keys()) {
16479
- if (!this.app.state.collaborators.has(key)) {
16480
- const trail = this.collabTrails.get(key);
16481
- trail.stop();
16482
- this.collabTrails.delete(key);
16483
- }
16484
- }
16485
- }
16486
- };
16487
-
16488
- // reactUtils.ts
16489
- import { version as ReactVersion } from "react";
16490
- import { unstable_batchedUpdates } from "react-dom";
16491
- import { throttleRAF } from "@excalidraw/common";
16492
- var withBatchedUpdates = (func) => (event) => {
16493
- unstable_batchedUpdates(func, event);
16494
- };
16495
- var withBatchedUpdatesThrottled = (func) => {
16496
- return throttleRAF((event) => {
16497
- unstable_batchedUpdates(func, event);
16498
- });
16499
- };
16500
- var isRenderThrottlingEnabled = (() => {
16501
- let IS_REACT_18_AND_UP;
16502
- try {
16503
- const version = ReactVersion.split(".");
16504
- IS_REACT_18_AND_UP = Number(version[0]) > 17;
16505
- } catch {
16506
- IS_REACT_18_AND_UP = false;
16507
- }
16508
- let hasWarned = false;
16509
- return () => {
16510
- if (window.EXCALIDRAW_THROTTLE_RENDER === true) {
16511
- if (!IS_REACT_18_AND_UP) {
16512
- if (!hasWarned) {
16513
- hasWarned = true;
16514
- console.warn(
16515
- "Excalidraw: render throttling is disabled on React versions < 18."
16516
- );
16517
- }
16518
- return false;
16519
- }
16520
- return true;
16521
- }
16522
- return false;
16523
- };
16524
- })();
16525
-
16526
16656
  // textAutoResizeHandle.ts
16527
16657
  import { DEFAULT_TRANSFORM_HANDLE_SPACING } from "@excalidraw/common";
16528
16658
  import {
@@ -17298,75 +17428,6 @@ var textWysiwyg = ({
17298
17428
  return handleSubmit;
17299
17429
  };
17300
17430
 
17301
- // scene/scrollbars.ts
17302
- import { getGlobalCSSVariable } from "@excalidraw/common";
17303
- import { getCommonBounds as getCommonBounds5 } from "@excalidraw/element";
17304
- var SCROLLBAR_MARGIN = 4;
17305
- var SCROLLBAR_WIDTH = 6;
17306
- var SCROLLBAR_COLOR = "rgba(0,0,0,0.3)";
17307
- var getScrollBars = (elements, viewportWidth, viewportHeight, appState) => {
17308
- if (!elements.size) {
17309
- return {
17310
- horizontal: null,
17311
- vertical: null
17312
- };
17313
- }
17314
- const [elementsMinX, elementsMinY, elementsMaxX, elementsMaxY] = getCommonBounds5(elements);
17315
- const viewportWidthWithZoom = viewportWidth / appState.zoom.value;
17316
- const viewportHeightWithZoom = viewportHeight / appState.zoom.value;
17317
- const safeArea = {
17318
- top: parseInt(getGlobalCSSVariable("sat")) || 0,
17319
- bottom: parseInt(getGlobalCSSVariable("sab")) || 0,
17320
- left: parseInt(getGlobalCSSVariable("sal")) || 0,
17321
- right: parseInt(getGlobalCSSVariable("sar")) || 0
17322
- };
17323
- const isRTL3 = getLanguage().rtl;
17324
- const viewportMinX = -appState.scrollX + safeArea.left;
17325
- const viewportMinY = -appState.scrollY + safeArea.top;
17326
- const viewportMaxX = viewportMinX + viewportWidthWithZoom - safeArea.right;
17327
- const viewportMaxY = viewportMinY + viewportHeightWithZoom - safeArea.bottom;
17328
- const sceneMinX = Math.min(elementsMinX, viewportMinX);
17329
- const sceneMinY = Math.min(elementsMinY, viewportMinY);
17330
- const sceneMaxX = Math.max(elementsMaxX, viewportMaxX);
17331
- const sceneMaxY = Math.max(elementsMaxY, viewportMaxY);
17332
- const sceneWidth = elementsMaxX - elementsMinX;
17333
- const sceneHeight = elementsMaxY - elementsMinY;
17334
- const extendedSceneWidth = sceneMaxX - sceneMinX;
17335
- const extendedSceneHeight = sceneMaxY - sceneMinY;
17336
- const scrollWidthOffset = Math.max(SCROLLBAR_MARGIN * 2, safeArea.left + safeArea.right) + SCROLLBAR_WIDTH * 2;
17337
- const scrollbarWidth = viewportWidth * (viewportWidthWithZoom / extendedSceneWidth) - scrollWidthOffset;
17338
- const scrollbarHeightOffset = Math.max(SCROLLBAR_MARGIN * 2, safeArea.top + safeArea.bottom) + SCROLLBAR_WIDTH * 2;
17339
- const scrollbarHeight = viewportHeight * (viewportHeightWithZoom / extendedSceneHeight) - scrollbarHeightOffset;
17340
- const horizontalDeltaMultiplier = extendedSceneWidth > sceneWidth ? extendedSceneWidth * appState.zoom.value / (scrollbarWidth + scrollWidthOffset) : viewportWidth / (scrollbarWidth + scrollWidthOffset);
17341
- const verticalDeltaMultiplier = extendedSceneHeight > sceneHeight ? extendedSceneHeight * appState.zoom.value / (scrollbarHeight + scrollbarHeightOffset) : viewportHeight / (scrollbarHeight + scrollbarHeightOffset);
17342
- return {
17343
- horizontal: viewportMinX === sceneMinX && viewportMaxX === sceneMaxX ? null : {
17344
- x: Math.max(safeArea.left, SCROLLBAR_MARGIN) + SCROLLBAR_WIDTH + (viewportMinX - sceneMinX) / extendedSceneWidth * viewportWidth,
17345
- y: viewportHeight - SCROLLBAR_WIDTH - Math.max(SCROLLBAR_MARGIN, safeArea.bottom),
17346
- width: scrollbarWidth,
17347
- height: SCROLLBAR_WIDTH,
17348
- deltaMultiplier: horizontalDeltaMultiplier
17349
- },
17350
- vertical: viewportMinY === sceneMinY && viewportMaxY === sceneMaxY ? null : {
17351
- x: isRTL3 ? Math.max(safeArea.left, SCROLLBAR_MARGIN) : viewportWidth - SCROLLBAR_WIDTH - Math.max(safeArea.right, SCROLLBAR_MARGIN),
17352
- y: Math.max(safeArea.top, SCROLLBAR_MARGIN) + SCROLLBAR_WIDTH + (viewportMinY - sceneMinY) / extendedSceneHeight * viewportHeight,
17353
- width: SCROLLBAR_WIDTH,
17354
- height: scrollbarHeight,
17355
- deltaMultiplier: verticalDeltaMultiplier
17356
- }
17357
- };
17358
- };
17359
- var isOverScrollBars = (scrollBars, x, y) => {
17360
- const [isOverHorizontal, isOverVertical] = [
17361
- scrollBars.horizontal,
17362
- scrollBars.vertical
17363
- ].map((scrollBar) => {
17364
- return scrollBar != null && scrollBar.x <= x && x <= scrollBar.x + scrollBar.width && scrollBar.y <= y && y <= scrollBar.y + scrollBar.height;
17365
- });
17366
- const isOverEither = isOverHorizontal || isOverVertical;
17367
- return { isOverEither, isOverHorizontal, isOverVertical };
17368
- };
17369
-
17370
17431
  // lasso/index.ts
17371
17432
  import {
17372
17433
  pointFrom as pointFrom21
@@ -17481,8 +17542,8 @@ var intersectionTest = (lassoPath, element, elementsMap) => {
17481
17542
 
17482
17543
  // lasso/index.ts
17483
17544
  var LassoTrail = class extends AnimatedTrail {
17484
- constructor(animationFrameHandler, app) {
17485
- super(animationFrameHandler, app, {
17545
+ constructor(app) {
17546
+ super(app, {
17486
17547
  animateTrail: true,
17487
17548
  streamline: 0.4,
17488
17549
  sizeMapping: (c) => {
@@ -17688,8 +17749,8 @@ import { shouldTestInside as shouldTestInside2 } from "@excalidraw/element";
17688
17749
  import { hasBoundTextElement as hasBoundTextElement4, isBoundToContainer as isBoundToContainer8 } from "@excalidraw/element";
17689
17750
  import { getBoundTextElementId as getBoundTextElementId2 } from "@excalidraw/element";
17690
17751
  var EraserTrail = class extends AnimatedTrail {
17691
- constructor(animationFrameHandler, app) {
17692
- super(animationFrameHandler, app, {
17752
+ constructor(app) {
17753
+ super(app, {
17693
17754
  streamline: 0.2,
17694
17755
  size: 5,
17695
17756
  keepHead: true,
@@ -19525,6 +19586,122 @@ var getConvertibleType = (element) => {
19525
19586
  };
19526
19587
  var ConvertElementTypePopup_default = ConvertElementTypePopup;
19527
19588
 
19589
+ // components/AppStateObserver.ts
19590
+ var AppStateObserver = class {
19591
+ constructor(getState) {
19592
+ this.getState = getState;
19593
+ __publicField(this, "listeners", []);
19594
+ __publicField(this, "onStateChange", (propOrOpts, callback, opts) => {
19595
+ const {
19596
+ predicate,
19597
+ getValue,
19598
+ callback: stateChangeCallback,
19599
+ once,
19600
+ matchesImmediately
19601
+ } = this.normalize(propOrOpts, callback, opts);
19602
+ if (stateChangeCallback) {
19603
+ if (matchesImmediately) {
19604
+ queueMicrotask(() => {
19605
+ const state = this.getState();
19606
+ stateChangeCallback(getValue(state), state);
19607
+ });
19608
+ if (once) {
19609
+ return () => {
19610
+ };
19611
+ }
19612
+ }
19613
+ return this.subscribe({
19614
+ predicate,
19615
+ getValue,
19616
+ callback: stateChangeCallback,
19617
+ once
19618
+ });
19619
+ }
19620
+ if (matchesImmediately) {
19621
+ return Promise.resolve(getValue(this.getState()));
19622
+ }
19623
+ return new Promise((resolve) => {
19624
+ this.subscribe({
19625
+ predicate,
19626
+ getValue,
19627
+ callback: (value) => resolve(value),
19628
+ once: true
19629
+ });
19630
+ });
19631
+ });
19632
+ }
19633
+ isStateChangePredicateOptions(propOrOpts) {
19634
+ return typeof propOrOpts === "object" && !Array.isArray(propOrOpts) && "predicate" in propOrOpts;
19635
+ }
19636
+ subscribe(listener) {
19637
+ this.listeners.push(listener);
19638
+ return () => {
19639
+ this.listeners = this.listeners.filter(
19640
+ (existingListener) => existingListener !== listener
19641
+ );
19642
+ };
19643
+ }
19644
+ normalize(propOrOpts, callback, opts) {
19645
+ let predicate;
19646
+ let getValue;
19647
+ let normalizedCallback = callback;
19648
+ let once = opts?.once ?? false;
19649
+ let matchesImmediately = false;
19650
+ if (this.isStateChangePredicateOptions(propOrOpts)) {
19651
+ const {
19652
+ predicate: predicateFn,
19653
+ callback: callbackFromOpts,
19654
+ once: onceFromOpts
19655
+ } = propOrOpts;
19656
+ predicate = predicateFn;
19657
+ getValue = (appState) => appState;
19658
+ normalizedCallback = callbackFromOpts ? (_value, appState) => callbackFromOpts(appState) : void 0;
19659
+ once = onceFromOpts ?? false;
19660
+ matchesImmediately = predicateFn(this.getState());
19661
+ } else if (typeof propOrOpts === "function") {
19662
+ const selector = propOrOpts;
19663
+ predicate = (appState, prevState) => selector(appState) !== selector(prevState);
19664
+ getValue = (appState) => selector(appState);
19665
+ } else if (Array.isArray(propOrOpts)) {
19666
+ const keys = propOrOpts;
19667
+ predicate = (appState, prevState) => keys.some((key) => appState[key] !== prevState[key]);
19668
+ getValue = (appState) => appState;
19669
+ } else {
19670
+ const key = propOrOpts;
19671
+ predicate = (appState, prevState) => appState[key] !== prevState[key];
19672
+ getValue = (appState) => appState[key];
19673
+ }
19674
+ return {
19675
+ predicate,
19676
+ getValue,
19677
+ callback: normalizedCallback,
19678
+ once,
19679
+ matchesImmediately
19680
+ };
19681
+ }
19682
+ flush(prevState) {
19683
+ if (!this.listeners.length) {
19684
+ return;
19685
+ }
19686
+ const state = this.getState();
19687
+ const listenersToKeep = [];
19688
+ for (const listener of this.listeners) {
19689
+ if (listener.predicate(state, prevState)) {
19690
+ listener.callback(listener.getValue(state), state);
19691
+ if (!listener.once) {
19692
+ listenersToKeep.push(listener);
19693
+ }
19694
+ } else {
19695
+ listenersToKeep.push(listener);
19696
+ }
19697
+ }
19698
+ this.listeners = listenersToKeep;
19699
+ }
19700
+ clear() {
19701
+ this.listeners = [];
19702
+ }
19703
+ };
19704
+
19528
19705
  // components/Trans.tsx
19529
19706
  import React17 from "react";
19530
19707
  var SPLIT_REGEX = /({{[\w-]+}})|(<[\w-]+>)|(<\/[\w-]+>)/g;
@@ -30943,67 +31120,6 @@ var renderInteractiveScene = (renderConfig) => {
30943
31120
  return ret;
30944
31121
  };
30945
31122
 
30946
- // renderer/animation.ts
30947
- var _AnimationController = class _AnimationController {
30948
- static start(key, animation) {
30949
- const initialState = animation({
30950
- deltaTime: 0,
30951
- state: void 0
30952
- });
30953
- if (initialState) {
30954
- _AnimationController.animations.set(key, {
30955
- animation,
30956
- lastTime: 0,
30957
- state: initialState
30958
- });
30959
- if (!_AnimationController.isRunning) {
30960
- _AnimationController.isRunning = true;
30961
- if (isRenderThrottlingEnabled()) {
30962
- requestAnimationFrame(_AnimationController.tick);
30963
- } else {
30964
- setTimeout(_AnimationController.tick, 0);
30965
- }
30966
- }
30967
- }
30968
- }
30969
- static tick() {
30970
- if (_AnimationController.animations.size > 0) {
30971
- for (const [key, animation] of _AnimationController.animations) {
30972
- const now = performance.now();
30973
- const deltaTime = animation.lastTime === 0 ? 0 : now - animation.lastTime;
30974
- const state = animation.animation({
30975
- deltaTime,
30976
- state: animation.state
30977
- });
30978
- if (!state) {
30979
- _AnimationController.animations.delete(key);
30980
- if (_AnimationController.animations.size === 0) {
30981
- _AnimationController.isRunning = false;
30982
- return;
30983
- }
30984
- } else {
30985
- animation.lastTime = now;
30986
- animation.state = state;
30987
- }
30988
- }
30989
- if (isRenderThrottlingEnabled()) {
30990
- requestAnimationFrame(_AnimationController.tick);
30991
- } else {
30992
- setTimeout(_AnimationController.tick, 0);
30993
- }
30994
- }
30995
- }
30996
- static running(key) {
30997
- return _AnimationController.animations.has(key);
30998
- }
30999
- static cancel(key) {
31000
- _AnimationController.animations.delete(key);
31001
- }
31002
- };
31003
- __publicField(_AnimationController, "isRunning", false);
31004
- __publicField(_AnimationController, "animations", /* @__PURE__ */ new Map());
31005
- var AnimationController = _AnimationController;
31006
-
31007
31123
  // components/canvases/InteractiveCanvas.tsx
31008
31124
  import { jsx as jsx133 } from "react/jsx-runtime";
31009
31125
  var INTERACTIVE_SCENE_ANIMATION_KEY = "animateInteractiveScene";
@@ -31384,122 +31500,6 @@ var NewElementCanvas = (props) => {
31384
31500
  };
31385
31501
  var NewElementCanvas_default = NewElementCanvas;
31386
31502
 
31387
- // components/AppStateObserver.ts
31388
- var AppStateObserver = class {
31389
- constructor(getState) {
31390
- this.getState = getState;
31391
- __publicField(this, "listeners", []);
31392
- __publicField(this, "onStateChange", (propOrOpts, callback, opts) => {
31393
- const {
31394
- predicate,
31395
- getValue,
31396
- callback: stateChangeCallback,
31397
- once,
31398
- matchesImmediately
31399
- } = this.normalize(propOrOpts, callback, opts);
31400
- if (stateChangeCallback) {
31401
- if (matchesImmediately) {
31402
- queueMicrotask(() => {
31403
- const state = this.getState();
31404
- stateChangeCallback(getValue(state), state);
31405
- });
31406
- if (once) {
31407
- return () => {
31408
- };
31409
- }
31410
- }
31411
- return this.subscribe({
31412
- predicate,
31413
- getValue,
31414
- callback: stateChangeCallback,
31415
- once
31416
- });
31417
- }
31418
- if (matchesImmediately) {
31419
- return Promise.resolve(getValue(this.getState()));
31420
- }
31421
- return new Promise((resolve) => {
31422
- this.subscribe({
31423
- predicate,
31424
- getValue,
31425
- callback: (value) => resolve(value),
31426
- once: true
31427
- });
31428
- });
31429
- });
31430
- }
31431
- isStateChangePredicateOptions(propOrOpts) {
31432
- return typeof propOrOpts === "object" && !Array.isArray(propOrOpts) && "predicate" in propOrOpts;
31433
- }
31434
- subscribe(listener) {
31435
- this.listeners.push(listener);
31436
- return () => {
31437
- this.listeners = this.listeners.filter(
31438
- (existingListener) => existingListener !== listener
31439
- );
31440
- };
31441
- }
31442
- normalize(propOrOpts, callback, opts) {
31443
- let predicate;
31444
- let getValue;
31445
- let normalizedCallback = callback;
31446
- let once = opts?.once ?? false;
31447
- let matchesImmediately = false;
31448
- if (this.isStateChangePredicateOptions(propOrOpts)) {
31449
- const {
31450
- predicate: predicateFn,
31451
- callback: callbackFromOpts,
31452
- once: onceFromOpts
31453
- } = propOrOpts;
31454
- predicate = predicateFn;
31455
- getValue = (appState) => appState;
31456
- normalizedCallback = callbackFromOpts ? (_value, appState) => callbackFromOpts(appState) : void 0;
31457
- once = onceFromOpts ?? false;
31458
- matchesImmediately = predicateFn(this.getState());
31459
- } else if (typeof propOrOpts === "function") {
31460
- const selector = propOrOpts;
31461
- predicate = (appState, prevState) => selector(appState) !== selector(prevState);
31462
- getValue = (appState) => selector(appState);
31463
- } else if (Array.isArray(propOrOpts)) {
31464
- const keys = propOrOpts;
31465
- predicate = (appState, prevState) => keys.some((key) => appState[key] !== prevState[key]);
31466
- getValue = (appState) => appState;
31467
- } else {
31468
- const key = propOrOpts;
31469
- predicate = (appState, prevState) => appState[key] !== prevState[key];
31470
- getValue = (appState) => appState[key];
31471
- }
31472
- return {
31473
- predicate,
31474
- getValue,
31475
- callback: normalizedCallback,
31476
- once,
31477
- matchesImmediately
31478
- };
31479
- }
31480
- flush(prevState) {
31481
- if (!this.listeners.length) {
31482
- return;
31483
- }
31484
- const state = this.getState();
31485
- const listenersToKeep = [];
31486
- for (const listener of this.listeners) {
31487
- if (listener.predicate(state, prevState)) {
31488
- listener.callback(listener.getValue(state), state);
31489
- if (!listener.once) {
31490
- listenersToKeep.push(listener);
31491
- }
31492
- } else {
31493
- listenersToKeep.push(listener);
31494
- }
31495
- }
31496
- this.listeners = listenersToKeep;
31497
- }
31498
- clear() {
31499
- this.listeners = [];
31500
- }
31501
- };
31502
-
31503
31503
  // components/UnlockPopup.tsx
31504
31504
  import {
31505
31505
  getCommonBounds as getCommonBounds10,
@@ -31698,10 +31698,9 @@ var App = class _App extends React40.Component {
31698
31698
  /** previous frame pointer coords */
31699
31699
  __publicField(this, "previousPointerMoveCoords", null);
31700
31700
  __publicField(this, "lastViewportPosition", { x: 0, y: 0 });
31701
- __publicField(this, "animationFrameHandler", new AnimationFrameHandler());
31702
- __publicField(this, "laserTrails", new LaserTrails(this.animationFrameHandler, this));
31703
- __publicField(this, "eraserTrail", new EraserTrail(this.animationFrameHandler, this));
31704
- __publicField(this, "lassoTrail", new LassoTrail(this.animationFrameHandler, this));
31701
+ __publicField(this, "laserTrails", new LaserTrails(this));
31702
+ __publicField(this, "eraserTrail", new EraserTrail(this));
31703
+ __publicField(this, "lassoTrail", new LassoTrail(this));
31705
31704
  __publicField(this, "onChangeEmitter", new Emitter2());
31706
31705
  __publicField(this, "onPointerDownEmitter", new Emitter2());
31707
31706
  __publicField(this, "onPointerUpEmitter", new Emitter2());
@@ -31710,8 +31709,8 @@ var App = class _App extends React40.Component {
31710
31709
  __publicField(this, "missingPointerEventCleanupEmitter", new Emitter2());
31711
31710
  __publicField(this, "onRemoveEventListenersEmitter", new Emitter2());
31712
31711
  __publicField(this, "api");
31713
- __publicField(this, "addImageElementsToScene", async (imageFiles, sceneX, sceneY) => {
31714
- await this.insertImages(imageFiles, sceneX, sceneY);
31712
+ __publicField(this, "addImageElementsToScene", async (imageFiles, sceneX, sceneY, options) => {
31713
+ await this.insertImages(imageFiles, sceneX, sceneY, options);
31715
31714
  });
31716
31715
  __publicField(this, "updateEditorAtom", (atom2, ...args) => {
31717
31716
  const result = editorJotaiStore.set(atom2, ...args);
@@ -32902,6 +32901,7 @@ var App = class _App extends React40.Component {
32902
32901
  this.scene.replaceAllElements(elements);
32903
32902
  }
32904
32903
  if (collaborators) {
32904
+ this.laserTrails.updateCollabTrails(collaborators);
32905
32905
  this.setState({ collaborators });
32906
32906
  }
32907
32907
  }
@@ -36022,9 +36022,10 @@ var App = class _App extends React40.Component {
36022
36022
  throw new Error(t("errors.svgImageInsertError"));
36023
36023
  }
36024
36024
  } else if (fileNeedsResizing) {
36025
+ const { maxWidthOrHeight } = this.props.imageOptions;
36025
36026
  try {
36026
36027
  imageFile = await this.props.compressImageFile(imageFile, {
36027
- maxWidthOrHeight: DEFAULT_MAX_IMAGE_WIDTH_OR_HEIGHT
36028
+ maxWidthOrHeight
36028
36029
  });
36029
36030
  console.info("Excalidraw: image resized");
36030
36031
  } catch (error) {
@@ -36034,10 +36035,11 @@ var App = class _App extends React40.Component {
36034
36035
  );
36035
36036
  }
36036
36037
  }
36037
- if (imageFile.size > MAX_ALLOWED_FILE_BYTES) {
36038
+ const { maxFileSizeBytes } = this.props.imageOptions;
36039
+ if (imageFile.size > maxFileSizeBytes) {
36038
36040
  throw new Error(
36039
36041
  t("errors.fileTooBig", {
36040
- maxSize: `${Math.trunc(MAX_ALLOWED_FILE_BYTES / 1024 / 1024)}MB`
36042
+ maxSize: `${Math.trunc(maxFileSizeBytes / 1024 / 1024)}MB`
36041
36043
  })
36042
36044
  );
36043
36045
  }
@@ -36236,7 +36238,8 @@ var App = class _App extends React40.Component {
36236
36238
  );
36237
36239
  }
36238
36240
  });
36239
- __publicField(this, "insertImages", async (imageFiles, sceneX, sceneY) => {
36241
+ __publicField(this, "insertImages", async (imageFiles, sceneX, sceneY, options) => {
36242
+ const waitFor = options?.waitFor ?? "inserted";
36240
36243
  const gridPadding = 50 / this.state.zoom.value;
36241
36244
  const placeholders = positionElementsOnGrid(
36242
36245
  imageFiles.map(() => this.newImagePlaceholder({ sceneX, sceneY })),
@@ -36279,8 +36282,17 @@ var App = class _App extends React40.Component {
36279
36282
  elements: nextElements,
36280
36283
  captureUpdate: CaptureUpdateAction41.IMMEDIATELY
36281
36284
  });
36282
- this.setState({}, () => {
36283
- this.actionManager.executeAction(actionFinalize);
36285
+ await new Promise((resolve) => {
36286
+ this.setState({}, () => {
36287
+ this.actionManager.executeAction(actionFinalize);
36288
+ if (waitFor === "painted") {
36289
+ requestAnimationFrame(() => {
36290
+ requestAnimationFrame(() => resolve());
36291
+ });
36292
+ return;
36293
+ }
36294
+ resolve();
36295
+ });
36284
36296
  });
36285
36297
  });
36286
36298
  __publicField(this, "handleAppOnDrop", async (event) => {
@@ -36349,12 +36361,7 @@ var App = class _App extends React40.Component {
36349
36361
  const elements = this.scene.getElementsIncludingDeleted();
36350
36362
  let ret;
36351
36363
  try {
36352
- ret = await loadFromBlob(
36353
- file2,
36354
- this.state,
36355
- elements,
36356
- fileHandle
36357
- );
36364
+ ret = await loadFromBlob(file2, this.state, elements, fileHandle);
36358
36365
  } catch (error) {
36359
36366
  const imageSceneDataError = error instanceof ImageSceneDataError;
36360
36367
  if (imageSceneDataError && error.code === "IMAGE_NOT_CONTAINS_SCENE_DATA" && !this.isToolSupported("image")) {
@@ -41206,7 +41213,8 @@ var ExcalidrawBase = (props) => {
41206
41213
  wheelZoomsOnDefault,
41207
41214
  strokeColorTopPicks,
41208
41215
  backgroundColorTopPicks,
41209
- renderScrollbars
41216
+ renderScrollbars,
41217
+ imageOptions
41210
41218
  } = props;
41211
41219
  const canvasActions = props.UIOptions?.canvasActions;
41212
41220
  const UIOptions = {
@@ -41225,6 +41233,10 @@ var ExcalidrawBase = (props) => {
41225
41233
  if (UIOptions.canvasActions.toggleTheme === null && typeof theme === "undefined") {
41226
41234
  UIOptions.canvasActions.toggleTheme = true;
41227
41235
  }
41236
+ const normalizedImageOptions = {
41237
+ maxFileSizeBytes: imageOptions?.maxFileSizeBytes ?? DEFAULT_IMAGE_OPTIONS.maxFileSizeBytes,
41238
+ maxWidthOrHeight: imageOptions?.maxWidthOrHeight ?? DEFAULT_IMAGE_OPTIONS.maxWidthOrHeight
41239
+ };
41228
41240
  const setExcalidrawAPI = useContext4(ExcalidrawAPISetContext);
41229
41241
  const onExcalidrawAPIRef = useRef31(onExcalidrawAPI);
41230
41242
  onExcalidrawAPIRef.current = onExcalidrawAPI;
@@ -41296,6 +41308,7 @@ var ExcalidrawBase = (props) => {
41296
41308
  strokeColorTopPicks,
41297
41309
  backgroundColorTopPicks,
41298
41310
  renderScrollbars,
41311
+ imageOptions: normalizedImageOptions,
41299
41312
  children
41300
41313
  }
41301
41314
  ) }) });
@@ -41307,11 +41320,13 @@ var areEqual5 = (prevProps, nextProps) => {
41307
41320
  const {
41308
41321
  initialData: prevInitialData,
41309
41322
  UIOptions: prevUIOptions = {},
41323
+ imageOptions: prevImageOptions,
41310
41324
  ...prev
41311
41325
  } = prevProps;
41312
41326
  const {
41313
41327
  initialData: nextInitialData,
41314
41328
  UIOptions: nextUIOptions = {},
41329
+ imageOptions: nextImageOptions,
41315
41330
  ...next
41316
41331
  } = nextProps;
41317
41332
  const prevUIOptionsKeys = Object.keys(prevUIOptions);
@@ -41336,7 +41351,8 @@ var areEqual5 = (prevProps, nextProps) => {
41336
41351
  }
41337
41352
  return prevUIOptions[key] === nextUIOptions[key];
41338
41353
  });
41339
- return isUIOptionsSame && isShallowEqual9(prev, next);
41354
+ const isImageOptionsSame = (prevImageOptions?.maxWidthOrHeight ?? DEFAULT_IMAGE_OPTIONS.maxWidthOrHeight) === (nextImageOptions?.maxWidthOrHeight ?? DEFAULT_IMAGE_OPTIONS.maxWidthOrHeight) && (prevImageOptions?.maxFileSizeBytes ?? DEFAULT_IMAGE_OPTIONS.maxFileSizeBytes) === (nextImageOptions?.maxFileSizeBytes ?? DEFAULT_IMAGE_OPTIONS.maxFileSizeBytes);
41355
+ return isUIOptionsSame && isImageOptionsSame && isShallowEqual9(prev, next);
41340
41356
  };
41341
41357
  var Excalidraw = React42.memo(ExcalidrawBase, areEqual5);
41342
41358
  Excalidraw.displayName = "Excalidraw";