@excalidraw/excalidraw 0.18.0-b16b6f8fd → 0.18.0-b9d27d3

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 (37) hide show
  1. package/dist/dev/{chunk-OKO5QCIZ.js → chunk-CP5DND7P.js} +2 -2
  2. package/dist/dev/{chunk-OKO5QCIZ.js.map → chunk-CP5DND7P.js.map} +1 -1
  3. package/dist/dev/{chunk-EOSXEDPQ.js → chunk-WWDIUJ2Q.js} +34 -30
  4. package/dist/dev/chunk-WWDIUJ2Q.js.map +7 -0
  5. package/dist/dev/data/{image-LZHZW6U3.js → image-VTYIFRQE.js} +3 -3
  6. package/dist/dev/index.js +956 -736
  7. package/dist/dev/index.js.map +3 -3
  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-FBK55PRF.js → chunk-A66AFZZU.js} +1 -1
  11. package/dist/prod/{chunk-PXWC4GXH.js → chunk-VTWWEYSQ.js} +3 -3
  12. package/dist/prod/data/image-YQ6UXXDA.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 +12 -3
  17. package/dist/types/element/src/Scene.d.ts +6 -2
  18. package/dist/types/element/src/bounds.d.ts +1 -1
  19. package/dist/types/element/src/delta.d.ts +16 -4
  20. package/dist/types/element/src/index.d.ts +1 -0
  21. package/dist/types/element/src/positionElementsOnGrid.d.ts +2 -0
  22. package/dist/types/element/src/store.d.ts +6 -1
  23. package/dist/types/element/src/textElement.d.ts +1 -1
  24. package/dist/types/excalidraw/actions/actionCanvas.d.ts +15 -14
  25. package/dist/types/excalidraw/clipboard.d.ts +62 -1
  26. package/dist/types/excalidraw/components/App.d.ts +11 -8
  27. package/dist/types/excalidraw/components/shapes.d.ts +129 -1
  28. package/dist/types/excalidraw/data/blob.d.ts +1 -5
  29. package/dist/types/excalidraw/data/reconcile.d.ts +1 -0
  30. package/dist/types/excalidraw/data/restore.d.ts +6 -1
  31. package/dist/types/excalidraw/index.d.ts +1 -1
  32. package/dist/types/excalidraw/types.d.ts +7 -2
  33. package/history.ts +1 -1
  34. package/package.json +5 -5
  35. package/dist/dev/chunk-EOSXEDPQ.js.map +0 -7
  36. package/dist/prod/data/image-LFNJBNDB.js +0 -1
  37. /package/dist/dev/data/{image-LZHZW6U3.js.map → image-VTYIFRQE.js.map} +0 -0
package/dist/dev/index.js CHANGED
@@ -28,7 +28,7 @@ import {
28
28
  getDefaultAppState,
29
29
  getElementsWithinSelection,
30
30
  getExportSize,
31
- getFileFromEvent,
31
+ getFileHandle,
32
32
  getFileHandleType,
33
33
  getLinkHandleFromCoords,
34
34
  getNormalizedCanvasDimensions,
@@ -60,6 +60,7 @@ import {
60
60
  resizeImageFile,
61
61
  restore,
62
62
  restoreAppState,
63
+ restoreElement,
63
64
  restoreElements,
64
65
  restoreLibraryItems,
65
66
  saveAsJSON,
@@ -68,10 +69,10 @@ import {
68
69
  serializeLibraryAsJSON,
69
70
  strokeEllipseWithRotation,
70
71
  strokeRectWithRotation
71
- } from "./chunk-EOSXEDPQ.js";
72
+ } from "./chunk-WWDIUJ2Q.js";
72
73
  import {
73
74
  define_import_meta_env_default
74
- } from "./chunk-OKO5QCIZ.js";
75
+ } from "./chunk-CP5DND7P.js";
75
76
  import {
76
77
  en_default
77
78
  } from "./chunk-QF5FRM6O.js";
@@ -97,10 +98,10 @@ import rough3 from "roughjs/bin/rough";
97
98
  import { nanoid } from "nanoid";
98
99
  import {
99
100
  clamp as clamp7,
100
- pointFrom as pointFrom28,
101
+ pointFrom as pointFrom29,
101
102
  pointDistance as pointDistance8,
102
103
  vector as vector3,
103
- pointRotateRads as pointRotateRads16,
104
+ pointRotateRads as pointRotateRads17,
104
105
  vectorScale as vectorScale7,
105
106
  vectorFromPoint as vectorFromPoint9,
106
107
  vectorSubtract as vectorSubtract2,
@@ -122,14 +123,14 @@ import {
122
123
  DRAGGING_THRESHOLD as DRAGGING_THRESHOLD2,
123
124
  ELEMENT_SHIFT_TRANSLATE_AMOUNT,
124
125
  ELEMENT_TRANSLATE_AMOUNT,
125
- EVENT as EVENT13,
126
+ EVENT as EVENT14,
126
127
  FRAME_STYLE as FRAME_STYLE4,
127
128
  IMAGE_MIME_TYPES as IMAGE_MIME_TYPES2,
128
129
  IMAGE_RENDER_TIMEOUT,
129
130
  isBrave,
130
131
  LINE_CONFIRM_THRESHOLD as LINE_CONFIRM_THRESHOLD2,
131
132
  MAX_ALLOWED_FILE_BYTES,
132
- MIME_TYPES as MIME_TYPES8,
133
+ MIME_TYPES as MIME_TYPES9,
133
134
  MQ_MAX_HEIGHT_LANDSCAPE,
134
135
  MQ_MAX_WIDTH_LANDSCAPE,
135
136
  MQ_MAX_WIDTH_PORTRAIT,
@@ -188,7 +189,9 @@ import {
188
189
  randomInteger as randomInteger4,
189
190
  CLASSES as CLASSES7,
190
191
  Emitter as Emitter3,
191
- MINIMUM_ARROW_SIZE
192
+ isMobile,
193
+ MINIMUM_ARROW_SIZE,
194
+ DOUBLE_TAP_POSITION_THRESHOLD
192
195
  } from "@excalidraw/common";
193
196
  import {
194
197
  getObservedAppState,
@@ -203,7 +206,7 @@ import {
203
206
  updateBoundElements as updateBoundElements3,
204
207
  getSuggestedBindingsForArrows,
205
208
  LinearElementEditor as LinearElementEditor12,
206
- newElementWith as newElementWith10,
209
+ newElementWith as newElementWith11,
207
210
  newFrameElement as newFrameElement3,
208
211
  newFreeDrawElement,
209
212
  newEmbeddableElement,
@@ -318,7 +321,9 @@ import {
318
321
  CaptureUpdateAction as CaptureUpdateAction37,
319
322
  hitElementBoundingBox as hitElementBoundingBox2,
320
323
  isLineElement as isLineElement7,
321
- isSimpleArrow
324
+ isSimpleArrow,
325
+ StoreDelta as StoreDelta2,
326
+ positionElementsOnGrid
322
327
  } from "@excalidraw/element";
323
328
 
324
329
  // actions/actionDeleteSelected.tsx
@@ -3119,7 +3124,9 @@ var actionDeleteSelected = register({
3119
3124
  elements: nextElements,
3120
3125
  appState: {
3121
3126
  ...nextAppState,
3122
- activeTool: updateActiveTool(appState, { type: "selection" }),
3127
+ activeTool: updateActiveTool(appState, {
3128
+ type: app.defaultSelectionTool
3129
+ }),
3123
3130
  multiElement: null,
3124
3131
  activeEmbeddable: null,
3125
3132
  selectedLinearElement: null
@@ -7375,7 +7382,7 @@ var actionClearCanvas = register({
7375
7382
  gridModeEnabled: appState.gridModeEnabled,
7376
7383
  stats: appState.stats,
7377
7384
  pasteDialog: appState.pasteDialog,
7378
- activeTool: appState.activeTool.type === "image" ? { ...appState.activeTool, type: "selection" } : appState.activeTool
7385
+ activeTool: appState.activeTool.type === "image" ? { ...appState.activeTool, type: app.defaultSelectionTool } : appState.activeTool
7379
7386
  },
7380
7387
  captureUpdate: CaptureUpdateAction6.IMMEDIATELY
7381
7388
  };
@@ -7674,12 +7681,12 @@ var actionToggleEraserTool = register({
7674
7681
  name: "toggleEraserTool",
7675
7682
  label: "toolBar.eraser",
7676
7683
  trackEvent: { category: "toolbar" },
7677
- perform: (elements, appState) => {
7684
+ perform: (elements, appState, _, app) => {
7678
7685
  let activeTool;
7679
7686
  if (isEraserActive(appState)) {
7680
7687
  activeTool = updateActiveTool2(appState, {
7681
7688
  ...appState.activeTool.lastActiveTool || {
7682
- type: "selection"
7689
+ type: app.defaultSelectionTool
7683
7690
  },
7684
7691
  lastActiveToolBeforeEraser: null
7685
7692
  });
@@ -7707,6 +7714,9 @@ var actionToggleLassoTool = register({
7707
7714
  label: "toolBar.lasso",
7708
7715
  icon: LassoIcon,
7709
7716
  trackEvent: { category: "toolbar" },
7717
+ predicate: (elements, appState, props, app) => {
7718
+ return app.defaultSelectionTool !== "lasso";
7719
+ },
7710
7720
  perform: (elements, appState, _, app) => {
7711
7721
  let activeTool;
7712
7722
  if (appState.activeTool.type !== "lasso") {
@@ -7804,7 +7814,11 @@ import {
7804
7814
  bindOrUnbindLinearElement,
7805
7815
  isBindingEnabled
7806
7816
  } from "@excalidraw/element/binding";
7807
- import { isValidPolygon, LinearElementEditor as LinearElementEditor5 } from "@excalidraw/element";
7817
+ import {
7818
+ isValidPolygon,
7819
+ LinearElementEditor as LinearElementEditor5,
7820
+ newElementWith as newElementWith4
7821
+ } from "@excalidraw/element";
7808
7822
  import {
7809
7823
  isBindingElement,
7810
7824
  isFreeDrawElement,
@@ -7849,7 +7863,14 @@ var actionFinalize = register({
7849
7863
  if (linearElementEditor !== appState.selectedLinearElement) {
7850
7864
  let newElements2 = elements;
7851
7865
  if (element2 && isInvisiblySmallElement(element2)) {
7852
- newElements2 = newElements2.filter((el) => el.id !== element2.id);
7866
+ newElements2 = newElements2.map((el) => {
7867
+ if (el.id === element2.id) {
7868
+ return newElementWith4(el, {
7869
+ isDeleted: true
7870
+ });
7871
+ }
7872
+ return el;
7873
+ });
7853
7874
  }
7854
7875
  return {
7855
7876
  elements: newElements2,
@@ -7882,7 +7903,12 @@ var actionFinalize = register({
7882
7903
  });
7883
7904
  }
7884
7905
  return {
7885
- elements: element2.points.length < 2 || isInvisiblySmallElement(element2) ? elements.filter((el) => el.id !== element2.id) : void 0,
7906
+ elements: element2.points.length < 2 || isInvisiblySmallElement(element2) ? elements.map((el) => {
7907
+ if (el.id === element2.id) {
7908
+ return newElementWith4(el, { isDeleted: true });
7909
+ }
7910
+ return el;
7911
+ }) : void 0,
7886
7912
  appState: {
7887
7913
  ...appState,
7888
7914
  cursorButton: "up",
@@ -7924,7 +7950,12 @@ var actionFinalize = register({
7924
7950
  }
7925
7951
  }
7926
7952
  if (element && isInvisiblySmallElement(element)) {
7927
- newElements = newElements.filter((el) => el.id !== element.id);
7953
+ newElements = newElements.map((el) => {
7954
+ if (el.id === element?.id) {
7955
+ return newElementWith4(el, { isDeleted: true });
7956
+ }
7957
+ return el;
7958
+ });
7928
7959
  }
7929
7960
  if (isLinearElement3(element) || isFreeDrawElement(element)) {
7930
7961
  const isLoop = isPathALoop(element.points, appState.zoom.value);
@@ -7969,13 +8000,13 @@ var actionFinalize = register({
7969
8000
  if (appState.activeTool.type === "eraser") {
7970
8001
  activeTool = updateActiveTool4(appState, {
7971
8002
  ...appState.activeTool.lastActiveTool || {
7972
- type: "selection"
8003
+ type: app.defaultSelectionTool
7973
8004
  },
7974
8005
  lastActiveToolBeforeEraser: null
7975
8006
  });
7976
8007
  } else {
7977
8008
  activeTool = updateActiveTool4(appState, {
7978
- type: "selection"
8009
+ type: app.defaultSelectionTool
7979
8010
  });
7980
8011
  }
7981
8012
  return {
@@ -8156,7 +8187,8 @@ import {
8156
8187
  MIME_TYPES as MIME_TYPES2,
8157
8188
  arrayToMap as arrayToMap5,
8158
8189
  isMemberOf,
8159
- isPromiseLike as isPromiseLike2
8190
+ isPromiseLike as isPromiseLike2,
8191
+ EVENT as EVENT5
8160
8192
  } from "@excalidraw/common";
8161
8193
  import { mutateElement } from "@excalidraw/element";
8162
8194
  import { deepCopyElement } from "@excalidraw/element";
@@ -8535,7 +8567,7 @@ var createPasteEvent = ({
8535
8567
  if (!types && !files) {
8536
8568
  console.warn("createPasteEvent: no types or files provided");
8537
8569
  }
8538
- const event = new ClipboardEvent("paste", {
8570
+ const event = new ClipboardEvent(EVENT5.PASTE, {
8539
8571
  clipboardData: new DataTransfer()
8540
8572
  });
8541
8573
  if (types) {
@@ -8543,10 +8575,11 @@ var createPasteEvent = ({
8543
8575
  if (typeof value !== "string") {
8544
8576
  files = files || [];
8545
8577
  files.push(value);
8578
+ event.clipboardData?.items.add(value);
8546
8579
  continue;
8547
8580
  }
8548
8581
  try {
8549
- event.clipboardData?.setData(type, value);
8582
+ event.clipboardData?.items.add(value, type);
8550
8583
  if (event.clipboardData?.getData(type) !== value) {
8551
8584
  throw new Error(`Failed to set "${type}" as clipboardData item`);
8552
8585
  }
@@ -8644,11 +8677,8 @@ function parseHTMLTree(el) {
8644
8677
  }
8645
8678
  return result;
8646
8679
  }
8647
- var maybeParseHTMLPaste = (event) => {
8648
- const html = event.clipboardData?.getData(MIME_TYPES2.html);
8649
- if (!html) {
8650
- return null;
8651
- }
8680
+ var maybeParseHTMLDataItem = (dataItem) => {
8681
+ const html = dataItem.value;
8652
8682
  try {
8653
8683
  const doc = new DOMParser().parseFromString(html, MIME_TYPES2.html);
8654
8684
  const content = parseHTMLTree(doc.body);
@@ -8721,27 +8751,85 @@ var readSystemClipboard = async () => {
8721
8751
  }
8722
8752
  return types;
8723
8753
  };
8724
- var parseClipboardEventTextData = async (event, isPlainPaste = false) => {
8754
+ var parseClipboardEventTextData = async (dataList, isPlainPaste = false) => {
8725
8755
  try {
8726
- const mixedContent = !isPlainPaste && event && maybeParseHTMLPaste(event);
8756
+ const htmlItem = dataList.findByType(MIME_TYPES2.html);
8757
+ const mixedContent = !isPlainPaste && htmlItem && maybeParseHTMLDataItem(htmlItem);
8727
8758
  if (mixedContent) {
8728
8759
  if (mixedContent.value.every((item) => item.type === "text")) {
8729
8760
  return {
8730
8761
  type: "text",
8731
- value: event.clipboardData?.getData(MIME_TYPES2.text) || mixedContent.value.map((item) => item.value).join("\n").trim()
8762
+ value: dataList.getData(MIME_TYPES2.text) ?? mixedContent.value.map((item) => item.value).join("\n").trim()
8732
8763
  };
8733
8764
  }
8734
8765
  return mixedContent;
8735
8766
  }
8736
- const text = event.clipboardData?.getData(MIME_TYPES2.text);
8737
- return { type: "text", value: (text || "").trim() };
8767
+ return {
8768
+ type: "text",
8769
+ value: (dataList.getData(MIME_TYPES2.text) || "").trim()
8770
+ };
8738
8771
  } catch {
8739
8772
  return { type: "text", value: "" };
8740
8773
  }
8741
8774
  };
8742
- var parseClipboard = async (event, isPlainPaste = false) => {
8775
+ var findDataTransferItemType = function(type) {
8776
+ return this.find(
8777
+ (item) => item.type === type
8778
+ ) || null;
8779
+ };
8780
+ var getDataTransferItemData = function(type) {
8781
+ const item = this.find(
8782
+ (item2) => item2.type === type
8783
+ );
8784
+ return item?.value ?? null;
8785
+ };
8786
+ var getDataTransferFiles = function() {
8787
+ return this.filter(
8788
+ (item) => item.kind === "file"
8789
+ );
8790
+ };
8791
+ var parseDataTransferEvent = async (event) => {
8792
+ let items = void 0;
8793
+ if (isClipboardEvent(event)) {
8794
+ items = event.clipboardData?.items;
8795
+ } else {
8796
+ const dragEvent = event;
8797
+ items = dragEvent.dataTransfer?.items;
8798
+ }
8799
+ const dataItems = (await Promise.all(
8800
+ Array.from(items || []).map(
8801
+ async (item) => {
8802
+ if (item.kind === "file") {
8803
+ const file2 = item.getAsFile();
8804
+ if (file2) {
8805
+ const fileHandle = await getFileHandle(item);
8806
+ return { type: file2.type, kind: "file", file: file2, fileHandle };
8807
+ }
8808
+ } else if (item.kind === "string") {
8809
+ const { type } = item;
8810
+ let value;
8811
+ if ("clipboardData" in event && event.clipboardData) {
8812
+ value = event.clipboardData?.getData(type);
8813
+ } else {
8814
+ value = await new Promise((resolve) => {
8815
+ item.getAsString((str) => resolve(str));
8816
+ });
8817
+ }
8818
+ return { type, kind: "string", value };
8819
+ }
8820
+ return null;
8821
+ }
8822
+ )
8823
+ )).filter((data) => data != null);
8824
+ return Object.assign(dataItems, {
8825
+ findByType: findDataTransferItemType,
8826
+ getData: getDataTransferItemData,
8827
+ getFiles: getDataTransferFiles
8828
+ });
8829
+ };
8830
+ var parseClipboard = async (dataList, isPlainPaste = false) => {
8743
8831
  const parsedEventData = await parseClipboardEventTextData(
8744
- event,
8832
+ dataList,
8745
8833
  isPlainPaste
8746
8834
  );
8747
8835
  if (parsedEventData.type === "mixedContent") {
@@ -8843,6 +8931,9 @@ var copyTextViaExecCommand = (text) => {
8843
8931
  textarea.remove();
8844
8932
  return success;
8845
8933
  };
8934
+ var isClipboardEvent = (event) => {
8935
+ return event.type === EVENT5.PASTE || event.type === EVENT5.COPY || event.type === EVENT5.CUT;
8936
+ };
8846
8937
 
8847
8938
  // data/index.ts
8848
8939
  var prepareElementsForExport = (elements, { selectedElementIds }, exportSelectionOnly) => {
@@ -8936,7 +9027,7 @@ var exportCanvas = async (type, elements, appState, files, {
8936
9027
  let blob = canvasToBlob(tempCanvas);
8937
9028
  if (appState.exportEmbedScene) {
8938
9029
  blob = blob.then(
8939
- (blob2) => import("./data/image-LZHZW6U3.js").then(
9030
+ (blob2) => import("./data/image-VTYIFRQE.js").then(
8940
9031
  ({ encodePngMetadata: encodePngMetadata2 }) => encodePngMetadata2({
8941
9032
  blob: blob2,
8942
9033
  metadata: serializeAsJSON(elements, appState, files, "local")
@@ -9277,7 +9368,7 @@ import {
9277
9368
  KEYS as KEYS16,
9278
9369
  getLineHeight as getLineHeight2
9279
9370
  } from "@excalidraw/common";
9280
- import { newElementWith as newElementWith4 } from "@excalidraw/element";
9371
+ import { newElementWith as newElementWith5 } from "@excalidraw/element";
9281
9372
  import {
9282
9373
  hasBoundTextElement,
9283
9374
  canApplyRoundnessTypeToElement,
@@ -9348,7 +9439,7 @@ var actionPasteStyles = register({
9348
9439
  if (!elementStylesToCopyFrom) {
9349
9440
  return element;
9350
9441
  }
9351
- let newElement6 = newElementWith4(element, {
9442
+ let newElement6 = newElementWith5(element, {
9352
9443
  backgroundColor: elementStylesToCopyFrom?.backgroundColor,
9353
9444
  strokeWidth: elementStylesToCopyFrom?.strokeWidth,
9354
9445
  strokeColor: elementStylesToCopyFrom?.strokeColor,
@@ -9364,7 +9455,7 @@ var actionPasteStyles = register({
9364
9455
  if (isTextElement3(newElement6)) {
9365
9456
  const fontSize = elementStylesToCopyFrom.fontSize || DEFAULT_FONT_SIZE3;
9366
9457
  const fontFamily = elementStylesToCopyFrom.fontFamily || DEFAULT_FONT_FAMILY3;
9367
- newElement6 = newElementWith4(newElement6, {
9458
+ newElement6 = newElementWith5(newElement6, {
9368
9459
  fontSize,
9369
9460
  fontFamily,
9370
9461
  textAlign: elementStylesToCopyFrom.textAlign || DEFAULT_TEXT_ALIGN,
@@ -9379,13 +9470,13 @@ var actionPasteStyles = register({
9379
9470
  redrawTextBoundingBox2(newElement6, container, app.scene);
9380
9471
  }
9381
9472
  if (newElement6.type === "arrow" && isArrowElement2(elementStylesToCopyFrom)) {
9382
- newElement6 = newElementWith4(newElement6, {
9473
+ newElement6 = newElementWith5(newElement6, {
9383
9474
  startArrowhead: elementStylesToCopyFrom.startArrowhead,
9384
9475
  endArrowhead: elementStylesToCopyFrom.endArrowhead
9385
9476
  });
9386
9477
  }
9387
9478
  if (isFrameLikeElement4(element)) {
9388
- newElement6 = newElementWith4(newElement6, {
9479
+ newElement6 = newElementWith5(newElement6, {
9389
9480
  roundness: null,
9390
9481
  backgroundColor: "transparent"
9391
9482
  });
@@ -9479,7 +9570,7 @@ var actionShortcuts = register({
9479
9570
 
9480
9571
  // actions/actionGroup.tsx
9481
9572
  import { getNonDeletedElements as getNonDeletedElements9 } from "@excalidraw/element";
9482
- import { newElementWith as newElementWith5 } from "@excalidraw/element";
9573
+ import { newElementWith as newElementWith6 } from "@excalidraw/element";
9483
9574
  import { isBoundToContainer as isBoundToContainer3 } from "@excalidraw/element";
9484
9575
  import {
9485
9576
  frameAndChildrenSelectedTogether,
@@ -9583,7 +9674,7 @@ var actionGroup = register({
9583
9674
  if (!selectElementIds.get(element.id)) {
9584
9675
  return element;
9585
9676
  }
9586
- return newElementWith5(element, {
9677
+ return newElementWith6(element, {
9587
9678
  groupIds: addToGroup(
9588
9679
  element.groupIds,
9589
9680
  newGroupId,
@@ -9660,7 +9751,7 @@ var actionUngroup = register({
9660
9751
  if (nextGroupIds.length === element.groupIds.length) {
9661
9752
  return element;
9662
9753
  }
9663
- return newElementWith5(element, {
9754
+ return newElementWith6(element, {
9664
9755
  groupIds: nextGroupIds
9665
9756
  });
9666
9757
  });
@@ -10459,7 +10550,7 @@ import {
10459
10550
  isBindingEnabled as isBindingEnabled2
10460
10551
  } from "@excalidraw/element";
10461
10552
  import { getCommonBoundingBox } from "@excalidraw/element";
10462
- import { newElementWith as newElementWith6 } from "@excalidraw/element";
10553
+ import { newElementWith as newElementWith7 } from "@excalidraw/element";
10463
10554
  import { deepCopyElement as deepCopyElement3 } from "@excalidraw/element";
10464
10555
  import { resizeMultipleElements } from "@excalidraw/element";
10465
10556
  import {
@@ -10545,7 +10636,7 @@ var flipElements = (selectedElements, elementsMap, appState, flipDirection, app)
10545
10636
  )) {
10546
10637
  return selectedElements.map((element) => {
10547
10638
  const _element = element;
10548
- return newElementWith6(_element, {
10639
+ return newElementWith7(_element, {
10549
10640
  startArrowhead: _element.endArrowhead,
10550
10641
  endArrowhead: _element.startArrowhead
10551
10642
  });
@@ -11222,7 +11313,7 @@ import {
11222
11313
  useRef as useRef12,
11223
11314
  useState as useState9
11224
11315
  } from "react";
11225
- import { EVENT as EVENT5, HYPERLINK_TOOLTIP_DELAY, KEYS as KEYS27 } from "@excalidraw/common";
11316
+ import { EVENT as EVENT6, HYPERLINK_TOOLTIP_DELAY, KEYS as KEYS27 } from "@excalidraw/common";
11226
11317
  import { getElementAbsoluteCoords } from "@excalidraw/element";
11227
11318
  import { hitElementBoundingBox } from "@excalidraw/element";
11228
11319
  import { isElementLink } from "@excalidraw/element";
@@ -11353,9 +11444,9 @@ var Hyperlink = ({
11353
11444
  }, AUTO_HIDE_TIMEOUT);
11354
11445
  }
11355
11446
  };
11356
- window.addEventListener(EVENT5.POINTER_MOVE, handlePointerMove, false);
11447
+ window.addEventListener(EVENT6.POINTER_MOVE, handlePointerMove, false);
11357
11448
  return () => {
11358
- window.removeEventListener(EVENT5.POINTER_MOVE, handlePointerMove, false);
11449
+ window.removeEventListener(EVENT6.POINTER_MOVE, handlePointerMove, false);
11359
11450
  if (timeoutId) {
11360
11451
  clearTimeout(timeoutId);
11361
11452
  }
@@ -11414,7 +11505,7 @@ var Hyperlink = ({
11414
11505
  onClick: (event) => {
11415
11506
  if (element.link && onLinkOpen) {
11416
11507
  const customEvent = wrapEvent(
11417
- EVENT5.EXCALIDRAW_LINK,
11508
+ EVENT6.EXCALIDRAW_LINK,
11418
11509
  event.nativeEvent
11419
11510
  );
11420
11511
  onLinkOpen(
@@ -11616,7 +11707,7 @@ var actionLink = register({
11616
11707
  import { KEYS as KEYS29, arrayToMap as arrayToMap11, randomId as randomId4 } from "@excalidraw/common";
11617
11708
  import {
11618
11709
  elementsAreInSameGroup,
11619
- newElementWith as newElementWith7,
11710
+ newElementWith as newElementWith8,
11620
11711
  selectGroupsFromGivenElements
11621
11712
  } from "@excalidraw/element";
11622
11713
  import { CaptureUpdateAction as CaptureUpdateAction25 } from "@excalidraw/element";
@@ -11677,7 +11768,7 @@ var actionToggleElementLock = register({
11677
11768
  (groupId) => !appState.lockedMultiSelections[groupId]
11678
11769
  );
11679
11770
  }
11680
- return newElementWith7(element, {
11771
+ return newElementWith8(element, {
11681
11772
  locked: nextLockState,
11682
11773
  // do not recreate the array unncessarily
11683
11774
  groupIds: nextGroupIds.length !== element.groupIds.length ? nextGroupIds : element.groupIds
@@ -11726,7 +11817,7 @@ var actionUnlockAllElements = register({
11726
11817
  const nextGroupIds = element.groupIds.filter(
11727
11818
  (gid) => !appState.lockedMultiSelections[gid]
11728
11819
  );
11729
- return newElementWith7(element, {
11820
+ return newElementWith8(element, {
11730
11821
  locked: false,
11731
11822
  groupIds: (
11732
11823
  // do not recreate the array unncessarily
@@ -11778,7 +11869,7 @@ import fuzzy from "fuzzy";
11778
11869
  import { useEffect as useEffect27, useRef as useRef23, useState as useState22 } from "react";
11779
11870
  import {
11780
11871
  DEFAULT_SIDEBAR as DEFAULT_SIDEBAR2,
11781
- EVENT as EVENT8,
11872
+ EVENT as EVENT9,
11782
11873
  KEYS as KEYS35,
11783
11874
  capitalizeString as capitalizeString2,
11784
11875
  getShortcutKey as getShortcutKey11,
@@ -12813,7 +12904,7 @@ import {
12813
12904
  URL_HASH_KEYS,
12814
12905
  URL_QUERY_KEYS,
12815
12906
  APP_NAME,
12816
- EVENT as EVENT6,
12907
+ EVENT as EVENT7,
12817
12908
  DEFAULT_SIDEBAR,
12818
12909
  LIBRARY_SIDEBAR_TAB,
12819
12910
  arrayToMap as arrayToMap12,
@@ -12842,7 +12933,8 @@ var exportToCanvas2 = ({
12842
12933
  const { elements: restoredElements, appState: restoredAppState } = restore(
12843
12934
  { elements, appState },
12844
12935
  null,
12845
- null
12936
+ null,
12937
+ { deleteInvisibleElements: true }
12846
12938
  );
12847
12939
  const { exportBackground, viewBackgroundColor } = restoredAppState;
12848
12940
  return exportToCanvas(
@@ -12936,7 +13028,8 @@ var exportToSvg2 = async ({
12936
13028
  const { elements: restoredElements, appState: restoredAppState } = restore(
12937
13029
  { elements, appState },
12938
13030
  null,
12939
- null
13031
+ null,
13032
+ { deleteInvisibleElements: true }
12940
13033
  );
12941
13034
  const exportAppState = {
12942
13035
  ...restoredAppState,
@@ -13519,9 +13612,9 @@ var useHandleLibrary = (opts) => {
13519
13612
  isLibraryLoadedRef.current = true;
13520
13613
  });
13521
13614
  }
13522
- window.addEventListener(EVENT6.HASHCHANGE, onHashChange);
13615
+ window.addEventListener(EVENT7.HASHCHANGE, onHashChange);
13523
13616
  return () => {
13524
- window.removeEventListener(EVENT6.HASHCHANGE, onHashChange);
13617
+ window.removeEventListener(EVENT7.HASHCHANGE, onHashChange);
13525
13618
  };
13526
13619
  }, [
13527
13620
  // important this useEffect only depends on excalidrawAPI so it only reruns
@@ -13566,9 +13659,9 @@ var useHandleLibrary = (opts) => {
13566
13659
  preventUnload(event);
13567
13660
  }
13568
13661
  };
13569
- window.addEventListener(EVENT6.BEFORE_UNLOAD, onUnload);
13662
+ window.addEventListener(EVENT7.BEFORE_UNLOAD, onUnload);
13570
13663
  return () => {
13571
- window.removeEventListener(EVENT6.BEFORE_UNLOAD, onUnload);
13664
+ window.removeEventListener(EVENT7.BEFORE_UNLOAD, onUnload);
13572
13665
  unsubOnLibraryUpdate();
13573
13666
  lastSavedLibraryItemsHash = 0;
13574
13667
  librarySaveCounter = 0;
@@ -14353,7 +14446,7 @@ var PublishLibrary_default = PublishLibrary;
14353
14446
  // components/dropdownMenu/DropdownMenuContent.tsx
14354
14447
  import clsx23 from "clsx";
14355
14448
  import { useEffect as useEffect21, useRef as useRef16 } from "react";
14356
- import { EVENT as EVENT7, KEYS as KEYS30 } from "@excalidraw/common";
14449
+ import { EVENT as EVENT8, KEYS as KEYS30 } from "@excalidraw/common";
14357
14450
 
14358
14451
  // components/Stack.tsx
14359
14452
  import { forwardRef as forwardRef2 } from "react";
@@ -14427,9 +14520,9 @@ var MenuContent = ({
14427
14520
  // event handlers that were bound before this one
14428
14521
  capture: true
14429
14522
  };
14430
- document.addEventListener(EVENT7.KEYDOWN, onKeyDown, option);
14523
+ document.addEventListener(EVENT8.KEYDOWN, onKeyDown, option);
14431
14524
  return () => {
14432
- document.removeEventListener(EVENT7.KEYDOWN, onKeyDown, option);
14525
+ document.removeEventListener(EVENT8.KEYDOWN, onKeyDown, option);
14433
14526
  };
14434
14527
  }, [callbacksRef]);
14435
14528
  const classNames = clsx23(`dropdown-menu ${className}`, {
@@ -14893,7 +14986,7 @@ var LibraryUnit = memo(
14893
14986
  };
14894
14987
  }, [svg]);
14895
14988
  const [isHovered, setIsHovered] = useState15(false);
14896
- const isMobile = useDevice().editor.isMobile;
14989
+ const isMobile2 = useDevice().editor.isMobile;
14897
14990
  const adder = isPending && /* @__PURE__ */ jsx63("div", { className: "library-unit__adder", children: PlusIcon });
14898
14991
  return /* @__PURE__ */ jsxs33(
14899
14992
  "div",
@@ -14933,7 +15026,7 @@ var LibraryUnit = memo(
14933
15026
  }
14934
15027
  ),
14935
15028
  adder,
14936
- id && elements && (isHovered || isMobile || selected) && /* @__PURE__ */ jsx63(
15029
+ id && elements && (isHovered || isMobile2 || selected) && /* @__PURE__ */ jsx63(
14937
15030
  CheckboxItem,
14938
15031
  {
14939
15032
  checked: selected,
@@ -15766,8 +15859,20 @@ var SHAPES = [
15766
15859
  fillable: false
15767
15860
  }
15768
15861
  ];
15769
- var findShapeByKey = (key) => {
15770
- const shape = SHAPES.find((shape2, index) => {
15862
+ var getToolbarTools = (app) => {
15863
+ return app.defaultSelectionTool === "lasso" ? [
15864
+ {
15865
+ value: "lasso",
15866
+ icon: SelectionIcon,
15867
+ key: KEYS33.V,
15868
+ numericKey: KEYS33["1"],
15869
+ fillable: true
15870
+ },
15871
+ ...SHAPES.slice(1)
15872
+ ] : SHAPES;
15873
+ };
15874
+ var findShapeByKey = (key, app) => {
15875
+ const shape = getToolbarTools(app).find((shape2, index) => {
15771
15876
  return shape2.numericKey != null && key === shape2.numericKey.toString() || shape2.key && (typeof shape2.key === "string" ? shape2.key === key : shape2.key.includes(key));
15772
15877
  });
15773
15878
  return shape?.value || null;
@@ -15943,58 +16048,60 @@ var ShapesSwitcher = ({
15943
16048
  const [isExtraToolsMenuOpen, setIsExtraToolsMenuOpen] = useState21(false);
15944
16049
  const frameToolSelected = activeTool.type === "frame";
15945
16050
  const laserToolSelected = activeTool.type === "laser";
15946
- const lassoToolSelected = activeTool.type === "lasso";
16051
+ const lassoToolSelected = activeTool.type === "lasso" && app.defaultSelectionTool !== "lasso";
15947
16052
  const embeddableToolSelected = activeTool.type === "embeddable";
15948
16053
  const { TTDDialogTriggerTunnel } = useTunnels();
15949
16054
  return /* @__PURE__ */ jsxs39(Fragment11, { children: [
15950
- SHAPES.map(({ value, icon, key, numericKey, fillable }, index) => {
15951
- if (UIOptions.tools?.[value] === false) {
15952
- return null;
15953
- }
15954
- const label = t(`toolBar.${value}`);
15955
- const letter = key && capitalizeString(typeof key === "string" ? key : key[0]);
15956
- const shortcut = letter ? `${letter} ${t("helpDialog.or")} ${numericKey}` : `${numericKey}`;
15957
- return /* @__PURE__ */ jsx71(
15958
- ToolButton,
15959
- {
15960
- className: clsx31("Shape", { fillable }),
15961
- type: "radio",
15962
- icon,
15963
- checked: activeTool.type === value,
15964
- name: "editor-current-shape",
15965
- title: `${capitalizeString(label)} \u2014 ${shortcut}`,
15966
- keyBindingLabel: numericKey || letter,
15967
- "aria-label": capitalizeString(label),
15968
- "aria-keyshortcuts": shortcut,
15969
- "data-testid": `toolbar-${value}`,
15970
- onPointerDown: ({ pointerType }) => {
15971
- if (!appState.penDetected && pointerType === "pen") {
15972
- app.togglePenMode(true);
15973
- }
15974
- if (value === "selection") {
15975
- if (appState.activeTool.type === "selection") {
15976
- app.setActiveTool({ type: "lasso" });
16055
+ getToolbarTools(app).map(
16056
+ ({ value, icon, key, numericKey, fillable }, index) => {
16057
+ if (UIOptions.tools?.[value] === false) {
16058
+ return null;
16059
+ }
16060
+ const label = t(`toolBar.${value}`);
16061
+ const letter = key && capitalizeString(typeof key === "string" ? key : key[0]);
16062
+ const shortcut = letter ? `${letter} ${t("helpDialog.or")} ${numericKey}` : `${numericKey}`;
16063
+ return /* @__PURE__ */ jsx71(
16064
+ ToolButton,
16065
+ {
16066
+ className: clsx31("Shape", { fillable }),
16067
+ type: "radio",
16068
+ icon,
16069
+ checked: activeTool.type === value,
16070
+ name: "editor-current-shape",
16071
+ title: `${capitalizeString(label)} \u2014 ${shortcut}`,
16072
+ keyBindingLabel: numericKey || letter,
16073
+ "aria-label": capitalizeString(label),
16074
+ "aria-keyshortcuts": shortcut,
16075
+ "data-testid": `toolbar-${value}`,
16076
+ onPointerDown: ({ pointerType }) => {
16077
+ if (!appState.penDetected && pointerType === "pen") {
16078
+ app.togglePenMode(true);
16079
+ }
16080
+ if (value === "selection") {
16081
+ if (appState.activeTool.type === "selection") {
16082
+ app.setActiveTool({ type: "lasso" });
16083
+ } else {
16084
+ app.setActiveTool({ type: "selection" });
16085
+ }
16086
+ }
16087
+ },
16088
+ onChange: ({ pointerType }) => {
16089
+ if (appState.activeTool.type !== value) {
16090
+ trackEvent("toolbar", value, "ui");
16091
+ }
16092
+ if (value === "image") {
16093
+ app.setActiveTool({
16094
+ type: value
16095
+ });
15977
16096
  } else {
15978
- app.setActiveTool({ type: "selection" });
16097
+ app.setActiveTool({ type: value });
15979
16098
  }
15980
16099
  }
15981
16100
  },
15982
- onChange: ({ pointerType }) => {
15983
- if (appState.activeTool.type !== value) {
15984
- trackEvent("toolbar", value, "ui");
15985
- }
15986
- if (value === "image") {
15987
- app.setActiveTool({
15988
- type: value
15989
- });
15990
- } else {
15991
- app.setActiveTool({ type: value });
15992
- }
15993
- }
15994
- },
15995
- value
15996
- );
15997
- }),
16101
+ value
16102
+ );
16103
+ }
16104
+ ),
15998
16105
  /* @__PURE__ */ jsx71("div", { className: "App-toolbar__divider" }),
15999
16106
  /* @__PURE__ */ jsxs39(DropdownMenu_default, { open: isExtraToolsMenuOpen, children: [
16000
16107
  /* @__PURE__ */ jsx71(
@@ -16050,7 +16157,7 @@ var ShapesSwitcher = ({
16050
16157
  children: t("toolBar.laser")
16051
16158
  }
16052
16159
  ),
16053
- /* @__PURE__ */ jsx71(
16160
+ app.defaultSelectionTool !== "lasso" && /* @__PURE__ */ jsx71(
16054
16161
  DropdownMenu_default.Item,
16055
16162
  {
16056
16163
  onSelect: () => app.setActiveTool({ type: "lasso" }),
@@ -16243,10 +16350,10 @@ var CommandPalette = Object.assign(
16243
16350
  });
16244
16351
  }
16245
16352
  };
16246
- window.addEventListener(EVENT8.KEYDOWN, commandPaletteShortcut, {
16353
+ window.addEventListener(EVENT9.KEYDOWN, commandPaletteShortcut, {
16247
16354
  capture: true
16248
16355
  });
16249
- return () => window.removeEventListener(EVENT8.KEYDOWN, commandPaletteShortcut, {
16356
+ return () => window.removeEventListener(EVENT9.KEYDOWN, commandPaletteShortcut, {
16250
16357
  capture: true
16251
16358
  });
16252
16359
  }, [setAppState]);
@@ -16740,10 +16847,10 @@ function CommandPaletteInner({
16740
16847
  event.preventDefault();
16741
16848
  });
16742
16849
  useEffect27(() => {
16743
- window.addEventListener(EVENT8.KEYDOWN, handleKeyDown, {
16850
+ window.addEventListener(EVENT9.KEYDOWN, handleKeyDown, {
16744
16851
  capture: true
16745
16852
  });
16746
- return () => window.removeEventListener(EVENT8.KEYDOWN, handleKeyDown, {
16853
+ return () => window.removeEventListener(EVENT9.KEYDOWN, handleKeyDown, {
16747
16854
  capture: true
16748
16855
  });
16749
16856
  }, [handleKeyDown]);
@@ -16954,9 +17061,9 @@ var getCurvePathOps = (shape) => {
16954
17061
 
16955
17062
  // ../element/src/shape.ts
16956
17063
  import {
16957
- pointFrom as pointFrom17,
17064
+ pointFrom as pointFrom18,
16958
17065
  pointDistance as pointDistance7,
16959
- pointRotateRads as pointRotateRads11
17066
+ pointRotateRads as pointRotateRads12
16960
17067
  } from "@excalidraw/math";
16961
17068
  import {
16962
17069
  ROUGHNESS,
@@ -16996,17 +17103,17 @@ import {
16996
17103
  degreesToRadians,
16997
17104
  lineSegment as lineSegment5,
16998
17105
  pointDistance as pointDistance6,
16999
- pointFrom as pointFrom13,
17106
+ pointFrom as pointFrom14,
17000
17107
  pointFromArray as pointFromArray3,
17001
- pointRotateRads as pointRotateRads8
17108
+ pointRotateRads as pointRotateRads9
17002
17109
  } from "@excalidraw/math";
17003
17110
  import { pointsOnBezierCurves as pointsOnBezierCurves2 } from "points-on-curve";
17004
17111
 
17005
17112
  // ../element/src/linearElementEditor.ts
17006
17113
  import {
17007
17114
  pointCenter,
17008
- pointFrom as pointFrom12,
17009
- pointRotateRads as pointRotateRads7,
17115
+ pointFrom as pointFrom13,
17116
+ pointRotateRads as pointRotateRads8,
17010
17117
  pointsEqual as pointsEqual7,
17011
17118
  pointDistance as pointDistance5,
17012
17119
  vectorFromPoint as vectorFromPoint6,
@@ -17039,8 +17146,8 @@ import {
17039
17146
  } from "@excalidraw/common";
17040
17147
  import {
17041
17148
  lineSegment as lineSegment4,
17042
- pointFrom as pointFrom11,
17043
- pointRotateRads as pointRotateRads6,
17149
+ pointFrom as pointFrom12,
17150
+ pointRotateRads as pointRotateRads7,
17044
17151
  vectorFromPoint as vectorFromPoint5,
17045
17152
  pointDistanceSq,
17046
17153
  clamp as clamp3,
@@ -17061,9 +17168,9 @@ import {
17061
17168
  isPointWithinBounds,
17062
17169
  lineSegment as lineSegment3,
17063
17170
  lineSegmentIntersectionPoints,
17064
- pointFrom as pointFrom8,
17171
+ pointFrom as pointFrom9,
17065
17172
  pointFromVector as pointFromVector2,
17066
- pointRotateRads as pointRotateRads4,
17173
+ pointRotateRads as pointRotateRads5,
17067
17174
  pointsEqual as pointsEqual2,
17068
17175
  vectorFromPoint as vectorFromPoint2,
17069
17176
  vectorNormalize,
@@ -17160,6 +17267,7 @@ import {
17160
17267
  isProdEnv as isProdEnv2,
17161
17268
  invariant as invariant2
17162
17269
  } from "@excalidraw/common";
17270
+ import { pointFrom as pointFrom8, pointRotateRads as pointRotateRads3 } from "@excalidraw/math";
17163
17271
 
17164
17272
  // ../element/src/textMeasurements.ts
17165
17273
  import {
@@ -17179,16 +17287,16 @@ import { isDevEnv as isDevEnv4, isTestEnv as isTestEnv2 } from "@excalidraw/comm
17179
17287
  import {
17180
17288
  curvePointDistance,
17181
17289
  distanceToLineSegment,
17182
- pointRotateRads as pointRotateRads3
17290
+ pointRotateRads as pointRotateRads4
17183
17291
  } from "@excalidraw/math";
17184
17292
  import { ellipse, ellipseDistanceFromPoint } from "@excalidraw/math/ellipse";
17185
17293
 
17186
17294
  // ../element/src/heading.ts
17187
17295
  import { invariant as invariant3, isDevEnv as isDevEnv5, isTestEnv as isTestEnv3 } from "@excalidraw/common";
17188
17296
  import {
17189
- pointFrom as pointFrom9,
17297
+ pointFrom as pointFrom10,
17190
17298
  pointFromVector as pointFromVector3,
17191
- pointRotateRads as pointRotateRads5,
17299
+ pointRotateRads as pointRotateRads6,
17192
17300
  pointScaleFromOrigin,
17193
17301
  pointsEqual as pointsEqual3,
17194
17302
  triangleIncludesPoint,
@@ -17222,7 +17330,7 @@ var headingIsHorizontal = (a) => compareHeading(a, HEADING_RIGHT) || compareHead
17222
17330
  import {
17223
17331
  clamp as clamp2,
17224
17332
  pointDistance as pointDistance3,
17225
- pointFrom as pointFrom10,
17333
+ pointFrom as pointFrom11,
17226
17334
  pointScaleFromOrigin as pointScaleFromOrigin2,
17227
17335
  pointsEqual as pointsEqual4,
17228
17336
  pointTranslate,
@@ -17301,17 +17409,17 @@ var getArrowheadPoints = (element, shape, position, arrowhead) => {
17301
17409
  const index = position === "start" ? 1 : ops.length - 1;
17302
17410
  const data = ops[index].data;
17303
17411
  invariant7(data.length === 6, "Op data length is not 6");
17304
- const p3 = pointFrom13(data[4], data[5]);
17305
- const p2 = pointFrom13(data[2], data[3]);
17306
- const p1 = pointFrom13(data[0], data[1]);
17412
+ const p3 = pointFrom14(data[4], data[5]);
17413
+ const p2 = pointFrom14(data[2], data[3]);
17414
+ const p1 = pointFrom14(data[0], data[1]);
17307
17415
  const prevOp = ops[index - 1];
17308
- let p0 = pointFrom13(0, 0);
17416
+ let p0 = pointFrom14(0, 0);
17309
17417
  if (prevOp.op === "move") {
17310
17418
  const p = pointFromArray3(prevOp.data);
17311
17419
  invariant7(p != null, "Op data is not a point");
17312
17420
  p0 = p;
17313
17421
  } else if (prevOp.op === "bcurveTo") {
17314
- p0 = pointFrom13(prevOp.data[4], prevOp.data[5]);
17422
+ p0 = pointFrom14(prevOp.data[4], prevOp.data[5]);
17315
17423
  }
17316
17424
  const equation = (t2, idx) => Math.pow(1 - t2, 3) * p3[idx] + 3 * t2 * Math.pow(1 - t2, 2) * p2[idx] + 3 * Math.pow(t2, 2) * (1 - t2) * p1[idx] + p0[idx] * Math.pow(t2, 3);
17317
17425
  const [x2, y2] = position === "start" ? p0 : p3;
@@ -17336,26 +17444,26 @@ var getArrowheadPoints = (element, shape, position, arrowhead) => {
17336
17444
  }
17337
17445
  const angle = getArrowheadAngle(arrowhead);
17338
17446
  if (arrowhead === "crowfoot_many" || arrowhead === "crowfoot_one_or_many") {
17339
- const [x32, y32] = pointRotateRads8(
17340
- pointFrom13(x2, y2),
17341
- pointFrom13(xs, ys),
17447
+ const [x32, y32] = pointRotateRads9(
17448
+ pointFrom14(x2, y2),
17449
+ pointFrom14(xs, ys),
17342
17450
  degreesToRadians(-angle)
17343
17451
  );
17344
- const [x42, y42] = pointRotateRads8(
17345
- pointFrom13(x2, y2),
17346
- pointFrom13(xs, ys),
17452
+ const [x42, y42] = pointRotateRads9(
17453
+ pointFrom14(x2, y2),
17454
+ pointFrom14(xs, ys),
17347
17455
  degreesToRadians(angle)
17348
17456
  );
17349
17457
  return [xs, ys, x32, y32, x42, y42];
17350
17458
  }
17351
- const [x3, y3] = pointRotateRads8(
17352
- pointFrom13(xs, ys),
17353
- pointFrom13(x2, y2),
17459
+ const [x3, y3] = pointRotateRads9(
17460
+ pointFrom14(xs, ys),
17461
+ pointFrom14(x2, y2),
17354
17462
  -angle * Math.PI / 180
17355
17463
  );
17356
- const [x4, y4] = pointRotateRads8(
17357
- pointFrom13(xs, ys),
17358
- pointFrom13(x2, y2),
17464
+ const [x4, y4] = pointRotateRads9(
17465
+ pointFrom14(xs, ys),
17466
+ pointFrom14(x2, y2),
17359
17467
  degreesToRadians(angle)
17360
17468
  );
17361
17469
  if (arrowhead === "diamond" || arrowhead === "diamond_outline") {
@@ -17363,16 +17471,16 @@ var getArrowheadPoints = (element, shape, position, arrowhead) => {
17363
17471
  let oy;
17364
17472
  if (position === "start") {
17365
17473
  const [px, py] = element.points.length > 1 ? element.points[1] : [0, 0];
17366
- [ox, oy] = pointRotateRads8(
17367
- pointFrom13(x2 + minSize * 2, y2),
17368
- pointFrom13(x2, y2),
17474
+ [ox, oy] = pointRotateRads9(
17475
+ pointFrom14(x2 + minSize * 2, y2),
17476
+ pointFrom14(x2, y2),
17369
17477
  Math.atan2(py - y2, px - x2)
17370
17478
  );
17371
17479
  } else {
17372
17480
  const [px, py] = element.points.length > 1 ? element.points[element.points.length - 2] : [0, 0];
17373
- [ox, oy] = pointRotateRads8(
17374
- pointFrom13(x2 - minSize * 2, y2),
17375
- pointFrom13(x2, y2),
17481
+ [ox, oy] = pointRotateRads9(
17482
+ pointFrom14(x2 - minSize * 2, y2),
17483
+ pointFrom14(x2, y2),
17376
17484
  Math.atan2(y2 - py, x2 - px)
17377
17485
  );
17378
17486
  }
@@ -17383,9 +17491,9 @@ var getArrowheadPoints = (element, shape, position, arrowhead) => {
17383
17491
 
17384
17492
  // ../element/src/cropElement.ts
17385
17493
  import {
17386
- pointFrom as pointFrom14,
17494
+ pointFrom as pointFrom15,
17387
17495
  pointCenter as pointCenter2,
17388
- pointRotateRads as pointRotateRads9,
17496
+ pointRotateRads as pointRotateRads10,
17389
17497
  vectorFromPoint as vectorFromPoint7,
17390
17498
  vectorNormalize as vectorNormalize3,
17391
17499
  vectorSubtract,
@@ -17398,7 +17506,7 @@ import {
17398
17506
 
17399
17507
  // ../element/src/frame.ts
17400
17508
  import { arrayToMap as arrayToMap19 } from "@excalidraw/common";
17401
- import { isPointWithinBounds as isPointWithinBounds2, pointFrom as pointFrom16 } from "@excalidraw/math";
17509
+ import { isPointWithinBounds as isPointWithinBounds2, pointFrom as pointFrom17 } from "@excalidraw/math";
17402
17510
 
17403
17511
  // ../utils/src/bbox.ts
17404
17512
  import {
@@ -17418,24 +17526,24 @@ import {
17418
17526
  } from "@excalidraw/element";
17419
17527
  import {
17420
17528
  rangeIncludesValue,
17421
- pointFrom as pointFrom15,
17422
- pointRotateRads as pointRotateRads10,
17529
+ pointFrom as pointFrom16,
17530
+ pointRotateRads as pointRotateRads11,
17423
17531
  rangeInclusive
17424
17532
  } from "@excalidraw/math";
17425
17533
  var getNonLinearElementRelativePoints = (element) => {
17426
17534
  if (element.type === "diamond") {
17427
17535
  return [
17428
- pointFrom15(element.width / 2, 0),
17429
- pointFrom15(element.width, element.height / 2),
17430
- pointFrom15(element.width / 2, element.height),
17431
- pointFrom15(0, element.height / 2)
17536
+ pointFrom16(element.width / 2, 0),
17537
+ pointFrom16(element.width, element.height / 2),
17538
+ pointFrom16(element.width / 2, element.height),
17539
+ pointFrom16(0, element.height / 2)
17432
17540
  ];
17433
17541
  }
17434
17542
  return [
17435
- pointFrom15(0, 0),
17436
- pointFrom15(0 + element.width, 0),
17437
- pointFrom15(0 + element.width, element.height),
17438
- pointFrom15(0, element.height)
17543
+ pointFrom16(0, 0),
17544
+ pointFrom16(0 + element.width, 0),
17545
+ pointFrom16(0 + element.width, element.height),
17546
+ pointFrom16(0, element.height)
17439
17547
  ];
17440
17548
  };
17441
17549
  var getElementRelativePoints = (element) => {
@@ -17469,9 +17577,9 @@ var getMinMaxPoints = (points) => {
17469
17577
  var getRotatedBBox = (element) => {
17470
17578
  const points = getElementRelativePoints(element);
17471
17579
  const { cx, cy } = getMinMaxPoints(points);
17472
- const centerPoint = pointFrom15(cx, cy);
17580
+ const centerPoint = pointFrom16(cx, cy);
17473
17581
  const rotatedPoints = points.map(
17474
- (p) => pointRotateRads10(p, centerPoint, element.angle)
17582
+ (p) => pointRotateRads11(p, centerPoint, element.angle)
17475
17583
  );
17476
17584
  const { minX, minY, maxX, maxY } = getMinMaxPoints(rotatedPoints);
17477
17585
  return [
@@ -18080,7 +18188,7 @@ var generateElementShape = (element, generator, {
18080
18188
  case "arrow": {
18081
18189
  let shape;
18082
18190
  const options = generateRoughOptions(element);
18083
- const points = element.points.length ? element.points : [pointFrom17(0, 0)];
18191
+ const points = element.points.length ? element.points : [pointFrom18(0, 0)];
18084
18192
  if (isElbowArrow6(element)) {
18085
18193
  if (!points.every(
18086
18194
  (point) => Math.abs(point[0]) <= 1e6 && Math.abs(point[1]) <= 1e6
@@ -18225,7 +18333,7 @@ var generateElbowArrowShape = (points, radius) => {
18225
18333
  };
18226
18334
 
18227
18335
  // ../element/src/mutateElement.ts
18228
- var newElementWith8 = (element, updates, force = false) => {
18336
+ var newElementWith9 = (element, updates, force = false) => {
18229
18337
  let didChange = false;
18230
18338
  for (const key in updates) {
18231
18339
  const value = updates[key];
@@ -18354,7 +18462,7 @@ var actionTogglePolygon = register({
18354
18462
  if (!targetElementsMap.has(element.id) || !isLineElement4(element)) {
18355
18463
  return element;
18356
18464
  }
18357
- return newElementWith8(element, {
18465
+ return newElementWith9(element, {
18358
18466
  backgroundColor: nextPolygonState ? element.backgroundColor : "transparent",
18359
18467
  ...toggleLinePolygonState3(element, nextPolygonState)
18360
18468
  });
@@ -18946,7 +19054,7 @@ var createRedoAction = (history) => ({
18946
19054
 
18947
19055
  // actions/actionTextAutoResize.ts
18948
19056
  import { getFontString as getFontString6 } from "@excalidraw/common";
18949
- import { newElementWith as newElementWith9 } from "@excalidraw/element";
19057
+ import { newElementWith as newElementWith10 } from "@excalidraw/element";
18950
19058
  import { measureText as measureText4 } from "@excalidraw/element";
18951
19059
  import { isTextElement as isTextElement9 } from "@excalidraw/element";
18952
19060
  import { CaptureUpdateAction as CaptureUpdateAction34 } from "@excalidraw/element";
@@ -18970,7 +19078,7 @@ var actionTextAutoResize = register({
18970
19078
  getFontString6(element),
18971
19079
  element.lineHeight
18972
19080
  );
18973
- return newElementWith9(element, {
19081
+ return newElementWith10(element, {
18974
19082
  autoResize: true,
18975
19083
  width: metrics.width,
18976
19084
  height: metrics.height,
@@ -19209,8 +19317,8 @@ var sum = (array, mapper) => array.reduce((acc, item) => acc + mapper(item), 0);
19209
19317
 
19210
19318
  // snapping.ts
19211
19319
  import {
19212
- pointFrom as pointFrom18,
19213
- pointRotateRads as pointRotateRads12,
19320
+ pointFrom as pointFrom19,
19321
+ pointRotateRads as pointRotateRads13,
19214
19322
  rangeInclusive as rangeInclusive2,
19215
19323
  rangeIntersection,
19216
19324
  rangesOverlap
@@ -19260,7 +19368,8 @@ var isSnappingEnabled = ({
19260
19368
  selectedElements
19261
19369
  }) => {
19262
19370
  if (event) {
19263
- return app.state.activeTool.type !== "lasso" && (app.state.objectsSnapModeEnabled && !event[KEYS42.CTRL_OR_CMD] || !app.state.objectsSnapModeEnabled && event[KEYS42.CTRL_OR_CMD] && !isGridModeEnabled(app));
19371
+ const isLassoDragging = app.state.activeTool.type === "lasso" && app.state.selectedElementsAreBeingDragged;
19372
+ return (app.state.activeTool.type !== "lasso" || isLassoDragging) && (app.state.objectsSnapModeEnabled && !event[KEYS42.CTRL_OR_CMD] || !app.state.objectsSnapModeEnabled && event[KEYS42.CTRL_OR_CMD] && !isGridModeEnabled(app));
19264
19373
  }
19265
19374
  if (selectedElements.length === 1 && selectedElements[0].type === "arrow") {
19266
19375
  return false;
@@ -19296,50 +19405,50 @@ var getElementsCorners = (elements, elementsMap, {
19296
19405
  const halfWidth = (x2 - x1) / 2;
19297
19406
  const halfHeight = (y2 - y1) / 2;
19298
19407
  if ((element.type === "diamond" || element.type === "ellipse") && !boundingBoxCorners) {
19299
- const leftMid = pointRotateRads12(
19300
- pointFrom18(x1, y1 + halfHeight),
19301
- pointFrom18(cx, cy),
19408
+ const leftMid = pointRotateRads13(
19409
+ pointFrom19(x1, y1 + halfHeight),
19410
+ pointFrom19(cx, cy),
19302
19411
  element.angle
19303
19412
  );
19304
- const topMid = pointRotateRads12(
19305
- pointFrom18(x1 + halfWidth, y1),
19306
- pointFrom18(cx, cy),
19413
+ const topMid = pointRotateRads13(
19414
+ pointFrom19(x1 + halfWidth, y1),
19415
+ pointFrom19(cx, cy),
19307
19416
  element.angle
19308
19417
  );
19309
- const rightMid = pointRotateRads12(
19310
- pointFrom18(x2, y1 + halfHeight),
19311
- pointFrom18(cx, cy),
19418
+ const rightMid = pointRotateRads13(
19419
+ pointFrom19(x2, y1 + halfHeight),
19420
+ pointFrom19(cx, cy),
19312
19421
  element.angle
19313
19422
  );
19314
- const bottomMid = pointRotateRads12(
19315
- pointFrom18(x1 + halfWidth, y2),
19316
- pointFrom18(cx, cy),
19423
+ const bottomMid = pointRotateRads13(
19424
+ pointFrom19(x1 + halfWidth, y2),
19425
+ pointFrom19(cx, cy),
19317
19426
  element.angle
19318
19427
  );
19319
- const center = pointFrom18(cx, cy);
19428
+ const center = pointFrom19(cx, cy);
19320
19429
  result = omitCenter ? [leftMid, topMid, rightMid, bottomMid] : [leftMid, topMid, rightMid, bottomMid, center];
19321
19430
  } else {
19322
- const topLeft = pointRotateRads12(
19323
- pointFrom18(x1, y1),
19324
- pointFrom18(cx, cy),
19431
+ const topLeft = pointRotateRads13(
19432
+ pointFrom19(x1, y1),
19433
+ pointFrom19(cx, cy),
19325
19434
  element.angle
19326
19435
  );
19327
- const topRight = pointRotateRads12(
19328
- pointFrom18(x2, y1),
19329
- pointFrom18(cx, cy),
19436
+ const topRight = pointRotateRads13(
19437
+ pointFrom19(x2, y1),
19438
+ pointFrom19(cx, cy),
19330
19439
  element.angle
19331
19440
  );
19332
- const bottomLeft = pointRotateRads12(
19333
- pointFrom18(x1, y2),
19334
- pointFrom18(cx, cy),
19441
+ const bottomLeft = pointRotateRads13(
19442
+ pointFrom19(x1, y2),
19443
+ pointFrom19(cx, cy),
19335
19444
  element.angle
19336
19445
  );
19337
- const bottomRight = pointRotateRads12(
19338
- pointFrom18(x2, y2),
19339
- pointFrom18(cx, cy),
19446
+ const bottomRight = pointRotateRads13(
19447
+ pointFrom19(x2, y2),
19448
+ pointFrom19(cx, cy),
19340
19449
  element.angle
19341
19450
  );
19342
- const center = pointFrom18(cx, cy);
19451
+ const center = pointFrom19(cx, cy);
19343
19452
  result = omitCenter ? [topLeft, topRight, bottomLeft, bottomRight] : [topLeft, topRight, bottomLeft, bottomRight, center];
19344
19453
  }
19345
19454
  } else if (elements.length > 1) {
@@ -19349,14 +19458,14 @@ var getElementsCorners = (elements, elementsMap, {
19349
19458
  );
19350
19459
  const width = maxX - minX;
19351
19460
  const height = maxY - minY;
19352
- const topLeft = pointFrom18(minX, minY);
19353
- const topRight = pointFrom18(maxX, minY);
19354
- const bottomLeft = pointFrom18(minX, maxY);
19355
- const bottomRight = pointFrom18(maxX, maxY);
19356
- const center = pointFrom18(minX + width / 2, minY + height / 2);
19461
+ const topLeft = pointFrom19(minX, minY);
19462
+ const topRight = pointFrom19(maxX, minY);
19463
+ const bottomLeft = pointFrom19(minX, maxY);
19464
+ const bottomRight = pointFrom19(maxX, maxY);
19465
+ const center = pointFrom19(minX + width / 2, minY + height / 2);
19357
19466
  result = omitCenter ? [topLeft, topRight, bottomLeft, bottomRight] : [topLeft, topRight, bottomLeft, bottomRight, center];
19358
19467
  }
19359
- return result.map((p) => pointFrom18(round(p[0]), round(p[1])));
19468
+ return result.map((p) => pointFrom19(round(p[0]), round(p[1])));
19360
19469
  };
19361
19470
  var getReferenceElements = (elements, selectedElements, appState, elementsMap) => getVisibleAndNonSelectedElements(
19362
19471
  elements,
@@ -19399,10 +19508,10 @@ var getVisibleGaps = (elements, selectedElements, appState, elementsMap) => {
19399
19508
  startBounds,
19400
19509
  endBounds,
19401
19510
  startSide: [
19402
- pointFrom18(startMaxX, startMinY),
19403
- pointFrom18(startMaxX, startMaxY)
19511
+ pointFrom19(startMaxX, startMinY),
19512
+ pointFrom19(startMaxX, startMaxY)
19404
19513
  ],
19405
- endSide: [pointFrom18(endMinX, endMinY), pointFrom18(endMinX, endMaxY)],
19514
+ endSide: [pointFrom19(endMinX, endMinY), pointFrom19(endMinX, endMaxY)],
19406
19515
  length: endMinX - startMaxX,
19407
19516
  overlap: rangeIntersection(
19408
19517
  rangeInclusive2(startMinY, startMaxY),
@@ -19433,10 +19542,10 @@ var getVisibleGaps = (elements, selectedElements, appState, elementsMap) => {
19433
19542
  startBounds,
19434
19543
  endBounds,
19435
19544
  startSide: [
19436
- pointFrom18(startMinX, startMaxY),
19437
- pointFrom18(startMaxX, startMaxY)
19545
+ pointFrom19(startMinX, startMaxY),
19546
+ pointFrom19(startMaxX, startMaxY)
19438
19547
  ],
19439
- endSide: [pointFrom18(endMinX, endMinY), pointFrom18(endMaxX, endMinY)],
19548
+ endSide: [pointFrom19(endMinX, endMinY), pointFrom19(endMaxX, endMinY)],
19440
19549
  length: endMinY - startMaxY,
19441
19550
  overlap: rangeIntersection(
19442
19551
  rangeInclusive2(startMinX, startMaxX),
@@ -19741,7 +19850,7 @@ var createPointSnapLines = (nearestSnapsX, nearestSnapsY) => {
19741
19850
  }
19742
19851
  snapsX[key].push(
19743
19852
  ...snap.points.map(
19744
- (p) => pointFrom18(round(p[0]), round(p[1]))
19853
+ (p) => pointFrom19(round(p[0]), round(p[1]))
19745
19854
  )
19746
19855
  );
19747
19856
  }
@@ -19756,7 +19865,7 @@ var createPointSnapLines = (nearestSnapsX, nearestSnapsY) => {
19756
19865
  }
19757
19866
  snapsY[key].push(
19758
19867
  ...snap.points.map(
19759
- (p) => pointFrom18(round(p[0]), round(p[1]))
19868
+ (p) => pointFrom19(round(p[0]), round(p[1]))
19760
19869
  )
19761
19870
  );
19762
19871
  }
@@ -19767,7 +19876,7 @@ var createPointSnapLines = (nearestSnapsX, nearestSnapsY) => {
19767
19876
  type: "points",
19768
19877
  points: dedupePoints(
19769
19878
  points.map((p) => {
19770
- return pointFrom18(Number(key), p[1]);
19879
+ return pointFrom19(Number(key), p[1]);
19771
19880
  }).sort((a, b) => a[1] - b[1])
19772
19881
  )
19773
19882
  };
@@ -19777,7 +19886,7 @@ var createPointSnapLines = (nearestSnapsX, nearestSnapsY) => {
19777
19886
  type: "points",
19778
19887
  points: dedupePoints(
19779
19888
  points.map((p) => {
19780
- return pointFrom18(p[0], Number(key));
19889
+ return pointFrom19(p[0], Number(key));
19781
19890
  }).sort((a, b) => a[0] - b[0])
19782
19891
  )
19783
19892
  };
@@ -19820,16 +19929,16 @@ var createGapSnapLines = (selectedElements, dragOffset, gapSnaps) => {
19820
19929
  type: "gap",
19821
19930
  direction: "horizontal",
19822
19931
  points: [
19823
- pointFrom18(gapSnap.gap.startSide[0][0], gapLineY),
19824
- pointFrom18(minX, gapLineY)
19932
+ pointFrom19(gapSnap.gap.startSide[0][0], gapLineY),
19933
+ pointFrom19(minX, gapLineY)
19825
19934
  ]
19826
19935
  },
19827
19936
  {
19828
19937
  type: "gap",
19829
19938
  direction: "horizontal",
19830
19939
  points: [
19831
- pointFrom18(maxX, gapLineY),
19832
- pointFrom18(gapSnap.gap.endSide[0][0], gapLineY)
19940
+ pointFrom19(maxX, gapLineY),
19941
+ pointFrom19(gapSnap.gap.endSide[0][0], gapLineY)
19833
19942
  ]
19834
19943
  }
19835
19944
  );
@@ -19844,16 +19953,16 @@ var createGapSnapLines = (selectedElements, dragOffset, gapSnaps) => {
19844
19953
  type: "gap",
19845
19954
  direction: "vertical",
19846
19955
  points: [
19847
- pointFrom18(gapLineX, gapSnap.gap.startSide[0][1]),
19848
- pointFrom18(gapLineX, minY)
19956
+ pointFrom19(gapLineX, gapSnap.gap.startSide[0][1]),
19957
+ pointFrom19(gapLineX, minY)
19849
19958
  ]
19850
19959
  },
19851
19960
  {
19852
19961
  type: "gap",
19853
19962
  direction: "vertical",
19854
19963
  points: [
19855
- pointFrom18(gapLineX, maxY),
19856
- pointFrom18(gapLineX, gapSnap.gap.endSide[0][1])
19964
+ pointFrom19(gapLineX, maxY),
19965
+ pointFrom19(gapLineX, gapSnap.gap.endSide[0][1])
19857
19966
  ]
19858
19967
  }
19859
19968
  );
@@ -19868,14 +19977,14 @@ var createGapSnapLines = (selectedElements, dragOffset, gapSnaps) => {
19868
19977
  type: "gap",
19869
19978
  direction: "horizontal",
19870
19979
  points: [
19871
- pointFrom18(startMaxX, gapLineY),
19872
- pointFrom18(endMinX, gapLineY)
19980
+ pointFrom19(startMaxX, gapLineY),
19981
+ pointFrom19(endMinX, gapLineY)
19873
19982
  ]
19874
19983
  },
19875
19984
  {
19876
19985
  type: "gap",
19877
19986
  direction: "horizontal",
19878
- points: [pointFrom18(endMaxX, gapLineY), pointFrom18(minX, gapLineY)]
19987
+ points: [pointFrom19(endMaxX, gapLineY), pointFrom19(minX, gapLineY)]
19879
19988
  }
19880
19989
  );
19881
19990
  }
@@ -19889,16 +19998,16 @@ var createGapSnapLines = (selectedElements, dragOffset, gapSnaps) => {
19889
19998
  type: "gap",
19890
19999
  direction: "horizontal",
19891
20000
  points: [
19892
- pointFrom18(maxX, gapLineY),
19893
- pointFrom18(startMinX, gapLineY)
20001
+ pointFrom19(maxX, gapLineY),
20002
+ pointFrom19(startMinX, gapLineY)
19894
20003
  ]
19895
20004
  },
19896
20005
  {
19897
20006
  type: "gap",
19898
20007
  direction: "horizontal",
19899
20008
  points: [
19900
- pointFrom18(startMaxX, gapLineY),
19901
- pointFrom18(endMinX, gapLineY)
20009
+ pointFrom19(startMaxX, gapLineY),
20010
+ pointFrom19(endMinX, gapLineY)
19902
20011
  ]
19903
20012
  }
19904
20013
  );
@@ -19913,16 +20022,16 @@ var createGapSnapLines = (selectedElements, dragOffset, gapSnaps) => {
19913
20022
  type: "gap",
19914
20023
  direction: "vertical",
19915
20024
  points: [
19916
- pointFrom18(gapLineX, maxY),
19917
- pointFrom18(gapLineX, startMinY)
20025
+ pointFrom19(gapLineX, maxY),
20026
+ pointFrom19(gapLineX, startMinY)
19918
20027
  ]
19919
20028
  },
19920
20029
  {
19921
20030
  type: "gap",
19922
20031
  direction: "vertical",
19923
20032
  points: [
19924
- pointFrom18(gapLineX, startMaxY),
19925
- pointFrom18(gapLineX, endMinY)
20033
+ pointFrom19(gapLineX, startMaxY),
20034
+ pointFrom19(gapLineX, endMinY)
19926
20035
  ]
19927
20036
  }
19928
20037
  );
@@ -19937,14 +20046,14 @@ var createGapSnapLines = (selectedElements, dragOffset, gapSnaps) => {
19937
20046
  type: "gap",
19938
20047
  direction: "vertical",
19939
20048
  points: [
19940
- pointFrom18(gapLineX, startMaxY),
19941
- pointFrom18(gapLineX, endMinY)
20049
+ pointFrom19(gapLineX, startMaxY),
20050
+ pointFrom19(gapLineX, endMinY)
19942
20051
  ]
19943
20052
  },
19944
20053
  {
19945
20054
  type: "gap",
19946
20055
  direction: "vertical",
19947
- points: [pointFrom18(gapLineX, endMaxY), pointFrom18(gapLineX, minY)]
20056
+ points: [pointFrom19(gapLineX, endMaxY), pointFrom19(gapLineX, minY)]
19948
20057
  }
19949
20058
  );
19950
20059
  }
@@ -19957,7 +20066,7 @@ var createGapSnapLines = (selectedElements, dragOffset, gapSnaps) => {
19957
20066
  return {
19958
20067
  ...gapSnapLine,
19959
20068
  points: gapSnapLine.points.map(
19960
- (p) => pointFrom18(round(p[0]), round(p[1]))
20069
+ (p) => pointFrom19(round(p[0]), round(p[1]))
19961
20070
  )
19962
20071
  };
19963
20072
  })
@@ -19987,35 +20096,35 @@ var snapResizingElements = (selectedElements, selectedOriginalElements, app, eve
19987
20096
  if (transformHandle) {
19988
20097
  switch (transformHandle) {
19989
20098
  case "e": {
19990
- selectionSnapPoints.push(pointFrom18(maxX, minY), pointFrom18(maxX, maxY));
20099
+ selectionSnapPoints.push(pointFrom19(maxX, minY), pointFrom19(maxX, maxY));
19991
20100
  break;
19992
20101
  }
19993
20102
  case "w": {
19994
- selectionSnapPoints.push(pointFrom18(minX, minY), pointFrom18(minX, maxY));
20103
+ selectionSnapPoints.push(pointFrom19(minX, minY), pointFrom19(minX, maxY));
19995
20104
  break;
19996
20105
  }
19997
20106
  case "n": {
19998
- selectionSnapPoints.push(pointFrom18(minX, minY), pointFrom18(maxX, minY));
20107
+ selectionSnapPoints.push(pointFrom19(minX, minY), pointFrom19(maxX, minY));
19999
20108
  break;
20000
20109
  }
20001
20110
  case "s": {
20002
- selectionSnapPoints.push(pointFrom18(minX, maxY), pointFrom18(maxX, maxY));
20111
+ selectionSnapPoints.push(pointFrom19(minX, maxY), pointFrom19(maxX, maxY));
20003
20112
  break;
20004
20113
  }
20005
20114
  case "ne": {
20006
- selectionSnapPoints.push(pointFrom18(maxX, minY));
20115
+ selectionSnapPoints.push(pointFrom19(maxX, minY));
20007
20116
  break;
20008
20117
  }
20009
20118
  case "nw": {
20010
- selectionSnapPoints.push(pointFrom18(minX, minY));
20119
+ selectionSnapPoints.push(pointFrom19(minX, minY));
20011
20120
  break;
20012
20121
  }
20013
20122
  case "se": {
20014
- selectionSnapPoints.push(pointFrom18(maxX, maxY));
20123
+ selectionSnapPoints.push(pointFrom19(maxX, maxY));
20015
20124
  break;
20016
20125
  }
20017
20126
  case "sw": {
20018
- selectionSnapPoints.push(pointFrom18(minX, maxY));
20127
+ selectionSnapPoints.push(pointFrom19(minX, maxY));
20019
20128
  break;
20020
20129
  }
20021
20130
  }
@@ -20048,10 +20157,10 @@ var snapResizingElements = (selectedElements, selectedOriginalElements, app, eve
20048
20157
  (bound) => round(bound)
20049
20158
  );
20050
20159
  const corners = [
20051
- pointFrom18(x1, y1),
20052
- pointFrom18(x1, y2),
20053
- pointFrom18(x2, y1),
20054
- pointFrom18(x2, y2)
20160
+ pointFrom19(x1, y1),
20161
+ pointFrom19(x1, y2),
20162
+ pointFrom19(x2, y1),
20163
+ pointFrom19(x2, y2)
20055
20164
  ];
20056
20165
  getPointSnaps(
20057
20166
  selectedElements,
@@ -20076,7 +20185,7 @@ var snapNewElement = (newElement6, app, event, origin, dragOffset, elementsMap)
20076
20185
  };
20077
20186
  }
20078
20187
  const selectionSnapPoints = [
20079
- pointFrom18(origin.x + dragOffset.x, origin.y + dragOffset.y)
20188
+ pointFrom19(origin.x + dragOffset.x, origin.y + dragOffset.y)
20080
20189
  ];
20081
20190
  const snapDistance = getSnapDistance(app.state.zoom.value);
20082
20191
  const minOffset = {
@@ -20151,7 +20260,7 @@ var getSnapLinesAtPointer = (elements, app, pointer, event, elementsMap) => {
20151
20260
  }
20152
20261
  verticalSnapLines.push({
20153
20262
  type: "pointer",
20154
- points: [corner, pointFrom18(corner[0], pointer.y)],
20263
+ points: [corner, pointFrom19(corner[0], pointer.y)],
20155
20264
  direction: "vertical"
20156
20265
  });
20157
20266
  minOffset.x = offsetX;
@@ -20163,7 +20272,7 @@ var getSnapLinesAtPointer = (elements, app, pointer, event, elementsMap) => {
20163
20272
  }
20164
20273
  horizontalSnapLines.push({
20165
20274
  type: "pointer",
20166
- points: [corner, pointFrom18(pointer.x, corner[1])],
20275
+ points: [corner, pointFrom19(pointer.x, corner[1])],
20167
20276
  direction: "horizontal"
20168
20277
  });
20169
20278
  minOffset.y = offsetY;
@@ -20183,7 +20292,7 @@ var isActiveToolNonLinearSnappable = (activeToolType) => {
20183
20292
  };
20184
20293
 
20185
20294
  // data/transform.ts
20186
- import { pointFrom as pointFrom19 } from "@excalidraw/math";
20295
+ import { pointFrom as pointFrom20 } from "@excalidraw/math";
20187
20296
  import {
20188
20297
  DEFAULT_FONT_FAMILY as DEFAULT_FONT_FAMILY5,
20189
20298
  DEFAULT_FONT_SIZE as DEFAULT_FONT_SIZE6,
@@ -20482,7 +20591,7 @@ var convertToExcalidrawElements = (elementsSkeleton, opts) => {
20482
20591
  excalidrawElement = newLinearElement3({
20483
20592
  width,
20484
20593
  height,
20485
- points: [pointFrom19(0, 0), pointFrom19(width, height)],
20594
+ points: [pointFrom20(0, 0), pointFrom20(width, height)],
20486
20595
  ...element
20487
20596
  });
20488
20597
  break;
@@ -20494,7 +20603,7 @@ var convertToExcalidrawElements = (elementsSkeleton, opts) => {
20494
20603
  width,
20495
20604
  height,
20496
20605
  endArrowhead: "arrow",
20497
- points: [pointFrom19(0, 0), pointFrom19(width, height)],
20606
+ points: [pointFrom20(0, 0), pointFrom20(width, height)],
20498
20607
  ...element,
20499
20608
  type: "arrow"
20500
20609
  });
@@ -20710,7 +20819,7 @@ import { memoize, toBrandedType as toBrandedType2 } from "@excalidraw/common";
20710
20819
 
20711
20820
  // renderer/interactiveScene.ts
20712
20821
  import {
20713
- pointFrom as pointFrom21,
20822
+ pointFrom as pointFrom22,
20714
20823
  pointsEqual as pointsEqual8
20715
20824
  } from "@excalidraw/math";
20716
20825
  import oc2 from "open-color";
@@ -20748,7 +20857,7 @@ import {
20748
20857
  import { getCommonBounds as getCommonBounds7, getElementAbsoluteCoords as getElementAbsoluteCoords6 } from "@excalidraw/element";
20749
20858
 
20750
20859
  // renderer/renderSnaps.ts
20751
- import { pointFrom as pointFrom20 } from "@excalidraw/math";
20860
+ import { pointFrom as pointFrom21 } from "@excalidraw/math";
20752
20861
  import { THEME as THEME10 } from "@excalidraw/common";
20753
20862
  var SNAP_COLOR_LIGHT = "#ff6b6b";
20754
20863
  var SNAP_COLOR_DARK = "#ff0000";
@@ -20826,25 +20935,25 @@ var drawGapLine = (from, to, direction, appState, context) => {
20826
20935
  const halfPoint = [(from[0] + to[0]) / 2, from[1]];
20827
20936
  if (!appState.zenModeEnabled) {
20828
20937
  drawLine(
20829
- pointFrom20(from[0], from[1] - FULL),
20830
- pointFrom20(from[0], from[1] + FULL),
20938
+ pointFrom21(from[0], from[1] - FULL),
20939
+ pointFrom21(from[0], from[1] + FULL),
20831
20940
  context
20832
20941
  );
20833
20942
  }
20834
20943
  drawLine(
20835
- pointFrom20(halfPoint[0] - QUARTER, halfPoint[1] - HALF),
20836
- pointFrom20(halfPoint[0] - QUARTER, halfPoint[1] + HALF),
20944
+ pointFrom21(halfPoint[0] - QUARTER, halfPoint[1] - HALF),
20945
+ pointFrom21(halfPoint[0] - QUARTER, halfPoint[1] + HALF),
20837
20946
  context
20838
20947
  );
20839
20948
  drawLine(
20840
- pointFrom20(halfPoint[0] + QUARTER, halfPoint[1] - HALF),
20841
- pointFrom20(halfPoint[0] + QUARTER, halfPoint[1] + HALF),
20949
+ pointFrom21(halfPoint[0] + QUARTER, halfPoint[1] - HALF),
20950
+ pointFrom21(halfPoint[0] + QUARTER, halfPoint[1] + HALF),
20842
20951
  context
20843
20952
  );
20844
20953
  if (!appState.zenModeEnabled) {
20845
20954
  drawLine(
20846
- pointFrom20(to[0], to[1] - FULL),
20847
- pointFrom20(to[0], to[1] + FULL),
20955
+ pointFrom21(to[0], to[1] - FULL),
20956
+ pointFrom21(to[0], to[1] + FULL),
20848
20957
  context
20849
20958
  );
20850
20959
  drawLine(from, to, context);
@@ -20853,25 +20962,25 @@ var drawGapLine = (from, to, direction, appState, context) => {
20853
20962
  const halfPoint = [from[0], (from[1] + to[1]) / 2];
20854
20963
  if (!appState.zenModeEnabled) {
20855
20964
  drawLine(
20856
- pointFrom20(from[0] - FULL, from[1]),
20857
- pointFrom20(from[0] + FULL, from[1]),
20965
+ pointFrom21(from[0] - FULL, from[1]),
20966
+ pointFrom21(from[0] + FULL, from[1]),
20858
20967
  context
20859
20968
  );
20860
20969
  }
20861
20970
  drawLine(
20862
- pointFrom20(halfPoint[0] - HALF, halfPoint[1] - QUARTER),
20863
- pointFrom20(halfPoint[0] + HALF, halfPoint[1] - QUARTER),
20971
+ pointFrom21(halfPoint[0] - HALF, halfPoint[1] - QUARTER),
20972
+ pointFrom21(halfPoint[0] + HALF, halfPoint[1] - QUARTER),
20864
20973
  context
20865
20974
  );
20866
20975
  drawLine(
20867
- pointFrom20(halfPoint[0] - HALF, halfPoint[1] + QUARTER),
20868
- pointFrom20(halfPoint[0] + HALF, halfPoint[1] + QUARTER),
20976
+ pointFrom21(halfPoint[0] - HALF, halfPoint[1] + QUARTER),
20977
+ pointFrom21(halfPoint[0] + HALF, halfPoint[1] + QUARTER),
20869
20978
  context
20870
20979
  );
20871
20980
  if (!appState.zenModeEnabled) {
20872
20981
  drawLine(
20873
- pointFrom20(to[0] - FULL, to[1]),
20874
- pointFrom20(to[0] + FULL, to[1]),
20982
+ pointFrom21(to[0] - FULL, to[1]),
20983
+ pointFrom21(to[0] + FULL, to[1]),
20875
20984
  context
20876
20985
  );
20877
20986
  drawLine(from, to, context);
@@ -21224,7 +21333,7 @@ var renderLinearPointHandles = (context, appState, element, elementsMap) => {
21224
21333
  renderSingleLinearPoint(
21225
21334
  context,
21226
21335
  appState,
21227
- pointFrom21(
21336
+ pointFrom22(
21228
21337
  (p[0] + points[idx + 1][0]) / 2,
21229
21338
  (p[1] + points[idx + 1][1]) / 2
21230
21339
  ),
@@ -22169,7 +22278,8 @@ import {
22169
22278
  isWritableElement as isWritableElement2,
22170
22279
  getFontString as getFontString8,
22171
22280
  getFontFamilyString as getFontFamilyString3,
22172
- isTestEnv as isTestEnv5
22281
+ isTestEnv as isTestEnv5,
22282
+ MIME_TYPES as MIME_TYPES8
22173
22283
  } from "@excalidraw/common";
22174
22284
  import {
22175
22285
  originalContainerCache,
@@ -22304,11 +22414,12 @@ var textWysiwyg = ({
22304
22414
  );
22305
22415
  app.scene.mutateElement(container, { height: targetContainerHeight });
22306
22416
  } else {
22307
- const { y } = computeBoundTextPosition2(
22417
+ const { x, y } = computeBoundTextPosition2(
22308
22418
  container,
22309
22419
  updatedTextElement,
22310
22420
  elementsMap
22311
22421
  );
22422
+ coordX = x;
22312
22423
  coordY = y;
22313
22424
  }
22314
22425
  }
@@ -22396,12 +22507,14 @@ var textWysiwyg = ({
22396
22507
  updateWysiwygStyle();
22397
22508
  if (onChange) {
22398
22509
  editable.onpaste = async (event) => {
22399
- const clipboardData = await parseClipboard(event, true);
22400
- if (!clipboardData.text) {
22510
+ const textItem = (await parseDataTransferEvent(event)).findByType(
22511
+ MIME_TYPES8.text
22512
+ );
22513
+ if (!textItem) {
22401
22514
  return;
22402
22515
  }
22403
- const data = normalizeText2(clipboardData.text);
22404
- if (!data) {
22516
+ const text = normalizeText2(textItem.value);
22517
+ if (!text) {
22405
22518
  return;
22406
22519
  }
22407
22520
  const container = getContainerElement3(
@@ -22418,7 +22531,7 @@ var textWysiwyg = ({
22418
22531
  app.scene.getNonDeletedElementsMap()
22419
22532
  );
22420
22533
  const wrappedText = wrapText3(
22421
- `${editable.value}${data}`,
22534
+ `${editable.value}${text}`,
22422
22535
  font,
22423
22536
  getBoundTextMaxWidth3(container, boundTextElement)
22424
22537
  );
@@ -22720,7 +22833,7 @@ var isMaybeMermaidDefinition = (text) => {
22720
22833
 
22721
22834
  // lasso/index.ts
22722
22835
  import {
22723
- pointFrom as pointFrom22
22836
+ pointFrom as pointFrom23
22724
22837
  } from "@excalidraw/math";
22725
22838
  import { getElementLineSegments as getElementLineSegments2 } from "@excalidraw/element";
22726
22839
  import { LinearElementEditor as LinearElementEditor11 } from "@excalidraw/element";
@@ -22919,7 +23032,7 @@ var LassoTrail = class extends AnimatedTrail {
22919
23032
  this.updateSelection();
22920
23033
  });
22921
23034
  __publicField(this, "updateSelection", () => {
22922
- const lassoPath = super.getCurrentTrail()?.originalPoints?.map((p) => pointFrom22(p[0], p[1]));
23035
+ const lassoPath = super.getCurrentTrail()?.originalPoints?.map((p) => pointFrom23(p[0], p[1]));
22923
23036
  const currentCanvasTranslate = {
22924
23037
  scrollX: this.app.state.scrollX,
22925
23038
  scrollY: this.app.state.scrollY,
@@ -22979,7 +23092,7 @@ import {
22979
23092
  intersectElementWithLineSegment as intersectElementWithLineSegment3,
22980
23093
  isPointInElement
22981
23094
  } from "@excalidraw/element";
22982
- import { lineSegment as lineSegment7, pointFrom as pointFrom23 } from "@excalidraw/math";
23095
+ import { lineSegment as lineSegment7, pointFrom as pointFrom24 } from "@excalidraw/math";
22983
23096
  import { getElementsInGroup as getElementsInGroup6 } from "@excalidraw/element";
22984
23097
  import { shouldTestInside as shouldTestInside2 } from "@excalidraw/element";
22985
23098
  import { hasBoundTextElement as hasBoundTextElement6, isBoundToContainer as isBoundToContainer7 } from "@excalidraw/element";
@@ -23016,7 +23129,7 @@ var EraserTrail = class extends AnimatedTrail {
23016
23129
  return elementsToEraser;
23017
23130
  }
23018
23131
  updateElementsToBeErased(restoreToErase) {
23019
- const eraserPath = super.getCurrentTrail()?.originalPoints?.map((p) => pointFrom23(p[0], p[1])) || [];
23132
+ const eraserPath = super.getCurrentTrail()?.originalPoints?.map((p) => pointFrom24(p[0], p[1])) || [];
23020
23133
  if (eraserPath.length < 2) {
23021
23134
  return [];
23022
23135
  }
@@ -23543,7 +23656,7 @@ import { isNodeInFlowchart } from "@excalidraw/element";
23543
23656
  import { jsx as jsx87 } from "react/jsx-runtime";
23544
23657
  var getHints = ({
23545
23658
  appState,
23546
- isMobile,
23659
+ isMobile: isMobile2,
23547
23660
  device,
23548
23661
  app
23549
23662
  }) => {
@@ -23606,7 +23719,7 @@ var getHints = ({
23606
23719
  if (isGridModeEnabled(app) && appState.selectedElementsAreBeingDragged) {
23607
23720
  return t("hints.disableSnapping");
23608
23721
  }
23609
- if (!selectedElements.length && !isMobile) {
23722
+ if (!selectedElements.length && !isMobile2) {
23610
23723
  return [t("hints.canvasPanning")];
23611
23724
  }
23612
23725
  if (selectedElements.length === 1) {
@@ -23634,13 +23747,13 @@ var getHints = ({
23634
23747
  };
23635
23748
  var HintViewer = ({
23636
23749
  appState,
23637
- isMobile,
23750
+ isMobile: isMobile2,
23638
23751
  device,
23639
23752
  app
23640
23753
  }) => {
23641
23754
  const hints = getHints({
23642
23755
  appState,
23643
- isMobile,
23756
+ isMobile: isMobile2,
23644
23757
  device,
23645
23758
  app
23646
23759
  });
@@ -24260,7 +24373,7 @@ import {
24260
24373
  useImperativeHandle as useImperativeHandle3,
24261
24374
  useCallback as useCallback11
24262
24375
  } from "react";
24263
- import { EVENT as EVENT9, isDevEnv as isDevEnv9, KEYS as KEYS46, updateObject } from "@excalidraw/common";
24376
+ import { EVENT as EVENT10, isDevEnv as isDevEnv9, KEYS as KEYS46, updateObject } from "@excalidraw/common";
24264
24377
 
24265
24378
  // components/Sidebar/SidebarHeader.tsx
24266
24379
  import clsx41 from "clsx";
@@ -24498,9 +24611,9 @@ var SidebarInner = forwardRef4(
24498
24611
  closeLibrary();
24499
24612
  }
24500
24613
  };
24501
- document.addEventListener(EVENT9.KEYDOWN, handleKeyDown);
24614
+ document.addEventListener(EVENT10.KEYDOWN, handleKeyDown);
24502
24615
  return () => {
24503
- document.removeEventListener(EVENT9.KEYDOWN, handleKeyDown);
24616
+ document.removeEventListener(EVENT10.KEYDOWN, handleKeyDown);
24504
24617
  };
24505
24618
  }, [closeLibrary, docked, device.editor.canFitSidebar]);
24506
24619
  return /* @__PURE__ */ jsx101(
@@ -25284,7 +25397,7 @@ import debounce2 from "lodash.debounce";
25284
25397
  import { Fragment as Fragment17, memo as memo4, useEffect as useEffect32, useMemo as useMemo8, useRef as useRef28, useState as useState28 } from "react";
25285
25398
  import {
25286
25399
  CLASSES as CLASSES5,
25287
- EVENT as EVENT10,
25400
+ EVENT as EVENT11,
25288
25401
  FONT_FAMILY as FONT_FAMILY4,
25289
25402
  FRAME_STYLE as FRAME_STYLE3,
25290
25403
  getLineHeight as getLineHeight4
@@ -25505,7 +25618,7 @@ var SearchMenu2 = () => {
25505
25618
  }
25506
25619
  }
25507
25620
  };
25508
- return addEventListener(window, EVENT10.KEYDOWN, eventHandler, {
25621
+ return addEventListener(window, EVENT11.KEYDOWN, eventHandler, {
25509
25622
  capture: true,
25510
25623
  passive: false
25511
25624
  });
@@ -25976,7 +26089,7 @@ import { EDITOR_LS_KEYS as EDITOR_LS_KEYS3, debounce as debounce3, isDevEnv as i
25976
26089
 
25977
26090
  // components/TTDDialog/TTDDialogInput.tsx
25978
26091
  import { useEffect as useEffect33, useRef as useRef29 } from "react";
25979
- import { EVENT as EVENT11, KEYS as KEYS48 } from "@excalidraw/common";
26092
+ import { EVENT as EVENT12, KEYS as KEYS48 } from "@excalidraw/common";
25980
26093
  import { jsx as jsx112 } from "react/jsx-runtime";
25981
26094
  var TTDDialogInput = ({
25982
26095
  input,
@@ -26000,9 +26113,9 @@ var TTDDialogInput = ({
26000
26113
  }
26001
26114
  };
26002
26115
  textarea.focus();
26003
- textarea.addEventListener(EVENT11.KEYDOWN, handleKeyDown);
26116
+ textarea.addEventListener(EVENT12.KEYDOWN, handleKeyDown);
26004
26117
  return () => {
26005
- textarea.removeEventListener(EVENT11.KEYDOWN, handleKeyDown);
26118
+ textarea.removeEventListener(EVENT12.KEYDOWN, handleKeyDown);
26006
26119
  };
26007
26120
  }
26008
26121
  }, []);
@@ -26701,12 +26814,12 @@ import { updateBindings as updateBindings3 } from "@excalidraw/element";
26701
26814
  // components/Stats/DragInput.tsx
26702
26815
  import clsx50 from "clsx";
26703
26816
  import { useEffect as useEffect36, useRef as useRef33, useState as useState31 } from "react";
26704
- import { EVENT as EVENT12, KEYS as KEYS49, cloneJSON as cloneJSON4 } from "@excalidraw/common";
26817
+ import { EVENT as EVENT13, KEYS as KEYS49, cloneJSON as cloneJSON4 } from "@excalidraw/common";
26705
26818
  import { deepCopyElement as deepCopyElement4 } from "@excalidraw/element";
26706
26819
  import { CaptureUpdateAction as CaptureUpdateAction36 } from "@excalidraw/element";
26707
26820
 
26708
26821
  // components/Stats/utils.ts
26709
- import { pointFrom as pointFrom24, pointRotateRads as pointRotateRads13 } from "@excalidraw/math";
26822
+ import { pointFrom as pointFrom25, pointRotateRads as pointRotateRads14 } from "@excalidraw/math";
26710
26823
  import { getBoundTextElement as getBoundTextElement9 } from "@excalidraw/element";
26711
26824
  import { isFrameLikeElement as isFrameLikeElement12 } from "@excalidraw/element";
26712
26825
  import {
@@ -26744,16 +26857,16 @@ var moveElement = (newTopLeftX, newTopLeftY, originalElement, scene, originalEle
26744
26857
  originalElement.x + originalElement.width / 2,
26745
26858
  originalElement.y + originalElement.height / 2
26746
26859
  ];
26747
- const [topLeftX, topLeftY] = pointRotateRads13(
26748
- pointFrom24(originalElement.x, originalElement.y),
26749
- pointFrom24(cx, cy),
26860
+ const [topLeftX, topLeftY] = pointRotateRads14(
26861
+ pointFrom25(originalElement.x, originalElement.y),
26862
+ pointFrom25(cx, cy),
26750
26863
  originalElement.angle
26751
26864
  );
26752
26865
  const changeInX = newTopLeftX - topLeftX;
26753
26866
  const changeInY = newTopLeftY - topLeftY;
26754
- const [x, y] = pointRotateRads13(
26755
- pointFrom24(newTopLeftX, newTopLeftY),
26756
- pointFrom24(cx + changeInX, cy + changeInY),
26867
+ const [x, y] = pointRotateRads14(
26868
+ pointFrom25(newTopLeftX, newTopLeftY),
26869
+ pointFrom25(cx + changeInX, cy + changeInY),
26757
26870
  -originalElement.angle
26758
26871
  );
26759
26872
  scene.mutateElement(
@@ -26794,16 +26907,16 @@ var moveElement = (newTopLeftX, newTopLeftY, originalElement, scene, originalEle
26794
26907
  child.x + child.width / 2,
26795
26908
  child.y + child.height / 2
26796
26909
  ];
26797
- const [childTopLeftX, childTopLeftY] = pointRotateRads13(
26798
- pointFrom24(child.x, child.y),
26799
- pointFrom24(childCX, childCY),
26910
+ const [childTopLeftX, childTopLeftY] = pointRotateRads14(
26911
+ pointFrom25(child.x, child.y),
26912
+ pointFrom25(childCX, childCY),
26800
26913
  child.angle
26801
26914
  );
26802
26915
  const childNewTopLeftX = Math.round(childTopLeftX + changeInX);
26803
26916
  const childNewTopLeftY = Math.round(childTopLeftY + changeInY);
26804
- const [childX, childY] = pointRotateRads13(
26805
- pointFrom24(childNewTopLeftX, childNewTopLeftY),
26806
- pointFrom24(childCX + changeInX, childCY + changeInY),
26917
+ const [childX, childY] = pointRotateRads14(
26918
+ pointFrom25(childNewTopLeftX, childNewTopLeftY),
26919
+ pointFrom25(childCX + changeInX, childCY + changeInY),
26807
26920
  -child.angle
26808
26921
  );
26809
26922
  scene.mutateElement(
@@ -26920,12 +27033,12 @@ var StatsDragInput = ({
26920
27033
  );
26921
27034
  }
26922
27035
  window.removeEventListener(
26923
- EVENT12.POINTER_MOVE,
27036
+ EVENT13.POINTER_MOVE,
26924
27037
  callbacks.onPointerMove,
26925
27038
  false
26926
27039
  );
26927
27040
  window.removeEventListener(
26928
- EVENT12.POINTER_UP,
27041
+ EVENT13.POINTER_UP,
26929
27042
  callbacks.onPointerUp,
26930
27043
  false
26931
27044
  );
@@ -27004,7 +27117,7 @@ var StatsDragInput = ({
27004
27117
  };
27005
27118
  const onPointerUp = () => {
27006
27119
  window.removeEventListener(
27007
- EVENT12.POINTER_MOVE,
27120
+ EVENT13.POINTER_MOVE,
27008
27121
  onPointerMove,
27009
27122
  false
27010
27123
  );
@@ -27023,12 +27136,12 @@ var StatsDragInput = ({
27023
27136
  originalElements = null;
27024
27137
  originalElementsMap = null;
27025
27138
  document.body.classList.remove("excalidraw-cursor-resize");
27026
- window.removeEventListener(EVENT12.POINTER_UP, onPointerUp, false);
27139
+ window.removeEventListener(EVENT13.POINTER_UP, onPointerUp, false);
27027
27140
  };
27028
27141
  callbacksRef.current.onPointerMove = onPointerMove;
27029
27142
  callbacksRef.current.onPointerUp = onPointerUp;
27030
- window.addEventListener(EVENT12.POINTER_MOVE, onPointerMove, false);
27031
- window.addEventListener(EVENT12.POINTER_UP, onPointerUp, false);
27143
+ window.addEventListener(EVENT13.POINTER_MOVE, onPointerMove, false);
27144
+ window.addEventListener(EVENT13.POINTER_UP, onPointerUp, false);
27032
27145
  }
27033
27146
  },
27034
27147
  onPointerEnter: () => {
@@ -27633,7 +27746,7 @@ var MultiAngle = ({
27633
27746
  var MultiAngle_default = MultiAngle;
27634
27747
 
27635
27748
  // components/Stats/MultiDimension.tsx
27636
- import { pointFrom as pointFrom25 } from "@excalidraw/math";
27749
+ import { pointFrom as pointFrom26 } from "@excalidraw/math";
27637
27750
  import { useMemo as useMemo9 } from "react";
27638
27751
  import { MIN_WIDTH_OR_HEIGHT as MIN_WIDTH_OR_HEIGHT2 } from "@excalidraw/common";
27639
27752
  import {
@@ -27761,7 +27874,7 @@ var handleDimensionChange2 = ({
27761
27874
  nextHeight,
27762
27875
  initialHeight,
27763
27876
  aspectRatio,
27764
- pointFrom25(x1, y1),
27877
+ pointFrom26(x1, y1),
27765
27878
  property,
27766
27879
  latestElements,
27767
27880
  originalElements2,
@@ -27863,7 +27976,7 @@ var handleDimensionChange2 = ({
27863
27976
  nextHeight,
27864
27977
  initialHeight,
27865
27978
  aspectRatio,
27866
- pointFrom25(x1, y1),
27979
+ pointFrom26(x1, y1),
27867
27980
  property,
27868
27981
  latestElements,
27869
27982
  originalElements2,
@@ -28108,7 +28221,7 @@ var MultiFontSize = ({
28108
28221
  var MultiFontSize_default = MultiFontSize;
28109
28222
 
28110
28223
  // components/Stats/MultiPosition.tsx
28111
- import { pointFrom as pointFrom26, pointRotateRads as pointRotateRads14 } from "@excalidraw/math";
28224
+ import { pointFrom as pointFrom27, pointRotateRads as pointRotateRads15 } from "@excalidraw/math";
28112
28225
  import { useMemo as useMemo10 } from "react";
28113
28226
  import { isTextElement as isTextElement18 } from "@excalidraw/element";
28114
28227
  import { getCommonBounds as getCommonBounds9 } from "@excalidraw/element";
@@ -28120,9 +28233,9 @@ var moveElements = (property, changeInTopX, changeInTopY, originalElements, orig
28120
28233
  origElement.x + origElement.width / 2,
28121
28234
  origElement.y + origElement.height / 2
28122
28235
  ];
28123
- const [topLeftX, topLeftY] = pointRotateRads14(
28124
- pointFrom26(origElement.x, origElement.y),
28125
- pointFrom26(cx, cy),
28236
+ const [topLeftX, topLeftY] = pointRotateRads15(
28237
+ pointFrom27(origElement.x, origElement.y),
28238
+ pointFrom27(cx, cy),
28126
28239
  origElement.angle
28127
28240
  );
28128
28241
  const newTopLeftX = property === "x" ? Math.round(topLeftX + changeInTopX) : topLeftX;
@@ -28153,9 +28266,9 @@ var moveGroupTo = (nextX, nextY, originalElements, originalElementsMap, scene) =
28153
28266
  latestElement.x + latestElement.width / 2,
28154
28267
  latestElement.y + latestElement.height / 2
28155
28268
  ];
28156
- const [topLeftX, topLeftY] = pointRotateRads14(
28157
- pointFrom26(latestElement.x, latestElement.y),
28158
- pointFrom26(cx, cy),
28269
+ const [topLeftX, topLeftY] = pointRotateRads15(
28270
+ pointFrom27(latestElement.x, latestElement.y),
28271
+ pointFrom27(cx, cy),
28159
28272
  latestElement.angle
28160
28273
  );
28161
28274
  moveElement(
@@ -28211,9 +28324,9 @@ var handlePositionChange = ({
28211
28324
  origElement.x + origElement.width / 2,
28212
28325
  origElement.y + origElement.height / 2
28213
28326
  ];
28214
- const [topLeftX, topLeftY] = pointRotateRads14(
28215
- pointFrom26(origElement.x, origElement.y),
28216
- pointFrom26(cx, cy),
28327
+ const [topLeftX, topLeftY] = pointRotateRads15(
28328
+ pointFrom27(origElement.x, origElement.y),
28329
+ pointFrom27(cx, cy),
28217
28330
  origElement.angle
28218
28331
  );
28219
28332
  const newTopLeftX = property === "x" ? nextValue : topLeftX;
@@ -28262,9 +28375,9 @@ var MultiPosition = ({
28262
28375
  }
28263
28376
  const [el] = elementsInUnit;
28264
28377
  const [cx, cy] = [el.x + el.width / 2, el.y + el.height / 2];
28265
- const [topLeftX, topLeftY] = pointRotateRads14(
28266
- pointFrom26(el.x, el.y),
28267
- pointFrom26(cx, cy),
28378
+ const [topLeftX, topLeftY] = pointRotateRads15(
28379
+ pointFrom27(el.x, el.y),
28380
+ pointFrom27(cx, cy),
28268
28381
  el.angle
28269
28382
  );
28270
28383
  return Math.round((property === "x" ? topLeftX : topLeftY) * 100) / 100;
@@ -28288,7 +28401,7 @@ var MultiPosition = ({
28288
28401
  var MultiPosition_default = MultiPosition;
28289
28402
 
28290
28403
  // components/Stats/Position.tsx
28291
- import { clamp as clamp6, pointFrom as pointFrom27, pointRotateRads as pointRotateRads15, round as round4 } from "@excalidraw/math";
28404
+ import { clamp as clamp6, pointFrom as pointFrom28, pointRotateRads as pointRotateRads16, round as round4 } from "@excalidraw/math";
28292
28405
  import {
28293
28406
  getFlipAdjustedCropPosition,
28294
28407
  getUncroppedWidthAndHeight as getUncroppedWidthAndHeight2
@@ -28312,9 +28425,9 @@ var handlePositionChange2 = ({
28312
28425
  origElement.x + origElement.width / 2,
28313
28426
  origElement.y + origElement.height / 2
28314
28427
  ];
28315
- const [topLeftX, topLeftY] = pointRotateRads15(
28316
- pointFrom27(origElement.x, origElement.y),
28317
- pointFrom27(cx, cy),
28428
+ const [topLeftX, topLeftY] = pointRotateRads16(
28429
+ pointFrom28(origElement.x, origElement.y),
28430
+ pointFrom28(cx, cy),
28318
28431
  origElement.angle
28319
28432
  );
28320
28433
  if (originalAppState.croppingElementId === origElement.id) {
@@ -28412,9 +28525,9 @@ var Position = ({
28412
28525
  scene,
28413
28526
  appState
28414
28527
  }) => {
28415
- const [topLeftX, topLeftY] = pointRotateRads15(
28416
- pointFrom27(element.x, element.y),
28417
- pointFrom27(element.x + element.width / 2, element.y + element.height / 2),
28528
+ const [topLeftX, topLeftY] = pointRotateRads16(
28529
+ pointFrom28(element.x, element.y),
28530
+ pointFrom28(element.x + element.width / 2, element.y + element.height / 2),
28418
28531
  element.angle
28419
28532
  );
28420
28533
  let value = round4(property === "x" ? topLeftX : topLeftY, 2);
@@ -31183,6 +31296,7 @@ var useExcalidrawSetAppState = () => useContext3(ExcalidrawSetAppStateContext);
31183
31296
  var useExcalidrawActionManager = () => useContext3(ExcalidrawActionManagerContext);
31184
31297
  var didTapTwice = false;
31185
31298
  var tappedTwiceTimer = 0;
31299
+ var firstTapPosition = null;
31186
31300
  var isHoldingSpace = false;
31187
31301
  var isPanning = false;
31188
31302
  var isDraggingScrollBar = false;
@@ -31258,6 +31372,7 @@ var App = class _App extends React43.Component {
31258
31372
  __publicField(this, "onScrollChangeEmitter", new Emitter3());
31259
31373
  __publicField(this, "missingPointerEventCleanupEmitter", new Emitter3());
31260
31374
  __publicField(this, "onRemoveEventListenersEmitter", new Emitter3());
31375
+ __publicField(this, "defaultSelectionTool", "selection");
31261
31376
  __publicField(this, "updateEditorAtom", (atom2, ...args) => {
31262
31377
  const result = editorJotaiStore.set(atom2, ...args);
31263
31378
  this.triggerRender();
@@ -31600,7 +31715,7 @@ var App = class _App extends React43.Component {
31600
31715
  this.updateScene({
31601
31716
  elements: this.scene.getElementsIncludingDeleted().map((el) => {
31602
31717
  if (this.state.selectedElementIds[el.id]) {
31603
- return newElementWith10(el, {
31718
+ return newElementWith11(el, {
31604
31719
  [shouldUpdateStrokeColor ? "strokeColor" : "backgroundColor"]: color
31605
31720
  });
31606
31721
  }
@@ -31764,7 +31879,11 @@ var App = class _App extends React43.Component {
31764
31879
  }
31765
31880
  };
31766
31881
  }
31767
- const scene = restore(initialData, null, null, { repairBindings: true });
31882
+ const scene = restore(initialData, null, null, {
31883
+ repairBindings: true,
31884
+ deleteInvisibleElements: true
31885
+ });
31886
+ const activeTool = scene.appState.activeTool;
31768
31887
  scene.appState = {
31769
31888
  ...scene.appState,
31770
31889
  theme: this.props.theme || scene.appState.theme,
@@ -31773,7 +31892,10 @@ var App = class _App extends React43.Component {
31773
31892
  // update the state outside of initialData (e.g. when loading the app
31774
31893
  // with a library install link, which should auto-open the library)
31775
31894
  openSidebar: scene.appState?.openSidebar || this.state.openSidebar,
31776
- activeTool: scene.appState.activeTool.type === "image" ? { ...scene.appState.activeTool, type: "selection" } : scene.appState.activeTool,
31895
+ activeTool: activeTool.type === "image" || activeTool.type === "lasso" || activeTool.type === "selection" ? {
31896
+ ...activeTool,
31897
+ type: this.defaultSelectionTool
31898
+ } : scene.appState.activeTool,
31777
31899
  isLoading: false,
31778
31900
  toast: this.state.toast
31779
31901
  };
@@ -31803,6 +31925,12 @@ var App = class _App extends React43.Component {
31803
31925
  this.scrollToContent(window.location.href, { animate: false });
31804
31926
  }
31805
31927
  });
31928
+ __publicField(this, "isMobileOrTablet", () => {
31929
+ const hasTouch = "ontouchstart" in window || navigator.maxTouchPoints > 0;
31930
+ const hasCoarsePointer = "matchMedia" in window && window?.matchMedia("(pointer: coarse)")?.matches;
31931
+ const isTouchMobile = hasTouch && hasCoarsePointer;
31932
+ return isMobile || isTouchMobile;
31933
+ });
31806
31934
  __publicField(this, "isMobileBreakpoint", (width, height) => {
31807
31935
  return width < MQ_MAX_WIDTH_PORTRAIT || height < MQ_MAX_HEIGHT_LANDSCAPE && width < MQ_MAX_WIDTH_LANDSCAPE;
31808
31936
  });
@@ -31916,6 +32044,12 @@ var App = class _App extends React43.Component {
31916
32044
  }
31917
32045
  if (!didTapTwice) {
31918
32046
  didTapTwice = true;
32047
+ if (event.touches.length === 1) {
32048
+ firstTapPosition = {
32049
+ x: event.touches[0].clientX,
32050
+ y: event.touches[0].clientY
32051
+ };
32052
+ }
31919
32053
  clearTimeout(tappedTwiceTimer);
31920
32054
  tappedTwiceTimer = window.setTimeout(
31921
32055
  _App.resetTapTwice,
@@ -31923,12 +32057,20 @@ var App = class _App extends React43.Component {
31923
32057
  );
31924
32058
  return;
31925
32059
  }
31926
- if (didTapTwice && event.touches.length === 1) {
32060
+ if (didTapTwice && event.touches.length === 1 && firstTapPosition) {
31927
32061
  const touch = event.touches[0];
31928
- this.handleCanvasDoubleClick({
31929
- clientX: touch.clientX,
31930
- clientY: touch.clientY
31931
- });
32062
+ const distance3 = pointDistance8(
32063
+ pointFrom29(touch.clientX, touch.clientY),
32064
+ pointFrom29(firstTapPosition.x, firstTapPosition.y)
32065
+ );
32066
+ if (distance3 <= DOUBLE_TAP_POSITION_THRESHOLD) {
32067
+ this.lassoTrail.endPath();
32068
+ this.deselectElements();
32069
+ this.handleCanvasDoubleClick({
32070
+ clientX: touch.clientX,
32071
+ clientY: touch.clientY
32072
+ });
32073
+ }
31932
32074
  didTapTwice = false;
31933
32075
  clearTimeout(tappedTwiceTimer);
31934
32076
  }
@@ -31953,7 +32095,6 @@ var App = class _App extends React43.Component {
31953
32095
  gesture.pointers.clear();
31954
32096
  }
31955
32097
  });
31956
- // TODO: this is so spaghetti, we should refactor it and cover it with tests
31957
32098
  __publicField(this, "pasteFromClipboard", withBatchedUpdates(
31958
32099
  async (event) => {
31959
32100
  const isPlainPaste = !!IS_PLAIN_PASTE;
@@ -31969,37 +32110,9 @@ var App = class _App extends React43.Component {
31969
32110
  if (event && (!(elementUnderCursor instanceof HTMLCanvasElement) || isWritableElement3(target))) {
31970
32111
  return;
31971
32112
  }
31972
- const { x: sceneX, y: sceneY } = viewportCoordsToSceneCoords4(
31973
- {
31974
- clientX: this.lastViewportPosition.x,
31975
- clientY: this.lastViewportPosition.y
31976
- },
31977
- this.state
31978
- );
31979
- let file2 = event?.clipboardData?.files[0];
31980
- const data = await parseClipboard(event, isPlainPaste);
31981
- if (!file2 && !isPlainPaste) {
31982
- if (data.mixedContent) {
31983
- return this.addElementsFromMixedContentPaste(data.mixedContent, {
31984
- isPlainPaste,
31985
- sceneX,
31986
- sceneY
31987
- });
31988
- } else if (data.text) {
31989
- const string = data.text.trim();
31990
- if (string.startsWith("<svg") && string.endsWith("</svg>")) {
31991
- file2 = SVGStringToFile(string);
31992
- }
31993
- }
31994
- }
31995
- if (isSupportedImageFile(file2) && !data.spreadsheet) {
31996
- if (!this.isToolSupported("image")) {
31997
- this.setState({ errorMessage: t("errors.imageToolNotSupported") });
31998
- return;
31999
- }
32000
- this.createImageElement({ sceneX, sceneY, imageFile: file2 });
32001
- return;
32002
- }
32113
+ const dataTransferList = await parseDataTransferEvent(event);
32114
+ const filesList = dataTransferList.getFiles();
32115
+ const data = await parseClipboard(dataTransferList, isPlainPaste);
32003
32116
  if (this.props.onPaste) {
32004
32117
  try {
32005
32118
  if (await this.props.onPaste(data, event) === false) {
@@ -32009,82 +32122,15 @@ var App = class _App extends React43.Component {
32009
32122
  console.error(error);
32010
32123
  }
32011
32124
  }
32012
- if (data.errorMessage) {
32013
- this.setState({ errorMessage: data.errorMessage });
32014
- } else if (data.spreadsheet && !isPlainPaste) {
32015
- this.setState({
32016
- pasteDialog: {
32017
- data: data.spreadsheet,
32018
- shown: true
32019
- }
32020
- });
32021
- } else if (data.elements) {
32022
- const elements = data.programmaticAPI ? convertToExcalidrawElements(
32023
- data.elements
32024
- ) : data.elements;
32025
- this.addElementsFromPasteOrLibrary({
32026
- elements,
32027
- files: data.files || null,
32028
- position: "cursor",
32029
- retainSeed: isPlainPaste
32030
- });
32031
- } else if (data.text) {
32032
- if (data.text && isMaybeMermaidDefinition(data.text)) {
32033
- const api = await import("@excalidraw/mermaid-to-excalidraw");
32034
- try {
32035
- const { elements: skeletonElements, files } = await api.parseMermaidToExcalidraw(data.text);
32036
- const elements = convertToExcalidrawElements(skeletonElements, {
32037
- regenerateIds: true
32038
- });
32039
- this.addElementsFromPasteOrLibrary({
32040
- elements,
32041
- files,
32042
- position: "cursor"
32043
- });
32044
- return;
32045
- } catch (err) {
32046
- console.warn(
32047
- `parsing pasted text as mermaid definition failed: ${err.message}`
32048
- );
32049
- }
32050
- }
32051
- const nonEmptyLines = normalizeEOL2(data.text).split(/\n+/).map((s) => s.trim()).filter(Boolean);
32052
- const embbeddableUrls = nonEmptyLines.map((str) => maybeParseEmbedSrc(str)).filter((string) => {
32053
- return embeddableURLValidator2(string, this.props.validateEmbeddable) && (/^(http|https):\/\/[^\s/$.?#].[^\s]*$/.test(string) || getEmbedLink2(string)?.type === "video");
32054
- });
32055
- if (!IS_PLAIN_PASTE && embbeddableUrls.length > 0 && // if there were non-embeddable text (lines) mixed in with embeddable
32056
- // urls, ignore and paste as text
32057
- embbeddableUrls.length === nonEmptyLines.length) {
32058
- const embeddables = [];
32059
- for (const url of embbeddableUrls) {
32060
- const prevEmbeddable = embeddables[embeddables.length - 1];
32061
- const embeddable = this.insertEmbeddableElement({
32062
- sceneX: prevEmbeddable ? prevEmbeddable.x + prevEmbeddable.width + 20 : sceneX,
32063
- sceneY,
32064
- link: normalizeLink3(url)
32065
- });
32066
- if (embeddable) {
32067
- embeddables.push(embeddable);
32068
- }
32069
- }
32070
- if (embeddables.length) {
32071
- this.store.scheduleCapture();
32072
- this.setState({
32073
- selectedElementIds: Object.fromEntries(
32074
- embeddables.map((embeddable) => [embeddable.id, true])
32075
- )
32076
- });
32077
- }
32078
- return;
32079
- }
32080
- this.addTextFromPaste(data.text, isPlainPaste);
32081
- }
32082
- this.setActiveTool({ type: "selection" });
32125
+ await this.insertClipboardContent(data, filesList, isPlainPaste);
32126
+ this.setActiveTool({ type: this.defaultSelectionTool }, true);
32083
32127
  event?.preventDefault();
32084
32128
  }
32085
32129
  ));
32086
32130
  __publicField(this, "addElementsFromPasteOrLibrary", (opts) => {
32087
- const elements = restoreElements(opts.elements, null, void 0);
32131
+ const elements = restoreElements(opts.elements, null, {
32132
+ deleteInvisibleElements: true
32133
+ });
32088
32134
  const [minX, minY, maxX, maxY] = getCommonBounds12(elements);
32089
32135
  const elementsCenterX = distance2(minX, maxX) / 2;
32090
32136
  const elementsCenterY = distance2(minY, maxY) / 2;
@@ -32100,7 +32146,7 @@ var App = class _App extends React43.Component {
32100
32146
  const { duplicatedElements } = duplicateElements3({
32101
32147
  type: "everything",
32102
32148
  elements: elements.map((element) => {
32103
- return newElementWith10(element, {
32149
+ return newElementWith11(element, {
32104
32150
  x: element.x + gridX - minX,
32105
32151
  y: element.y + gridY - minY
32106
32152
  });
@@ -32181,7 +32227,7 @@ var App = class _App extends React43.Component {
32181
32227
  }
32182
32228
  }
32183
32229
  );
32184
- this.setActiveTool({ type: "selection" });
32230
+ this.setActiveTool({ type: this.defaultSelectionTool }, true);
32185
32231
  if (opts.fitToContent) {
32186
32232
  this.scrollToContent(duplicatedElements, {
32187
32233
  fitToContent: true,
@@ -32212,7 +32258,7 @@ var App = class _App extends React43.Component {
32212
32258
  ...prevState.activeTool,
32213
32259
  ...updateActiveTool7(
32214
32260
  this.state,
32215
- prevState.activeTool.locked ? { type: "selection" } : prevState.activeTool
32261
+ prevState.activeTool.locked ? { type: this.defaultSelectionTool } : prevState.activeTool
32216
32262
  ),
32217
32263
  locked: !prevState.activeTool.locked
32218
32264
  }
@@ -32403,11 +32449,11 @@ var App = class _App extends React43.Component {
32403
32449
  }
32404
32450
  addedFiles[fileData.id] = fileData;
32405
32451
  nextFiles[fileData.id] = fileData;
32406
- if (fileData.mimeType === MIME_TYPES8.svg) {
32452
+ if (fileData.mimeType === MIME_TYPES9.svg) {
32407
32453
  try {
32408
32454
  const restoredDataURL = getDataURL_sync(
32409
32455
  normalizeSVG(dataURLToString(fileData.dataURL)),
32410
- MIME_TYPES8.svg
32456
+ MIME_TYPES9.svg
32411
32457
  );
32412
32458
  if (fileData.dataURL !== restoredDataURL) {
32413
32459
  fileData.version = (fileData.version ?? 1) + 1;
@@ -32447,6 +32493,19 @@ var App = class _App extends React43.Component {
32447
32493
  }
32448
32494
  }
32449
32495
  ));
32496
+ __publicField(this, "applyDeltas", (deltas, options) => {
32497
+ const aggregatedDelta = StoreDelta2.squash(...deltas);
32498
+ const nextAppState = { ...this.state };
32499
+ const nextElements = new Map(
32500
+ this.scene.getElementsMapIncludingDeleted()
32501
+ );
32502
+ return StoreDelta2.applyTo(
32503
+ aggregatedDelta,
32504
+ nextElements,
32505
+ nextAppState,
32506
+ options
32507
+ );
32508
+ });
32450
32509
  __publicField(this, "mutateElement", (element, updates, informMutation = true) => {
32451
32510
  return this.scene.mutateElement(element, updates, {
32452
32511
  informMutation,
@@ -32814,7 +32873,7 @@ var App = class _App extends React43.Component {
32814
32873
  }
32815
32874
  }
32816
32875
  } else if (!event.ctrlKey && !event.altKey && !event.metaKey && !this.state.newElement && !this.state.selectionElement && !this.state.selectedElementsAreBeingDragged) {
32817
- const shape = findShapeByKey(event.key);
32876
+ const shape = findShapeByKey(event.key, this);
32818
32877
  if (shape) {
32819
32878
  if (this.state.activeTool.type !== shape) {
32820
32879
  trackEvent(
@@ -32871,7 +32930,7 @@ var App = class _App extends React43.Component {
32871
32930
  }
32872
32931
  if (event.key === KEYS52.K && !event.altKey && !event[KEYS52.CTRL_OR_CMD]) {
32873
32932
  if (this.state.activeTool.type === "laser") {
32874
- this.setActiveTool({ type: "selection" });
32933
+ this.setActiveTool({ type: this.defaultSelectionTool });
32875
32934
  } else {
32876
32935
  this.setActiveTool({ type: "laser" });
32877
32936
  }
@@ -32999,7 +33058,7 @@ var App = class _App extends React43.Component {
32999
33058
  this.setState({ suggestedBindings: [] });
33000
33059
  }
33001
33060
  if (nextActiveTool.type === "image") {
33002
- this.onImageAction();
33061
+ this.onImageToolbarButtonClick();
33003
33062
  }
33004
33063
  this.setState((prevState) => {
33005
33064
  const commonResets = {
@@ -33246,7 +33305,7 @@ var App = class _App extends React43.Component {
33246
33305
  if (this.state.multiElement) {
33247
33306
  return;
33248
33307
  }
33249
- if (this.state.activeTool.type !== "selection") {
33308
+ if (this.state.activeTool.type !== this.defaultSelectionTool) {
33250
33309
  return;
33251
33310
  }
33252
33311
  const selectedElements = this.scene.getSelectedElements(this.state);
@@ -33356,7 +33415,7 @@ var App = class _App extends React43.Component {
33356
33415
  );
33357
33416
  if (container) {
33358
33417
  if (hasBoundTextElement9(container) || !isTransparent6(container.backgroundColor) || hitElementItself({
33359
- point: pointFrom28(sceneX, sceneY),
33418
+ point: pointFrom29(sceneX, sceneY),
33360
33419
  element: container,
33361
33420
  elementsMap: this.scene.getNonDeletedElementsMap(),
33362
33421
  threshold: this.getElementHitThreshold(container)
@@ -33394,7 +33453,7 @@ var App = class _App extends React43.Component {
33394
33453
  element,
33395
33454
  this.scene.getNonDeletedElementsMap(),
33396
33455
  this.state,
33397
- pointFrom28(scenePointer.x, scenePointer.y),
33456
+ pointFrom29(scenePointer.x, scenePointer.y),
33398
33457
  this.device.editor.isMobile
33399
33458
  )) {
33400
33459
  return element;
@@ -33403,11 +33462,11 @@ var App = class _App extends React43.Component {
33403
33462
  });
33404
33463
  __publicField(this, "redirectToLink", (event, isTouchScreen) => {
33405
33464
  const draggedDistance = pointDistance8(
33406
- pointFrom28(
33465
+ pointFrom29(
33407
33466
  this.lastPointerDownEvent.clientX,
33408
33467
  this.lastPointerDownEvent.clientY
33409
33468
  ),
33410
- pointFrom28(
33469
+ pointFrom29(
33411
33470
  this.lastPointerUpEvent.clientX,
33412
33471
  this.lastPointerUpEvent.clientY
33413
33472
  )
@@ -33424,7 +33483,7 @@ var App = class _App extends React43.Component {
33424
33483
  this.hitLinkElement,
33425
33484
  elementsMap,
33426
33485
  this.state,
33427
- pointFrom28(lastPointerDownCoords.x, lastPointerDownCoords.y),
33486
+ pointFrom29(lastPointerDownCoords.x, lastPointerDownCoords.y),
33428
33487
  this.device.editor.isMobile
33429
33488
  );
33430
33489
  const lastPointerUpCoords = viewportCoordsToSceneCoords4(
@@ -33435,7 +33494,7 @@ var App = class _App extends React43.Component {
33435
33494
  this.hitLinkElement,
33436
33495
  elementsMap,
33437
33496
  this.state,
33438
- pointFrom28(lastPointerUpCoords.x, lastPointerUpCoords.y),
33497
+ pointFrom29(lastPointerUpCoords.x, lastPointerUpCoords.y),
33439
33498
  this.device.editor.isMobile
33440
33499
  );
33441
33500
  if (lastPointerDownHittingLinkIcon && lastPointerUpHittingLinkIcon) {
@@ -33445,7 +33504,7 @@ var App = class _App extends React43.Component {
33445
33504
  url = normalizeLink3(url);
33446
33505
  let customEvent;
33447
33506
  if (this.props.onLinkOpen) {
33448
- customEvent = wrapEvent2(EVENT13.EXCALIDRAW_LINK, event.nativeEvent);
33507
+ customEvent = wrapEvent2(EVENT14.EXCALIDRAW_LINK, event.nativeEvent);
33449
33508
  this.props.onLinkOpen(
33450
33509
  {
33451
33510
  ...this.hitLinkElement,
@@ -33468,7 +33527,7 @@ var App = class _App extends React43.Component {
33468
33527
  __publicField(this, "getTopLayerFrameAtSceneCoords", (sceneCoords) => {
33469
33528
  const elementsMap = this.scene.getNonDeletedElementsMap();
33470
33529
  const frames = this.scene.getNonDeletedFramesLikes().filter(
33471
- (frame) => isCursorInFrame(sceneCoords, frame, elementsMap)
33530
+ (frame) => !frame.locked && isCursorInFrame(sceneCoords, frame, elementsMap)
33472
33531
  );
33473
33532
  return frames.length ? frames[frames.length - 1] : null;
33474
33533
  });
@@ -33611,7 +33670,7 @@ var App = class _App extends React43.Component {
33611
33670
  setCursorForShape(this.interactiveCanvas, this.state);
33612
33671
  if (lastPoint === lastCommittedPoint) {
33613
33672
  if (pointDistance8(
33614
- pointFrom28(scenePointerX - rx, scenePointerY - ry),
33673
+ pointFrom29(scenePointerX - rx, scenePointerY - ry),
33615
33674
  lastPoint
33616
33675
  ) >= LINE_CONFIRM_THRESHOLD2) {
33617
33676
  this.scene.mutateElement(
@@ -33619,7 +33678,7 @@ var App = class _App extends React43.Component {
33619
33678
  {
33620
33679
  points: [
33621
33680
  ...points,
33622
- pointFrom28(scenePointerX - rx, scenePointerY - ry)
33681
+ pointFrom29(scenePointerX - rx, scenePointerY - ry)
33623
33682
  ]
33624
33683
  },
33625
33684
  { informMutation: false, isDragging: false }
@@ -33628,7 +33687,7 @@ var App = class _App extends React43.Component {
33628
33687
  setCursor(this.interactiveCanvas, CURSOR_TYPE4.POINTER);
33629
33688
  }
33630
33689
  } else if (points.length > 2 && lastCommittedPoint && pointDistance8(
33631
- pointFrom28(scenePointerX - rx, scenePointerY - ry),
33690
+ pointFrom29(scenePointerX - rx, scenePointerY - ry),
33632
33691
  lastCommittedPoint
33633
33692
  ) < LINE_CONFIRM_THRESHOLD2) {
33634
33693
  setCursor(this.interactiveCanvas, CURSOR_TYPE4.POINTER);
@@ -33666,7 +33725,7 @@ var App = class _App extends React43.Component {
33666
33725
  {
33667
33726
  points: [
33668
33727
  ...points.slice(0, -1),
33669
- pointFrom28(
33728
+ pointFrom29(
33670
33729
  lastCommittedX + dxFromLastCommitted,
33671
33730
  lastCommittedY + dyFromLastCommitted
33672
33731
  )
@@ -33682,7 +33741,7 @@ var App = class _App extends React43.Component {
33682
33741
  return;
33683
33742
  }
33684
33743
  const hasDeselectedButton = Boolean(event.buttons);
33685
- if (hasDeselectedButton || this.state.activeTool.type !== "selection" && this.state.activeTool.type !== "text" && this.state.activeTool.type !== "eraser") {
33744
+ if (hasDeselectedButton || this.state.activeTool.type !== "selection" && this.state.activeTool.type !== "lasso" && this.state.activeTool.type !== "text" && this.state.activeTool.type !== "eraser") {
33686
33745
  return;
33687
33746
  }
33688
33747
  const elements = this.scene.getNonDeletedElements();
@@ -33796,7 +33855,9 @@ var App = class _App extends React43.Component {
33796
33855
  });
33797
33856
  } else if (!hitElement || // Ebow arrows can only be moved when unconnected
33798
33857
  !isElbowArrow11(hitElement) || !(hitElement.startBinding || hitElement.endBinding)) {
33799
- setCursor(this.interactiveCanvas, CURSOR_TYPE4.MOVE);
33858
+ if (this.state.activeTool.type !== "lasso" || selectedElements.length > 0) {
33859
+ setCursor(this.interactiveCanvas, CURSOR_TYPE4.MOVE);
33860
+ }
33800
33861
  if (this.state.activeEmbeddable?.state === "hover") {
33801
33862
  this.setState({ activeEmbeddable: null });
33802
33863
  }
@@ -33957,7 +34018,7 @@ var App = class _App extends React43.Component {
33957
34018
  };
33958
34019
  const unsubPointerUp = addEventListener2(
33959
34020
  window,
33960
- EVENT13.POINTER_UP,
34021
+ EVENT14.POINTER_UP,
33961
34022
  onPointerUp2,
33962
34023
  {
33963
34024
  once: true
@@ -33994,11 +34055,76 @@ var App = class _App extends React43.Component {
33994
34055
  return;
33995
34056
  }
33996
34057
  if (this.state.activeTool.type === "lasso") {
33997
- this.lassoTrail.startPath(
33998
- pointerDownState.origin.x,
33999
- pointerDownState.origin.y,
34000
- event.shiftKey
34001
- );
34058
+ const hitSelectedElement = pointerDownState.hit.element && this.isASelectedElement(pointerDownState.hit.element);
34059
+ const isMobileOrTablet = this.isMobileOrTablet();
34060
+ if (!pointerDownState.hit.hasHitCommonBoundingBoxOfSelectedElements && !pointerDownState.resize.handleType && !hitSelectedElement) {
34061
+ this.lassoTrail.startPath(
34062
+ pointerDownState.origin.x,
34063
+ pointerDownState.origin.y,
34064
+ event.shiftKey
34065
+ );
34066
+ pointerDownState.drag.blockDragging = !isMobileOrTablet;
34067
+ }
34068
+ if (isMobileOrTablet && pointerDownState.hit.element && !hitSelectedElement) {
34069
+ this.setState((prevState) => {
34070
+ const nextSelectedElementIds = {
34071
+ ...prevState.selectedElementIds,
34072
+ [pointerDownState.hit.element.id]: true
34073
+ };
34074
+ const previouslySelectedElements = [];
34075
+ Object.keys(prevState.selectedElementIds).forEach((id) => {
34076
+ const element = this.scene.getElement(id);
34077
+ element && previouslySelectedElements.push(element);
34078
+ });
34079
+ const hitElement = pointerDownState.hit.element;
34080
+ if (isFrameLikeElement15(hitElement)) {
34081
+ getFrameChildren6(previouslySelectedElements, hitElement.id).forEach(
34082
+ (element) => {
34083
+ delete nextSelectedElementIds[element.id];
34084
+ }
34085
+ );
34086
+ } else if (hitElement.frameId) {
34087
+ if (nextSelectedElementIds[hitElement.frameId]) {
34088
+ delete nextSelectedElementIds[hitElement.id];
34089
+ }
34090
+ } else {
34091
+ const groupIds = hitElement.groupIds;
34092
+ const framesInGroups = new Set(
34093
+ groupIds.flatMap(
34094
+ (gid) => getElementsInGroup9(this.scene.getNonDeletedElements(), gid)
34095
+ ).filter((element) => isFrameLikeElement15(element)).map((frame) => frame.id)
34096
+ );
34097
+ if (framesInGroups.size > 0) {
34098
+ previouslySelectedElements.forEach((element) => {
34099
+ if (element.frameId && framesInGroups.has(element.frameId)) {
34100
+ delete nextSelectedElementIds[element.id];
34101
+ element.groupIds.flatMap(
34102
+ (gid) => getElementsInGroup9(
34103
+ this.scene.getNonDeletedElements(),
34104
+ gid
34105
+ )
34106
+ ).forEach((element2) => {
34107
+ delete nextSelectedElementIds[element2.id];
34108
+ });
34109
+ }
34110
+ });
34111
+ }
34112
+ }
34113
+ return {
34114
+ ...selectGroupsForSelectedElements6(
34115
+ {
34116
+ editingGroupId: prevState.editingGroupId,
34117
+ selectedElementIds: nextSelectedElementIds
34118
+ },
34119
+ this.scene.getNonDeletedElements(),
34120
+ prevState,
34121
+ this
34122
+ ),
34123
+ showHyperlinkPopup: hitElement.link || isEmbeddableElement4(hitElement) ? "info" : false
34124
+ };
34125
+ });
34126
+ pointerDownState.hit.wasAddedToSelection = true;
34127
+ }
34002
34128
  } else if (this.state.activeTool.type === "text") {
34003
34129
  this.handleTextOnPointerDown(event, pointerDownState);
34004
34130
  } else if (this.state.activeTool.type === "arrow" || this.state.activeTool.type === "line") {
@@ -34051,10 +34177,10 @@ var App = class _App extends React43.Component {
34051
34177
  (_event) => onPointerUp(_event || event.nativeEvent)
34052
34178
  );
34053
34179
  if (!this.state.viewModeEnabled || this.state.activeTool.type === "laser") {
34054
- window.addEventListener(EVENT13.POINTER_MOVE, onPointerMove);
34055
- window.addEventListener(EVENT13.POINTER_UP, onPointerUp);
34056
- window.addEventListener(EVENT13.KEYDOWN, onKeyDown);
34057
- window.addEventListener(EVENT13.KEYUP, onKeyUp);
34180
+ window.addEventListener(EVENT14.POINTER_MOVE, onPointerMove);
34181
+ window.addEventListener(EVENT14.POINTER_UP, onPointerUp);
34182
+ window.addEventListener(EVENT14.KEYDOWN, onKeyDown);
34183
+ window.addEventListener(EVENT14.KEYUP, onKeyUp);
34058
34184
  pointerDownState.eventListeners.onMove = onPointerMove;
34059
34185
  pointerDownState.eventListeners.onUp = onPointerUp;
34060
34186
  pointerDownState.eventListeners.onKeyUp = onKeyUp;
@@ -34102,7 +34228,7 @@ var App = class _App extends React43.Component {
34102
34228
  this.hitLinkElement,
34103
34229
  this.scene.getNonDeletedElementsMap(),
34104
34230
  this.state,
34105
- pointFrom28(scenePointer.x, scenePointer.y)
34231
+ pointFrom29(scenePointer.x, scenePointer.y)
34106
34232
  )) {
34107
34233
  this.handleEmbeddableCenterClick(this.hitLinkElement);
34108
34234
  } else {
@@ -34166,17 +34292,17 @@ var App = class _App extends React43.Component {
34166
34292
  if (isLinux && !nextPastePrevented && (Math.abs(deltaX) > 1 || Math.abs(deltaY) > 1)) {
34167
34293
  nextPastePrevented = true;
34168
34294
  const preventNextPaste = (event3) => {
34169
- document.body.removeEventListener(EVENT13.PASTE, preventNextPaste);
34295
+ document.body.removeEventListener(EVENT14.PASTE, preventNextPaste);
34170
34296
  event3.stopPropagation();
34171
34297
  };
34172
34298
  const enableNextPaste = () => {
34173
34299
  setTimeout(() => {
34174
- document.body.removeEventListener(EVENT13.PASTE, preventNextPaste);
34175
- window.removeEventListener(EVENT13.POINTER_UP, enableNextPaste);
34300
+ document.body.removeEventListener(EVENT14.PASTE, preventNextPaste);
34301
+ window.removeEventListener(EVENT14.POINTER_UP, enableNextPaste);
34176
34302
  }, 100);
34177
34303
  };
34178
- document.body.addEventListener(EVENT13.PASTE, preventNextPaste);
34179
- window.addEventListener(EVENT13.POINTER_UP, enableNextPaste);
34304
+ document.body.addEventListener(EVENT14.PASTE, preventNextPaste);
34305
+ window.addEventListener(EVENT14.POINTER_UP, enableNextPaste);
34180
34306
  }
34181
34307
  this.translateCanvas({
34182
34308
  scrollX: this.state.scrollX - deltaX / this.state.zoom.value,
@@ -34198,17 +34324,17 @@ var App = class _App extends React43.Component {
34198
34324
  cursorButton: "up"
34199
34325
  });
34200
34326
  this.savePointer(event.clientX, event.clientY, "up");
34201
- window.removeEventListener(EVENT13.POINTER_MOVE, onPointerMove);
34202
- window.removeEventListener(EVENT13.POINTER_UP, teardown);
34203
- window.removeEventListener(EVENT13.BLUR, teardown);
34327
+ window.removeEventListener(EVENT14.POINTER_MOVE, onPointerMove);
34328
+ window.removeEventListener(EVENT14.POINTER_UP, teardown);
34329
+ window.removeEventListener(EVENT14.BLUR, teardown);
34204
34330
  onPointerMove.flush();
34205
34331
  }
34206
34332
  );
34207
- window.addEventListener(EVENT13.BLUR, teardown);
34208
- window.addEventListener(EVENT13.POINTER_MOVE, onPointerMove, {
34333
+ window.addEventListener(EVENT14.BLUR, teardown);
34334
+ window.addEventListener(EVENT14.POINTER_MOVE, onPointerMove, {
34209
34335
  passive: true
34210
34336
  });
34211
- window.addEventListener(EVENT13.POINTER_UP, teardown);
34337
+ window.addEventListener(EVENT14.POINTER_UP, teardown);
34212
34338
  return true;
34213
34339
  });
34214
34340
  __publicField(this, "clearSelectionIfNotUsingSelection", () => {
@@ -34225,7 +34351,7 @@ var App = class _App extends React43.Component {
34225
34351
  * @returns whether the pointer event has been completely handled
34226
34352
  */
34227
34353
  __publicField(this, "handleSelectionOnPointerDown", (event, pointerDownState) => {
34228
- if (this.state.activeTool.type === "selection") {
34354
+ if (this.state.activeTool.type === "selection" || this.state.activeTool.type === "lasso") {
34229
34355
  const elements = this.scene.getNonDeletedElements();
34230
34356
  const elementsMap = this.scene.getNonDeletedElementsMap();
34231
34357
  const selectedElements = this.scene.getSelectedElements(this.state);
@@ -34375,6 +34501,15 @@ var App = class _App extends React43.Component {
34375
34501
  } else if (hitElement != null) {
34376
34502
  if (event[KEYS52.CTRL_OR_CMD]) {
34377
34503
  if (event.altKey) {
34504
+ if (this.state.openDialog?.name === "elementLinkSelector") {
34505
+ this.setOpenDialog(null);
34506
+ }
34507
+ this.lassoTrail.startPath(
34508
+ pointerDownState.origin.x,
34509
+ pointerDownState.origin.y,
34510
+ event.shiftKey
34511
+ );
34512
+ this.setActiveTool({ type: "lasso", fromSelection: true });
34378
34513
  return false;
34379
34514
  }
34380
34515
  if (!this.state.selectedElementIds[hitElement.id]) {
@@ -34501,7 +34636,9 @@ var App = class _App extends React43.Component {
34501
34636
  resetCursor(this.interactiveCanvas);
34502
34637
  if (!this.state.activeTool.locked) {
34503
34638
  this.setState({
34504
- activeTool: updateActiveTool7(this.state, { type: "selection" })
34639
+ activeTool: updateActiveTool7(this.state, {
34640
+ type: this.defaultSelectionTool
34641
+ })
34505
34642
  });
34506
34643
  }
34507
34644
  });
@@ -34531,7 +34668,7 @@ var App = class _App extends React43.Component {
34531
34668
  simulatePressure,
34532
34669
  locked: false,
34533
34670
  frameId: topLayerFrame ? topLayerFrame.id : null,
34534
- points: [pointFrom28(0, 0)],
34671
+ points: [pointFrom29(0, 0)],
34535
34672
  pressures: simulatePressure ? [] : [event.pressure]
34536
34673
  });
34537
34674
  this.scene.insertElement(element);
@@ -34630,11 +34767,10 @@ var App = class _App extends React43.Component {
34630
34767
  this.scene.insertElement(element);
34631
34768
  return element;
34632
34769
  });
34633
- __publicField(this, "createImageElement", async ({
34770
+ __publicField(this, "newImagePlaceholder", ({
34634
34771
  sceneX,
34635
34772
  sceneY,
34636
- addToFrameUnderCursor = true,
34637
- imageFile
34773
+ addToFrameUnderCursor = true
34638
34774
  }) => {
34639
34775
  const [gridX, gridY] = getGridPoint2(
34640
34776
  sceneX,
@@ -34646,7 +34782,7 @@ var App = class _App extends React43.Component {
34646
34782
  y: gridY
34647
34783
  }) : null;
34648
34784
  const placeholderSize = 100 / this.state.zoom.value;
34649
- const placeholderImageElement = newImageElement2({
34785
+ return newImageElement2({
34650
34786
  type: "image",
34651
34787
  strokeColor: this.state.currentItemStrokeColor,
34652
34788
  backgroundColor: this.state.currentItemBackgroundColor,
@@ -34663,11 +34799,6 @@ var App = class _App extends React43.Component {
34663
34799
  width: placeholderSize,
34664
34800
  height: placeholderSize
34665
34801
  });
34666
- const initializedImageElement = await this.insertImageElement(
34667
- placeholderImageElement,
34668
- imageFile
34669
- );
34670
- return initializedImageElement;
34671
34802
  });
34672
34803
  __publicField(this, "handleLinearElementOnPointerDown", (event, elementType, pointerDownState) => {
34673
34804
  if (this.state.multiElement) {
@@ -34688,7 +34819,7 @@ var App = class _App extends React43.Component {
34688
34819
  }
34689
34820
  const { x: rx, y: ry, lastCommittedPoint } = multiElement;
34690
34821
  if (multiElement.points.length > 1 && lastCommittedPoint && pointDistance8(
34691
- pointFrom28(
34822
+ pointFrom29(
34692
34823
  pointerDownState.origin.x - rx,
34693
34824
  pointerDownState.origin.y - ry
34694
34825
  ),
@@ -34772,7 +34903,7 @@ var App = class _App extends React43.Component {
34772
34903
  };
34773
34904
  });
34774
34905
  this.scene.mutateElement(element, {
34775
- points: [...element.points, pointFrom28(0, 0)]
34906
+ points: [...element.points, pointFrom29(0, 0)]
34776
34907
  });
34777
34908
  const boundElement = getHoveredElementForBinding2(
34778
34909
  pointerDownState.origin,
@@ -34867,7 +34998,7 @@ var App = class _App extends React43.Component {
34867
34998
  const elements = this.scene.getElementsIncludingDeleted().map((ele) => {
34868
34999
  if (this.elementsPendingErasure.has(ele.id) || ele.frameId && this.elementsPendingErasure.has(ele.frameId) || isBoundToContainer8(ele) && this.elementsPendingErasure.has(ele.containerId)) {
34869
35000
  didChange = true;
34870
- return newElementWith10(ele, { isDeleted: true });
35001
+ return newElementWith11(ele, { isDeleted: true });
34871
35002
  }
34872
35003
  return ele;
34873
35004
  });
@@ -34883,7 +35014,7 @@ var App = class _App extends React43.Component {
34883
35014
  }
34884
35015
  const mimeType = imageFile.type;
34885
35016
  setCursor(this.interactiveCanvas, "wait");
34886
- if (mimeType === MIME_TYPES8.svg) {
35017
+ if (mimeType === MIME_TYPES9.svg) {
34887
35018
  try {
34888
35019
  imageFile = SVGStringToFile(
34889
35020
  normalizeSVG(await imageFile.text()),
@@ -34976,57 +35107,14 @@ var App = class _App extends React43.Component {
34976
35107
  */
34977
35108
  __publicField(this, "getLatestInitializedImageElement", (imagePlaceholder, fileId) => {
34978
35109
  const latestImageElement = this.scene.getElement(imagePlaceholder.id) ?? imagePlaceholder;
34979
- return newElementWith10(
35110
+ return newElementWith11(
34980
35111
  latestImageElement,
34981
35112
  {
34982
35113
  fileId
34983
35114
  }
34984
35115
  );
34985
35116
  });
34986
- /**
34987
- * inserts image into elements array and rerenders
34988
- */
34989
- __publicField(this, "insertImageElement", async (placeholderImageElement, imageFile) => {
34990
- if (!this.isToolSupported("image")) {
34991
- this.setState({ errorMessage: t("errors.imageToolNotSupported") });
34992
- return;
34993
- }
34994
- this.scene.insertElement(placeholderImageElement);
34995
- try {
34996
- const initializedImageElement = await this.initializeImage(
34997
- placeholderImageElement,
34998
- imageFile
34999
- );
35000
- const nextElements = this.scene.getElementsIncludingDeleted().map((element) => {
35001
- if (element.id === initializedImageElement.id) {
35002
- return initializedImageElement;
35003
- }
35004
- return element;
35005
- });
35006
- this.updateScene({
35007
- captureUpdate: CaptureUpdateAction37.IMMEDIATELY,
35008
- elements: nextElements,
35009
- appState: {
35010
- selectedElementIds: makeNextSelectedElementIds2(
35011
- { [initializedImageElement.id]: true },
35012
- this.state
35013
- )
35014
- }
35015
- });
35016
- return initializedImageElement;
35017
- } catch (error) {
35018
- this.store.scheduleAction(CaptureUpdateAction37.NEVER);
35019
- this.scene.mutateElement(placeholderImageElement, {
35020
- isDeleted: true
35021
- });
35022
- this.actionManager.executeAction(actionFinalize);
35023
- this.setState({
35024
- errorMessage: error.message || t("errors.imageInsertError")
35025
- });
35026
- return null;
35027
- }
35028
- });
35029
- __publicField(this, "onImageAction", async () => {
35117
+ __publicField(this, "onImageToolbarButtonClick", async () => {
35030
35118
  try {
35031
35119
  const clientX = this.state.width / 2 + this.state.offsetLeft;
35032
35120
  const clientY = this.state.height / 2 + this.state.offsetTop;
@@ -35034,21 +35122,14 @@ var App = class _App extends React43.Component {
35034
35122
  { clientX, clientY },
35035
35123
  this.state
35036
35124
  );
35037
- const imageFile = await fileOpen({
35125
+ const imageFiles = await fileOpen({
35038
35126
  description: "Image",
35039
35127
  extensions: Object.keys(
35040
35128
  IMAGE_MIME_TYPES2
35041
- )
35042
- });
35043
- await this.createImageElement({
35044
- sceneX: x,
35045
- sceneY: y,
35046
- addToFrameUnderCursor: false,
35047
- imageFile
35048
- });
35049
- this.setState({}, () => {
35050
- this.actionManager.executeAction(actionFinalize);
35129
+ ),
35130
+ multiple: true
35051
35131
  });
35132
+ this.insertImages(imageFiles, x, y);
35052
35133
  } catch (error) {
35053
35134
  if (error.name !== "AbortError") {
35054
35135
  console.error(error);
@@ -35058,7 +35139,9 @@ var App = class _App extends React43.Component {
35058
35139
  this.setState(
35059
35140
  {
35060
35141
  newElement: null,
35061
- activeTool: updateActiveTool7(this.state, { type: "selection" })
35142
+ activeTool: updateActiveTool7(this.state, {
35143
+ type: this.defaultSelectionTool
35144
+ })
35062
35145
  },
35063
35146
  () => {
35064
35147
  this.actionManager.executeAction(actionFinalize);
@@ -35095,9 +35178,9 @@ var App = class _App extends React43.Component {
35095
35178
  if (erroredFiles.size) {
35096
35179
  this.store.scheduleAction(CaptureUpdateAction37.NEVER);
35097
35180
  this.scene.replaceAllElements(
35098
- elements.map((element) => {
35181
+ this.scene.getElementsIncludingDeleted().map((element) => {
35099
35182
  if (isInitializedImageElement3(element) && erroredFiles.has(element.fileId)) {
35100
- return newElementWith10(element, {
35183
+ return newElementWith11(element, {
35101
35184
  status: "error"
35102
35185
  });
35103
35186
  }
@@ -35159,64 +35242,105 @@ var App = class _App extends React43.Component {
35159
35242
  if (canvas !== null) {
35160
35243
  this.interactiveCanvas = canvas;
35161
35244
  this.interactiveCanvas.addEventListener(
35162
- EVENT13.TOUCH_START,
35245
+ EVENT14.TOUCH_START,
35163
35246
  this.onTouchStart,
35164
35247
  { passive: false }
35165
35248
  );
35166
- this.interactiveCanvas.addEventListener(EVENT13.TOUCH_END, this.onTouchEnd);
35249
+ this.interactiveCanvas.addEventListener(EVENT14.TOUCH_END, this.onTouchEnd);
35167
35250
  } else {
35168
35251
  this.interactiveCanvas?.removeEventListener(
35169
- EVENT13.TOUCH_START,
35252
+ EVENT14.TOUCH_START,
35170
35253
  this.onTouchStart
35171
35254
  );
35172
35255
  this.interactiveCanvas?.removeEventListener(
35173
- EVENT13.TOUCH_END,
35256
+ EVENT14.TOUCH_END,
35174
35257
  this.onTouchEnd
35175
35258
  );
35176
35259
  }
35177
35260
  });
35261
+ __publicField(this, "insertImages", async (imageFiles, sceneX, sceneY) => {
35262
+ const gridPadding = 50 / this.state.zoom.value;
35263
+ const placeholders = positionElementsOnGrid(
35264
+ imageFiles.map(() => this.newImagePlaceholder({ sceneX, sceneY })),
35265
+ sceneX,
35266
+ sceneY,
35267
+ gridPadding
35268
+ );
35269
+ placeholders.forEach((el) => this.scene.insertElement(el));
35270
+ const initialized = await Promise.all(
35271
+ placeholders.map(async (placeholder, i) => {
35272
+ try {
35273
+ return await this.initializeImage(placeholder, imageFiles[i]);
35274
+ } catch (error) {
35275
+ this.setState({
35276
+ errorMessage: error.message || t("errors.imageInsertError")
35277
+ });
35278
+ return newElementWith11(placeholder, { isDeleted: true });
35279
+ }
35280
+ })
35281
+ );
35282
+ const initializedMap = arrayToMap27(initialized);
35283
+ const positioned = positionElementsOnGrid(
35284
+ initialized.filter((el) => !el.isDeleted),
35285
+ sceneX,
35286
+ sceneY,
35287
+ gridPadding
35288
+ );
35289
+ const positionedMap = arrayToMap27(positioned);
35290
+ const nextElements = this.scene.getElementsIncludingDeleted().map((el) => positionedMap.get(el.id) ?? initializedMap.get(el.id) ?? el);
35291
+ this.updateScene({
35292
+ appState: {
35293
+ selectedElementIds: makeNextSelectedElementIds2(
35294
+ Object.fromEntries(positioned.map((el) => [el.id, true])),
35295
+ this.state
35296
+ )
35297
+ },
35298
+ elements: nextElements,
35299
+ captureUpdate: CaptureUpdateAction37.IMMEDIATELY
35300
+ });
35301
+ this.setState({}, () => {
35302
+ this.actionManager.executeAction(actionFinalize);
35303
+ });
35304
+ });
35178
35305
  __publicField(this, "handleAppOnDrop", async (event) => {
35179
- const { file: file2, fileHandle } = await getFileFromEvent(event);
35180
35306
  const { x: sceneX, y: sceneY } = viewportCoordsToSceneCoords4(
35181
35307
  event,
35182
35308
  this.state
35183
35309
  );
35184
- try {
35185
- if (isSupportedImageFile(file2) && this.isToolSupported("image")) {
35186
- if (file2?.type === MIME_TYPES8.png || file2?.type === MIME_TYPES8.svg) {
35187
- try {
35188
- const scene = await loadFromBlob(
35189
- file2,
35190
- this.state,
35191
- this.scene.getElementsIncludingDeleted(),
35192
- fileHandle
35193
- );
35194
- this.syncActionResult({
35195
- ...scene,
35196
- appState: {
35197
- ...scene.appState || this.state,
35198
- isLoading: false
35199
- },
35200
- replaceFiles: true,
35201
- captureUpdate: CaptureUpdateAction37.IMMEDIATELY
35202
- });
35203
- return;
35204
- } catch (error) {
35205
- if (error.name !== "EncodingError") {
35206
- throw new Error(t("alerts.couldNotLoadInvalidFile"));
35207
- }
35310
+ const dataTransferList = await parseDataTransferEvent(event);
35311
+ const fileItems = dataTransferList.getFiles();
35312
+ if (fileItems.length === 1) {
35313
+ const { file: file2, fileHandle } = fileItems[0];
35314
+ if (file2 && (file2.type === MIME_TYPES9.png || file2.type === MIME_TYPES9.svg)) {
35315
+ try {
35316
+ const scene = await loadFromBlob(
35317
+ file2,
35318
+ this.state,
35319
+ this.scene.getElementsIncludingDeleted(),
35320
+ fileHandle
35321
+ );
35322
+ this.syncActionResult({
35323
+ ...scene,
35324
+ appState: {
35325
+ ...scene.appState || this.state,
35326
+ isLoading: false
35327
+ },
35328
+ replaceFiles: true,
35329
+ captureUpdate: CaptureUpdateAction37.IMMEDIATELY
35330
+ });
35331
+ return;
35332
+ } catch (error) {
35333
+ if (error.name !== "EncodingError") {
35334
+ throw new Error(t("alerts.couldNotLoadInvalidFile"));
35208
35335
  }
35209
35336
  }
35210
- this.createImageElement({ sceneX, sceneY, imageFile: file2 });
35211
- return;
35212
35337
  }
35213
- } catch (error) {
35214
- return this.setState({
35215
- isLoading: false,
35216
- errorMessage: error.message
35217
- });
35218
35338
  }
35219
- const libraryJSON = event.dataTransfer.getData(MIME_TYPES8.excalidrawlib);
35339
+ const imageFiles = fileItems.map((data) => data.file).filter((file2) => isSupportedImageFile(file2));
35340
+ if (imageFiles.length > 0 && this.isToolSupported("image")) {
35341
+ return this.insertImages(imageFiles, sceneX, sceneY);
35342
+ }
35343
+ const libraryJSON = dataTransferList.getData(MIME_TYPES9.excalidrawlib);
35220
35344
  if (libraryJSON && typeof libraryJSON === "string") {
35221
35345
  try {
35222
35346
  const libraryItems = parseLibraryJSON(libraryJSON);
@@ -35230,11 +35354,15 @@ var App = class _App extends React43.Component {
35230
35354
  }
35231
35355
  return;
35232
35356
  }
35233
- if (file2) {
35234
- await this.loadFileToCanvas(file2, fileHandle);
35357
+ if (fileItems.length > 0) {
35358
+ const { file: file2, fileHandle } = fileItems[0];
35359
+ if (file2) {
35360
+ await this.loadFileToCanvas(file2, fileHandle);
35361
+ }
35235
35362
  }
35236
- if (event.dataTransfer?.types?.includes("text/plain")) {
35237
- const text = event.dataTransfer?.getData("text");
35363
+ const textItem = dataTransferList.findByType(MIME_TYPES9.text);
35364
+ if (textItem) {
35365
+ const text = textItem.value;
35238
35366
  if (text && embeddableURLValidator2(text, this.props.validateEmbeddable) && (/^(http|https):\/\/[^\s/$.?#].[^\s]*$/.test(text) || getEmbedLink2(text)?.type === "video")) {
35239
35367
  const embeddable = this.insertEmbeddableElement({
35240
35368
  sceneX,
@@ -35278,7 +35406,7 @@ var App = class _App extends React43.Component {
35278
35406
  if (!ret) {
35279
35407
  return;
35280
35408
  }
35281
- if (ret.type === MIME_TYPES8.excalidraw) {
35409
+ if (ret.type === MIME_TYPES9.excalidraw) {
35282
35410
  syncInvalidIndices2(elements.concat(ret.data.elements));
35283
35411
  this.store.scheduleMicroAction({
35284
35412
  action: CaptureUpdateAction37.NEVER,
@@ -35295,7 +35423,7 @@ var App = class _App extends React43.Component {
35295
35423
  replaceFiles: true,
35296
35424
  captureUpdate: CaptureUpdateAction37.IMMEDIATELY
35297
35425
  });
35298
- } else if (ret.type === MIME_TYPES8.excalidrawlib) {
35426
+ } else if (ret.type === MIME_TYPES9.excalidrawlib) {
35299
35427
  await this.library.updateLibrary({
35300
35428
  libraryItems: file2,
35301
35429
  merge: true,
@@ -35312,7 +35440,7 @@ var App = class _App extends React43.Component {
35312
35440
  __publicField(this, "handleCanvasContextMenu", (event) => {
35313
35441
  event.preventDefault();
35314
35442
  if (("pointerType" in event.nativeEvent && event.nativeEvent.pointerType === "touch" || "pointerType" in event.nativeEvent && event.nativeEvent.pointerType === "pen" && // always allow if user uses a pen secondary button
35315
- event.button !== POINTER_BUTTON2.SECONDARY) && this.state.activeTool.type !== "selection") {
35443
+ event.button !== POINTER_BUTTON2.SECONDARY) && this.state.activeTool.type !== this.defaultSelectionTool) {
35316
35444
  return;
35317
35445
  }
35318
35446
  const { x, y } = viewportCoordsToSceneCoords4(event, this.state);
@@ -35801,6 +35929,7 @@ var App = class _App extends React43.Component {
35801
35929
  this.setState({ ...this.getCanvasOffsets() });
35802
35930
  });
35803
35931
  const defaultAppState = getDefaultAppState();
35932
+ this.defaultSelectionTool = this.isMobileOrTablet() ? "lasso" : "selection";
35804
35933
  const {
35805
35934
  excalidrawAPI,
35806
35935
  viewModeEnabled = false,
@@ -35841,6 +35970,7 @@ var App = class _App extends React43.Component {
35841
35970
  if (excalidrawAPI) {
35842
35971
  const api = {
35843
35972
  updateScene: this.updateScene,
35973
+ applyDeltas: this.applyDeltas,
35844
35974
  mutateElement: this.mutateElement,
35845
35975
  updateLibrary: this.library.updateLibrary,
35846
35976
  addFiles: this.addFiles,
@@ -36320,7 +36450,7 @@ var App = class _App extends React43.Component {
36320
36450
  showExitZenModeBtn: typeof this.props?.zenModeEnabled === "undefined" && this.state.zenModeEnabled,
36321
36451
  UIOptions: this.props.UIOptions,
36322
36452
  onExportImage: this.onExportImage,
36323
- renderWelcomeScreen: !this.state.isLoading && this.state.showWelcomeScreen && this.state.activeTool.type === "selection" && !this.state.zenModeEnabled && !this.scene.getElementsIncludingDeleted().length,
36453
+ renderWelcomeScreen: !this.state.isLoading && this.state.showWelcomeScreen && this.state.activeTool.type === this.defaultSelectionTool && !this.state.zenModeEnabled && !this.scene.getElementsIncludingDeleted().length,
36324
36454
  app: this,
36325
36455
  isCollaborating: this.props.isCollaborating,
36326
36456
  generateLinkForSelection: this.props.generateLinkForSelection,
@@ -36754,26 +36884,26 @@ var App = class _App extends React43.Component {
36754
36884
  this.removeEventListeners();
36755
36885
  if (this.props.handleKeyboardGlobally) {
36756
36886
  this.onRemoveEventListenersEmitter.once(
36757
- addEventListener2(document, EVENT13.KEYDOWN, this.onKeyDown, false)
36887
+ addEventListener2(document, EVENT14.KEYDOWN, this.onKeyDown, false)
36758
36888
  );
36759
36889
  }
36760
36890
  this.onRemoveEventListenersEmitter.once(
36761
36891
  addEventListener2(
36762
36892
  this.excalidrawContainerRef.current,
36763
- EVENT13.WHEEL,
36893
+ EVENT14.WHEEL,
36764
36894
  this.handleWheel,
36765
36895
  { passive: false }
36766
36896
  ),
36767
- addEventListener2(window, EVENT13.MESSAGE, this.onWindowMessage, false),
36768
- addEventListener2(document, EVENT13.POINTER_UP, this.removePointer, {
36897
+ addEventListener2(window, EVENT14.MESSAGE, this.onWindowMessage, false),
36898
+ addEventListener2(document, EVENT14.POINTER_UP, this.removePointer, {
36769
36899
  passive: false
36770
36900
  }),
36771
36901
  // #3553
36772
- addEventListener2(document, EVENT13.COPY, this.onCopy, { passive: false }),
36773
- addEventListener2(document, EVENT13.KEYUP, this.onKeyUp, { passive: true }),
36902
+ addEventListener2(document, EVENT14.COPY, this.onCopy, { passive: false }),
36903
+ addEventListener2(document, EVENT14.KEYUP, this.onKeyUp, { passive: true }),
36774
36904
  addEventListener2(
36775
36905
  document,
36776
- EVENT13.POINTER_MOVE,
36906
+ EVENT14.POINTER_MOVE,
36777
36907
  this.updateCurrentCursorPosition,
36778
36908
  { passive: false }
36779
36909
  ),
@@ -36790,25 +36920,25 @@ var App = class _App extends React43.Component {
36790
36920
  // Safari-only desktop pinch zoom
36791
36921
  addEventListener2(
36792
36922
  document,
36793
- EVENT13.GESTURE_START,
36923
+ EVENT14.GESTURE_START,
36794
36924
  this.onGestureStart,
36795
36925
  false
36796
36926
  ),
36797
36927
  addEventListener2(
36798
36928
  document,
36799
- EVENT13.GESTURE_CHANGE,
36929
+ EVENT14.GESTURE_CHANGE,
36800
36930
  this.onGestureChange,
36801
36931
  false
36802
36932
  ),
36803
36933
  addEventListener2(
36804
36934
  document,
36805
- EVENT13.GESTURE_END,
36935
+ EVENT14.GESTURE_END,
36806
36936
  this.onGestureEnd,
36807
36937
  false
36808
36938
  ),
36809
36939
  addEventListener2(
36810
36940
  window,
36811
- EVENT13.FOCUS,
36941
+ EVENT14.FOCUS,
36812
36942
  () => {
36813
36943
  this.maybeCleanupAfterMissingPointerUp(null);
36814
36944
  this.triggerRender(true);
@@ -36822,32 +36952,32 @@ var App = class _App extends React43.Component {
36822
36952
  this.onRemoveEventListenersEmitter.once(
36823
36953
  addEventListener2(
36824
36954
  document,
36825
- EVENT13.FULLSCREENCHANGE,
36955
+ EVENT14.FULLSCREENCHANGE,
36826
36956
  this.onFullscreenChange,
36827
36957
  { passive: false }
36828
36958
  ),
36829
- addEventListener2(document, EVENT13.PASTE, this.pasteFromClipboard, {
36959
+ addEventListener2(document, EVENT14.PASTE, this.pasteFromClipboard, {
36830
36960
  passive: false
36831
36961
  }),
36832
- addEventListener2(document, EVENT13.CUT, this.onCut, { passive: false }),
36833
- addEventListener2(window, EVENT13.RESIZE, this.onResize, false),
36834
- addEventListener2(window, EVENT13.UNLOAD, this.onUnload, false),
36835
- addEventListener2(window, EVENT13.BLUR, this.onBlur, false),
36962
+ addEventListener2(document, EVENT14.CUT, this.onCut, { passive: false }),
36963
+ addEventListener2(window, EVENT14.RESIZE, this.onResize, false),
36964
+ addEventListener2(window, EVENT14.UNLOAD, this.onUnload, false),
36965
+ addEventListener2(window, EVENT14.BLUR, this.onBlur, false),
36836
36966
  addEventListener2(
36837
36967
  this.excalidrawContainerRef.current,
36838
- EVENT13.WHEEL,
36968
+ EVENT14.WHEEL,
36839
36969
  this.handleWheel,
36840
36970
  { passive: false }
36841
36971
  ),
36842
36972
  addEventListener2(
36843
36973
  this.excalidrawContainerRef.current,
36844
- EVENT13.DRAG_OVER,
36974
+ EVENT14.DRAG_OVER,
36845
36975
  this.disableEvent,
36846
36976
  false
36847
36977
  ),
36848
36978
  addEventListener2(
36849
36979
  this.excalidrawContainerRef.current,
36850
- EVENT13.DROP,
36980
+ EVENT14.DROP,
36851
36981
  this.disableEvent,
36852
36982
  false
36853
36983
  )
@@ -36856,7 +36986,7 @@ var App = class _App extends React43.Component {
36856
36986
  this.onRemoveEventListenersEmitter.once(
36857
36987
  addEventListener2(
36858
36988
  getNearestScrollableContainer(this.excalidrawContainerRef.current),
36859
- EVENT13.SCROLL,
36989
+ EVENT14.SCROLL,
36860
36990
  this.onScroll,
36861
36991
  { passive: false }
36862
36992
  )
@@ -36962,6 +37092,115 @@ var App = class _App extends React43.Component {
36962
37092
  }
36963
37093
  static resetTapTwice() {
36964
37094
  didTapTwice = false;
37095
+ firstTapPosition = null;
37096
+ }
37097
+ // TODO: Cover with tests
37098
+ async insertClipboardContent(data, dataTransferFiles, isPlainPaste) {
37099
+ const { x: sceneX, y: sceneY } = viewportCoordsToSceneCoords4(
37100
+ {
37101
+ clientX: this.lastViewportPosition.x,
37102
+ clientY: this.lastViewportPosition.y
37103
+ },
37104
+ this.state
37105
+ );
37106
+ if (data.errorMessage) {
37107
+ this.setState({ errorMessage: data.errorMessage });
37108
+ return;
37109
+ }
37110
+ if (dataTransferFiles.length === 0 && !isPlainPaste && data.mixedContent) {
37111
+ await this.addElementsFromMixedContentPaste(data.mixedContent, {
37112
+ isPlainPaste,
37113
+ sceneX,
37114
+ sceneY
37115
+ });
37116
+ return;
37117
+ }
37118
+ if (data.spreadsheet && !isPlainPaste) {
37119
+ this.setState({
37120
+ pasteDialog: {
37121
+ data: data.spreadsheet,
37122
+ shown: true
37123
+ }
37124
+ });
37125
+ return;
37126
+ }
37127
+ const imageFiles = dataTransferFiles.map((data2) => data2.file);
37128
+ if (imageFiles.length === 0 && data.text && !isPlainPaste) {
37129
+ const trimmedText = data.text.trim();
37130
+ if (trimmedText.startsWith("<svg") && trimmedText.endsWith("</svg>")) {
37131
+ imageFiles.push(SVGStringToFile(trimmedText));
37132
+ }
37133
+ }
37134
+ if (imageFiles.length > 0) {
37135
+ if (this.isToolSupported("image")) {
37136
+ await this.insertImages(imageFiles, sceneX, sceneY);
37137
+ } else {
37138
+ this.setState({ errorMessage: t("errors.imageToolNotSupported") });
37139
+ }
37140
+ return;
37141
+ }
37142
+ if (data.elements) {
37143
+ const elements = data.programmaticAPI ? convertToExcalidrawElements(
37144
+ data.elements
37145
+ ) : data.elements;
37146
+ this.addElementsFromPasteOrLibrary({
37147
+ elements,
37148
+ files: data.files || null,
37149
+ position: this.isMobileOrTablet() ? "center" : "cursor",
37150
+ retainSeed: isPlainPaste
37151
+ });
37152
+ return;
37153
+ }
37154
+ if (!data.text) {
37155
+ return;
37156
+ }
37157
+ if (!isPlainPaste && isMaybeMermaidDefinition(data.text)) {
37158
+ const api = await import("@excalidraw/mermaid-to-excalidraw");
37159
+ try {
37160
+ const { elements: skeletonElements, files } = await api.parseMermaidToExcalidraw(data.text);
37161
+ const elements = convertToExcalidrawElements(skeletonElements, {
37162
+ regenerateIds: true
37163
+ });
37164
+ this.addElementsFromPasteOrLibrary({
37165
+ elements,
37166
+ files,
37167
+ position: this.isMobileOrTablet() ? "center" : "cursor"
37168
+ });
37169
+ return;
37170
+ } catch (err) {
37171
+ console.warn(
37172
+ `parsing pasted text as mermaid definition failed: ${err.message}`
37173
+ );
37174
+ }
37175
+ }
37176
+ const nonEmptyLines = normalizeEOL2(data.text).split(/\n+/).map((s) => s.trim()).filter(Boolean);
37177
+ const embbeddableUrls = nonEmptyLines.map((str) => maybeParseEmbedSrc(str)).filter(
37178
+ (string) => embeddableURLValidator2(string, this.props.validateEmbeddable) && (/^(http|https):\/\/[^\s/$.?#].[^\s]*$/.test(string) || getEmbedLink2(string)?.type === "video")
37179
+ );
37180
+ if (!isPlainPaste && embbeddableUrls.length > 0 && embbeddableUrls.length === nonEmptyLines.length) {
37181
+ const embeddables = [];
37182
+ for (const url of embbeddableUrls) {
37183
+ const prevEmbeddable = embeddables[embeddables.length - 1];
37184
+ const embeddable = this.insertEmbeddableElement({
37185
+ sceneX: prevEmbeddable ? prevEmbeddable.x + prevEmbeddable.width + 20 : sceneX,
37186
+ sceneY,
37187
+ link: normalizeLink3(url)
37188
+ });
37189
+ if (embeddable) {
37190
+ embeddables.push(embeddable);
37191
+ }
37192
+ }
37193
+ if (embeddables.length) {
37194
+ this.store.scheduleCapture();
37195
+ this.setState({
37196
+ selectedElementIds: Object.fromEntries(
37197
+ embeddables.map((embeddable) => [embeddable.id, true])
37198
+ )
37199
+ });
37200
+ }
37201
+ return;
37202
+ }
37203
+ this.addTextFromPaste(data.text, isPlainPaste);
36965
37204
  }
36966
37205
  // TODO rewrite this to paste both text & images at the same time if
36967
37206
  // pasted data contains both
@@ -36987,37 +37226,8 @@ var App = class _App extends React43.Component {
36987
37226
  }
36988
37227
  })
36989
37228
  );
36990
- let y = sceneY;
36991
- let firstImageYOffsetDone = false;
36992
- const nextSelectedIds = {};
36993
- for (const response of responses) {
36994
- if (response.file) {
36995
- const initializedImageElement = await this.createImageElement({
36996
- sceneX,
36997
- sceneY: y,
36998
- imageFile: response.file
36999
- });
37000
- if (initializedImageElement) {
37001
- if (!firstImageYOffsetDone) {
37002
- firstImageYOffsetDone = true;
37003
- y -= initializedImageElement.height / 2;
37004
- }
37005
- this.scene.mutateElement(
37006
- initializedImageElement,
37007
- { y },
37008
- { informMutation: false, isDragging: false }
37009
- );
37010
- y = initializedImageElement.y + initializedImageElement.height + 25;
37011
- nextSelectedIds[initializedImageElement.id] = true;
37012
- }
37013
- }
37014
- }
37015
- this.setState({
37016
- selectedElementIds: makeNextSelectedElementIds2(
37017
- nextSelectedIds,
37018
- this.state
37019
- )
37020
- });
37229
+ const imageFiles = responses.filter((response) => !!response.file).map((response) => response.file);
37230
+ await this.insertImages(imageFiles, sceneX, sceneY);
37021
37231
  const error = responses.find((response) => !!response.errorMessage);
37022
37232
  if (error && error.errorMessage) {
37023
37233
  this.setState({ errorMessage: error.errorMessage });
@@ -37134,7 +37344,7 @@ var App = class _App extends React43.Component {
37134
37344
  // Not sure why we include deleted elements as well hence using deleted elements map
37135
37345
  ...this.scene.getElementsIncludingDeleted().map((_element) => {
37136
37346
  if (_element.id === element.id && isTextElement19(_element)) {
37137
- return newElementWith10(_element, {
37347
+ return newElementWith11(_element, {
37138
37348
  originalText: nextOriginalText,
37139
37349
  isDeleted: isDeleted ?? _element.isDeleted,
37140
37350
  // returns (wrapped) text and new dimensions
@@ -37174,13 +37384,7 @@ var App = class _App extends React43.Component {
37174
37384
  }),
37175
37385
  onSubmit: withBatchedUpdates(({ viaKeyboard, nextOriginalText }) => {
37176
37386
  const isDeleted = !nextOriginalText.trim();
37177
- if (isDeleted && !isExistingElement) {
37178
- this.scene.replaceAllElements(
37179
- this.scene.getElementsIncludingDeleted().filter((x) => x.id !== element.id)
37180
- );
37181
- } else {
37182
- updateElement(nextOriginalText, isDeleted);
37183
- }
37387
+ updateElement(nextOriginalText, isDeleted);
37184
37388
  if (!isDeleted && viaKeyboard) {
37185
37389
  const elementIdToSelect = element.containerId ? element.containerId : element.id;
37186
37390
  flushSync3(() => {
@@ -37200,7 +37404,9 @@ var App = class _App extends React43.Component {
37200
37404
  element
37201
37405
  ]);
37202
37406
  }
37203
- this.store.scheduleCapture();
37407
+ if (!isDeleted || isExistingElement) {
37408
+ this.store.scheduleCapture();
37409
+ }
37204
37410
  flushSync3(() => {
37205
37411
  this.setState({
37206
37412
  newElement: null,
@@ -37262,7 +37468,7 @@ var App = class _App extends React43.Component {
37262
37468
  }
37263
37469
  const elementWithHighestZIndex = allHitElements[allHitElements.length - 1];
37264
37470
  return hitElementItself({
37265
- point: pointFrom28(x, y),
37471
+ point: pointFrom29(x, y),
37266
37472
  element: elementWithHighestZIndex,
37267
37473
  // when overlapping, we would like to be more precise
37268
37474
  // this also avoids the need to update past tests
@@ -37306,7 +37512,7 @@ var App = class _App extends React43.Component {
37306
37512
  hitElement(x, y, element, considerBoundingBox = true) {
37307
37513
  if (considerBoundingBox && this.state.selectedElementIds[element.id] && shouldShowBoundingBox2([element], this.state)) {
37308
37514
  if (hitElementBoundingBox2(
37309
- pointFrom28(x, y),
37515
+ pointFrom29(x, y),
37310
37516
  element,
37311
37517
  this.scene.getNonDeletedElementsMap(),
37312
37518
  this.getElementHitThreshold(element)
@@ -37315,7 +37521,7 @@ var App = class _App extends React43.Component {
37315
37521
  }
37316
37522
  }
37317
37523
  const hitBoundTextOfElement = hitElementBoundText(
37318
- pointFrom28(x, y),
37524
+ pointFrom29(x, y),
37319
37525
  element,
37320
37526
  this.scene.getNonDeletedElementsMap()
37321
37527
  );
@@ -37323,7 +37529,7 @@ var App = class _App extends React43.Component {
37323
37529
  return true;
37324
37530
  }
37325
37531
  return hitElementItself({
37326
- point: pointFrom28(x, y),
37532
+ point: pointFrom29(x, y),
37327
37533
  element,
37328
37534
  threshold: this.getElementHitThreshold(element),
37329
37535
  elementsMap: this.scene.getNonDeletedElementsMap(),
@@ -37346,7 +37552,7 @@ var App = class _App extends React43.Component {
37346
37552
  this.scene.getNonDeletedElementsMap()
37347
37553
  );
37348
37554
  if (isArrowElement12(elements[index]) && hitElementItself({
37349
- point: pointFrom28(x, y),
37555
+ point: pointFrom29(x, y),
37350
37556
  element: elements[index],
37351
37557
  elementsMap: this.scene.getNonDeletedElementsMap(),
37352
37558
  threshold: this.getElementHitThreshold(elements[index])
@@ -37373,7 +37579,7 @@ var App = class _App extends React43.Component {
37373
37579
  let hoverPointIndex = -1;
37374
37580
  let segmentMidPointHoveredCoords = null;
37375
37581
  if (hitElementItself({
37376
- point: pointFrom28(scenePointerX, scenePointerY),
37582
+ point: pointFrom29(scenePointerX, scenePointerY),
37377
37583
  element,
37378
37584
  elementsMap,
37379
37585
  threshold: this.getElementHitThreshold(element)
@@ -37399,7 +37605,9 @@ var App = class _App extends React43.Component {
37399
37605
  // Ebow arrows can only be moved when unconnected
37400
37606
  !isElbowArrow11(element) || !(element.startBinding || element.endBinding)
37401
37607
  ) {
37402
- setCursor(this.interactiveCanvas, CURSOR_TYPE4.MOVE);
37608
+ if (this.state.activeTool.type !== "lasso" || Object.keys(this.state.selectedElementIds).length > 0) {
37609
+ setCursor(this.interactiveCanvas, CURSOR_TYPE4.MOVE);
37610
+ }
37403
37611
  }
37404
37612
  }
37405
37613
  } else if (this.hitElement(scenePointerX, scenePointerY, element)) {
@@ -37407,7 +37615,9 @@ var App = class _App extends React43.Component {
37407
37615
  // Ebow arrows can only be moved when unconnected
37408
37616
  !isElbowArrow11(element) || !(element.startBinding || element.endBinding)
37409
37617
  ) {
37410
- setCursor(this.interactiveCanvas, CURSOR_TYPE4.MOVE);
37618
+ if (this.state.activeTool.type !== "lasso" || Object.keys(this.state.selectedElementIds).length > 0) {
37619
+ setCursor(this.interactiveCanvas, CURSOR_TYPE4.MOVE);
37620
+ }
37411
37621
  }
37412
37622
  }
37413
37623
  if (this.state.selectedLinearElement.hoverPointIndex !== hoverPointIndex) {
@@ -37492,7 +37702,8 @@ var App = class _App extends React43.Component {
37492
37702
  drag: {
37493
37703
  hasOccurred: false,
37494
37704
  offset: null,
37495
- origin: { ...origin }
37705
+ origin: { ...origin },
37706
+ blockDragging: false
37496
37707
  },
37497
37708
  eventListeners: {
37498
37709
  onMove: null,
@@ -37528,13 +37739,13 @@ var App = class _App extends React43.Component {
37528
37739
  cursorButton: "up"
37529
37740
  });
37530
37741
  this.savePointer(event.clientX, event.clientY, "up");
37531
- window.removeEventListener(EVENT13.POINTER_MOVE, onPointerMove);
37532
- window.removeEventListener(EVENT13.POINTER_UP, onPointerUp);
37742
+ window.removeEventListener(EVENT14.POINTER_MOVE, onPointerMove);
37743
+ window.removeEventListener(EVENT14.POINTER_UP, onPointerUp);
37533
37744
  onPointerMove.flush();
37534
37745
  });
37535
37746
  lastPointerUp = onPointerUp;
37536
- window.addEventListener(EVENT13.POINTER_MOVE, onPointerMove);
37537
- window.addEventListener(EVENT13.POINTER_UP, onPointerUp);
37747
+ window.addEventListener(EVENT14.POINTER_MOVE, onPointerMove);
37748
+ window.addEventListener(EVENT14.POINTER_UP, onPointerUp);
37538
37749
  return true;
37539
37750
  }
37540
37751
  isASelectedElement(hitElement) {
@@ -37688,8 +37899,8 @@ var App = class _App extends React43.Component {
37688
37899
  );
37689
37900
  if (!pointerDownState.drag.hasOccurred && (this.state.activeTool.type === "arrow" || this.state.activeTool.type === "line")) {
37690
37901
  if (pointDistance8(
37691
- pointFrom28(pointerCoords.x, pointerCoords.y),
37692
- pointFrom28(pointerDownState.origin.x, pointerDownState.origin.y)
37902
+ pointFrom29(pointerCoords.x, pointerCoords.y),
37903
+ pointFrom29(pointerDownState.origin.x, pointerDownState.origin.y)
37693
37904
  ) * this.state.zoom.value < MINIMUM_ARROW_SIZE) {
37694
37905
  return;
37695
37906
  }
@@ -37758,9 +37969,9 @@ var App = class _App extends React43.Component {
37758
37969
  (element) => this.isASelectedElement(element)
37759
37970
  );
37760
37971
  const isSelectingPointsInLineEditor = this.state.selectedLinearElement?.isEditing && event.shiftKey && this.state.selectedLinearElement.elementId === pointerDownState.hit.element?.id;
37761
- if ((hasHitASelectedElement || pointerDownState.hit.hasHitCommonBoundingBoxOfSelectedElements) && !isSelectingPointsInLineEditor && this.state.activeTool.type !== "lasso") {
37972
+ if ((hasHitASelectedElement || pointerDownState.hit.hasHitCommonBoundingBoxOfSelectedElements) && !isSelectingPointsInLineEditor && !pointerDownState.drag.blockDragging) {
37762
37973
  const selectedElements = this.scene.getSelectedElements(this.state);
37763
- if (selectedElements.every((element) => element.locked)) {
37974
+ if (selectedElements.length > 0 && selectedElements.every((element) => element.locked)) {
37764
37975
  return;
37765
37976
  }
37766
37977
  const selectedElementsHasAFrame = selectedElements.find(
@@ -37774,6 +37985,12 @@ var App = class _App extends React43.Component {
37774
37985
  });
37775
37986
  }
37776
37987
  pointerDownState.drag.hasOccurred = true;
37988
+ if (this.state.activeTool.type === "lasso" && this.lassoTrail.hasCurrentTrail && !(this.isMobileOrTablet() && pointerDownState.hit.element) && !this.state.activeTool.fromSelection) {
37989
+ return;
37990
+ }
37991
+ if (this.state.activeTool.type === "lasso" && selectedElements.length > 0 && pointerDownState.drag.hasOccurred && !this.state.activeTool.fromSelection) {
37992
+ this.lassoTrail.endPath();
37993
+ }
37777
37994
  if (selectedElements.length > 0 && !pointerDownState.withCmdOrCtrl && !this.state.editingTextElement && this.state.activeEmbeddable?.state !== "active") {
37778
37995
  const dragOffset = {
37779
37996
  x: pointerCoords.x - pointerDownState.drag.origin.x,
@@ -37813,23 +38030,23 @@ var App = class _App extends React43.Component {
37813
38030
  elementsMap
37814
38031
  );
37815
38032
  const topLeft = vectorFromPoint9(
37816
- pointRotateRads16(
37817
- pointFrom28(x1, y1),
37818
- pointFrom28(cx, cy),
38033
+ pointRotateRads17(
38034
+ pointFrom29(x1, y1),
38035
+ pointFrom29(cx, cy),
37819
38036
  croppingElement.angle
37820
38037
  )
37821
38038
  );
37822
38039
  const topRight = vectorFromPoint9(
37823
- pointRotateRads16(
37824
- pointFrom28(x2, y1),
37825
- pointFrom28(cx, cy),
38040
+ pointRotateRads17(
38041
+ pointFrom29(x2, y1),
38042
+ pointFrom29(cx, cy),
37826
38043
  croppingElement.angle
37827
38044
  )
37828
38045
  );
37829
38046
  const bottomLeft = vectorFromPoint9(
37830
- pointRotateRads16(
37831
- pointFrom28(x1, y2),
37832
- pointFrom28(cx, cy),
38047
+ pointRotateRads17(
38048
+ pointFrom29(x1, y2),
38049
+ pointFrom29(cx, cy),
37833
38050
  croppingElement.angle
37834
38051
  )
37835
38052
  );
@@ -37950,7 +38167,7 @@ var App = class _App extends React43.Component {
37950
38167
  if (idsOfElementsToDuplicate.has(el.id)) {
37951
38168
  const origEl = pointerDownState.originalElements.get(el.id);
37952
38169
  if (origEl) {
37953
- return newElementWith10(el, {
38170
+ return newElementWith11(el, {
37954
38171
  x: origEl.x,
37955
38172
  y: origEl.y
37956
38173
  });
@@ -38054,7 +38271,7 @@ var App = class _App extends React43.Component {
38054
38271
  this.scene.mutateElement(
38055
38272
  newElement6,
38056
38273
  {
38057
- points: [...points, pointFrom28(dx, dy)],
38274
+ points: [...points, pointFrom29(dx, dy)],
38058
38275
  pressures
38059
38276
  },
38060
38277
  {
@@ -38083,7 +38300,7 @@ var App = class _App extends React43.Component {
38083
38300
  this.scene.mutateElement(
38084
38301
  newElement6,
38085
38302
  {
38086
- points: [...points, pointFrom28(dx, dy)]
38303
+ points: [...points, pointFrom29(dx, dy)]
38087
38304
  },
38088
38305
  { informMutation: false, isDragging: false }
38089
38306
  );
@@ -38091,7 +38308,7 @@ var App = class _App extends React43.Component {
38091
38308
  this.scene.mutateElement(
38092
38309
  newElement6,
38093
38310
  {
38094
- points: [...points.slice(0, -1), pointFrom28(dx, dy)]
38311
+ points: [...points.slice(0, -1), pointFrom29(dx, dy)]
38095
38312
  },
38096
38313
  { isDragging: true, informMutation: false }
38097
38314
  );
@@ -38219,6 +38436,7 @@ var App = class _App extends React43.Component {
38219
38436
  onPointerUpFromPointerDownHandler(pointerDownState) {
38220
38437
  return withBatchedUpdates((childEvent) => {
38221
38438
  this.removePointer(childEvent);
38439
+ pointerDownState.drag.blockDragging = false;
38222
38440
  if (pointerDownState.eventListeners.onMove) {
38223
38441
  pointerDownState.eventListeners.onMove.flush();
38224
38442
  }
@@ -38333,19 +38551,19 @@ var App = class _App extends React43.Component {
38333
38551
  }
38334
38552
  this.missingPointerEventCleanupEmitter.clear();
38335
38553
  window.removeEventListener(
38336
- EVENT13.POINTER_MOVE,
38554
+ EVENT14.POINTER_MOVE,
38337
38555
  pointerDownState.eventListeners.onMove
38338
38556
  );
38339
38557
  window.removeEventListener(
38340
- EVENT13.POINTER_UP,
38558
+ EVENT14.POINTER_UP,
38341
38559
  pointerDownState.eventListeners.onUp
38342
38560
  );
38343
38561
  window.removeEventListener(
38344
- EVENT13.KEYDOWN,
38562
+ EVENT14.KEYDOWN,
38345
38563
  pointerDownState.eventListeners.onKeyDown
38346
38564
  );
38347
38565
  window.removeEventListener(
38348
- EVENT13.KEYUP,
38566
+ EVENT14.KEYUP,
38349
38567
  pointerDownState.eventListeners.onKeyUp
38350
38568
  );
38351
38569
  this.props?.onPointerUp?.(activeTool, pointerDownState);
@@ -38368,9 +38586,9 @@ var App = class _App extends React43.Component {
38368
38586
  }
38369
38587
  const pressures = newElement6.simulatePressure ? [] : [...newElement6.pressures, childEvent.pressure];
38370
38588
  this.scene.mutateElement(newElement6, {
38371
- points: [...points, pointFrom28(dx, dy)],
38589
+ points: [...points, pointFrom29(dx, dy)],
38372
38590
  pressures,
38373
- lastCommittedPoint: pointFrom28(dx, dy)
38591
+ lastCommittedPoint: pointFrom29(dx, dy)
38374
38592
  });
38375
38593
  this.actionManager.executeAction(actionFinalize);
38376
38594
  return;
@@ -38384,8 +38602,8 @@ var App = class _App extends React43.Component {
38384
38602
  this.state
38385
38603
  );
38386
38604
  const dragDistance = pointDistance8(
38387
- pointFrom28(pointerCoords.x, pointerCoords.y),
38388
- pointFrom28(pointerDownState.origin.x, pointerDownState.origin.y)
38605
+ pointFrom29(pointerCoords.x, pointerCoords.y),
38606
+ pointFrom29(pointerDownState.origin.x, pointerDownState.origin.y)
38389
38607
  ) * this.state.zoom.value;
38390
38608
  if ((!pointerDownState.drag.hasOccurred || dragDistance < MINIMUM_ARROW_SIZE) && newElement6 && !multiElement) {
38391
38609
  if (this.device.isTouchScreen) {
@@ -38398,8 +38616,8 @@ var App = class _App extends React43.Component {
38398
38616
  {
38399
38617
  x: newElement6.x - FIXED_DELTA_X / 2,
38400
38618
  points: [
38401
- pointFrom28(0, 0),
38402
- pointFrom28(FIXED_DELTA_X, 0)
38619
+ pointFrom29(0, 0),
38620
+ pointFrom29(FIXED_DELTA_X, 0)
38403
38621
  ]
38404
38622
  },
38405
38623
  { informMutation: false, isDragging: false }
@@ -38411,7 +38629,7 @@ var App = class _App extends React43.Component {
38411
38629
  this.scene.mutateElement(
38412
38630
  newElement6,
38413
38631
  {
38414
- points: [...newElement6.points, pointFrom28(dx, dy)]
38632
+ points: [...newElement6.points, pointFrom29(dx, dy)]
38415
38633
  },
38416
38634
  { informMutation: false, isDragging: false }
38417
38635
  );
@@ -38433,7 +38651,7 @@ var App = class _App extends React43.Component {
38433
38651
  this.setState((prevState) => ({
38434
38652
  newElement: null,
38435
38653
  activeTool: updateActiveTool7(this.state, {
38436
- type: "selection"
38654
+ type: this.defaultSelectionTool
38437
38655
  }),
38438
38656
  selectedElementIds: makeNextSelectedElementIds2(
38439
38657
  {
@@ -38660,8 +38878,8 @@ var App = class _App extends React43.Component {
38660
38878
  if (isEraserActive(this.state) && pointerStart && pointerEnd) {
38661
38879
  this.eraserTrail.endPath();
38662
38880
  const draggedDistance = pointDistance8(
38663
- pointFrom28(pointerStart.clientX, pointerStart.clientY),
38664
- pointFrom28(pointerEnd.clientX, pointerEnd.clientY)
38881
+ pointFrom29(pointerStart.clientX, pointerStart.clientY),
38882
+ pointFrom29(pointerEnd.clientX, pointerEnd.clientY)
38665
38883
  );
38666
38884
  if (draggedDistance === 0) {
38667
38885
  const scenePointer = viewportCoordsToSceneCoords4(
@@ -38807,7 +39025,7 @@ var App = class _App extends React43.Component {
38807
39025
  !this.state.isResizing && // only hitting the bounding box of the previous hit element
38808
39026
  (hitElement && hitElementBoundingBoxOnly(
38809
39027
  {
38810
- point: pointFrom28(
39028
+ point: pointFrom29(
38811
39029
  pointerDownState.origin.x,
38812
39030
  pointerDownState.origin.y
38813
39031
  ),
@@ -38870,7 +39088,9 @@ var App = class _App extends React43.Component {
38870
39088
  this.setState({
38871
39089
  newElement: null,
38872
39090
  suggestedBindings: [],
38873
- activeTool: updateActiveTool7(this.state, { type: "selection" })
39091
+ activeTool: updateActiveTool7(this.state, {
39092
+ type: this.defaultSelectionTool
39093
+ })
38874
39094
  });
38875
39095
  } else {
38876
39096
  this.setState({
@@ -39326,8 +39546,7 @@ import {
39326
39546
  } from "@excalidraw/element";
39327
39547
  var shouldDiscardRemoteElement = (localAppState, local, remote) => {
39328
39548
  if (local && // local element is being edited
39329
- (local.id === localAppState.editingTextElement?.id || local.id === localAppState.resizingElement?.id || local.id === localAppState.newElement?.id || // TODO: Is this still valid? As newElement is selection element, which is never part of the elements array
39330
- // local element is newer
39549
+ (local.id === localAppState.editingTextElement?.id || local.id === localAppState.resizingElement?.id || local.id === localAppState.newElement?.id || // local element is newer
39331
39550
  local.version > remote.version || // resolve conflicting edits deterministically by taking the one with
39332
39551
  // the lowest versionNonce
39333
39552
  local.version === remote.version && local.versionNonce < remote.versionNonce)) {
@@ -39394,7 +39613,7 @@ import { isLinearElement as isLinearElement14 } from "@excalidraw/element";
39394
39613
  import {
39395
39614
  FONT_FAMILY as FONT_FAMILY5,
39396
39615
  THEME as THEME16,
39397
- MIME_TYPES as MIME_TYPES9,
39616
+ MIME_TYPES as MIME_TYPES10,
39398
39617
  ROUNDNESS as ROUNDNESS3,
39399
39618
  DEFAULT_LASER_COLOR as DEFAULT_LASER_COLOR2,
39400
39619
  UserIdleState as UserIdleState2,
@@ -39402,7 +39621,7 @@ import {
39402
39621
  } from "@excalidraw/common";
39403
39622
  import {
39404
39623
  mutateElement as mutateElement2,
39405
- newElementWith as newElementWith11,
39624
+ newElementWith as newElementWith12,
39406
39625
  bumpVersion
39407
39626
  } from "@excalidraw/element";
39408
39627
  import { CaptureUpdateAction as CaptureUpdateAction38 } from "@excalidraw/element";
@@ -39614,7 +39833,7 @@ export {
39614
39833
  FONT_FAMILY5 as FONT_FAMILY,
39615
39834
  FooterCenter_default as Footer,
39616
39835
  LiveCollaborationTrigger_default as LiveCollaborationTrigger,
39617
- MIME_TYPES9 as MIME_TYPES,
39836
+ MIME_TYPES10 as MIME_TYPES,
39618
39837
  MainMenu_default as MainMenu,
39619
39838
  ROUNDNESS3 as ROUNDNESS,
39620
39839
  Sidebar,
@@ -39653,12 +39872,13 @@ export {
39653
39872
  loadSceneOrLibraryFromBlob,
39654
39873
  mergeLibraryItems,
39655
39874
  mutateElement2 as mutateElement,
39656
- newElementWith11 as newElementWith,
39875
+ newElementWith12 as newElementWith,
39657
39876
  normalizeLink4 as normalizeLink,
39658
39877
  parseLibraryTokensFromUrl,
39659
39878
  reconcileElements,
39660
39879
  restore,
39661
39880
  restoreAppState,
39881
+ restoreElement,
39662
39882
  restoreElements,
39663
39883
  restoreLibraryItems,
39664
39884
  sceneCoordsToViewportCoords2 as sceneCoordsToViewportCoords,