@excalidraw/excalidraw 0.18.0-39ce38a0d-200a6bd94 → 0.18.0-414182f

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 (36) hide show
  1. package/dist/dev/{chunk-Y7B3JU7D.js → chunk-CP5DND7P.js} +2 -2
  2. package/dist/dev/{chunk-Y7B3JU7D.js.map → chunk-CP5DND7P.js.map} +1 -1
  3. package/dist/dev/{chunk-GZYPVQVV.js → chunk-WWDIUJ2Q.js} +34 -30
  4. package/dist/dev/chunk-WWDIUJ2Q.js.map +7 -0
  5. package/dist/dev/data/{image-V3RGFWEQ.js → image-VTYIFRQE.js} +3 -3
  6. package/dist/dev/index.js +960 -734
  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-ATYYHCCY.js → chunk-A66AFZZU.js} +1 -1
  11. package/dist/prod/{chunk-QH2XZQ34.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 +6 -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 -1
  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/restore.d.ts +6 -1
  30. package/dist/types/excalidraw/index.d.ts +1 -1
  31. package/dist/types/excalidraw/types.d.ts +5 -2
  32. package/history.ts +1 -1
  33. package/package.json +5 -5
  34. package/dist/dev/chunk-GZYPVQVV.js.map +0 -7
  35. package/dist/prod/data/image-4FTETSFG.js +0 -1
  36. /package/dist/dev/data/{image-V3RGFWEQ.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-GZYPVQVV.js";
72
+ } from "./chunk-WWDIUJ2Q.js";
72
73
  import {
73
74
  define_import_meta_env_default
74
- } from "./chunk-Y7B3JU7D.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,90 @@ 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 {
8807
+ type: file2.type,
8808
+ kind: "file",
8809
+ file: await normalizeFile(file2),
8810
+ fileHandle
8811
+ };
8812
+ }
8813
+ } else if (item.kind === "string") {
8814
+ const { type } = item;
8815
+ let value;
8816
+ if ("clipboardData" in event && event.clipboardData) {
8817
+ value = event.clipboardData?.getData(type);
8818
+ } else {
8819
+ value = await new Promise((resolve) => {
8820
+ item.getAsString((str) => resolve(str));
8821
+ });
8822
+ }
8823
+ return { type, kind: "string", value };
8824
+ }
8825
+ return null;
8826
+ }
8827
+ )
8828
+ )).filter((data) => data != null);
8829
+ return Object.assign(dataItems, {
8830
+ findByType: findDataTransferItemType,
8831
+ getData: getDataTransferItemData,
8832
+ getFiles: getDataTransferFiles
8833
+ });
8834
+ };
8835
+ var parseClipboard = async (dataList, isPlainPaste = false) => {
8743
8836
  const parsedEventData = await parseClipboardEventTextData(
8744
- event,
8837
+ dataList,
8745
8838
  isPlainPaste
8746
8839
  );
8747
8840
  if (parsedEventData.type === "mixedContent") {
@@ -8843,6 +8936,9 @@ var copyTextViaExecCommand = (text) => {
8843
8936
  textarea.remove();
8844
8937
  return success;
8845
8938
  };
8939
+ var isClipboardEvent = (event) => {
8940
+ return event.type === EVENT5.PASTE || event.type === EVENT5.COPY || event.type === EVENT5.CUT;
8941
+ };
8846
8942
 
8847
8943
  // data/index.ts
8848
8944
  var prepareElementsForExport = (elements, { selectedElementIds }, exportSelectionOnly) => {
@@ -8936,7 +9032,7 @@ var exportCanvas = async (type, elements, appState, files, {
8936
9032
  let blob = canvasToBlob(tempCanvas);
8937
9033
  if (appState.exportEmbedScene) {
8938
9034
  blob = blob.then(
8939
- (blob2) => import("./data/image-V3RGFWEQ.js").then(
9035
+ (blob2) => import("./data/image-VTYIFRQE.js").then(
8940
9036
  ({ encodePngMetadata: encodePngMetadata2 }) => encodePngMetadata2({
8941
9037
  blob: blob2,
8942
9038
  metadata: serializeAsJSON(elements, appState, files, "local")
@@ -9277,7 +9373,7 @@ import {
9277
9373
  KEYS as KEYS16,
9278
9374
  getLineHeight as getLineHeight2
9279
9375
  } from "@excalidraw/common";
9280
- import { newElementWith as newElementWith4 } from "@excalidraw/element";
9376
+ import { newElementWith as newElementWith5 } from "@excalidraw/element";
9281
9377
  import {
9282
9378
  hasBoundTextElement,
9283
9379
  canApplyRoundnessTypeToElement,
@@ -9348,7 +9444,7 @@ var actionPasteStyles = register({
9348
9444
  if (!elementStylesToCopyFrom) {
9349
9445
  return element;
9350
9446
  }
9351
- let newElement6 = newElementWith4(element, {
9447
+ let newElement6 = newElementWith5(element, {
9352
9448
  backgroundColor: elementStylesToCopyFrom?.backgroundColor,
9353
9449
  strokeWidth: elementStylesToCopyFrom?.strokeWidth,
9354
9450
  strokeColor: elementStylesToCopyFrom?.strokeColor,
@@ -9364,7 +9460,7 @@ var actionPasteStyles = register({
9364
9460
  if (isTextElement3(newElement6)) {
9365
9461
  const fontSize = elementStylesToCopyFrom.fontSize || DEFAULT_FONT_SIZE3;
9366
9462
  const fontFamily = elementStylesToCopyFrom.fontFamily || DEFAULT_FONT_FAMILY3;
9367
- newElement6 = newElementWith4(newElement6, {
9463
+ newElement6 = newElementWith5(newElement6, {
9368
9464
  fontSize,
9369
9465
  fontFamily,
9370
9466
  textAlign: elementStylesToCopyFrom.textAlign || DEFAULT_TEXT_ALIGN,
@@ -9379,13 +9475,13 @@ var actionPasteStyles = register({
9379
9475
  redrawTextBoundingBox2(newElement6, container, app.scene);
9380
9476
  }
9381
9477
  if (newElement6.type === "arrow" && isArrowElement2(elementStylesToCopyFrom)) {
9382
- newElement6 = newElementWith4(newElement6, {
9478
+ newElement6 = newElementWith5(newElement6, {
9383
9479
  startArrowhead: elementStylesToCopyFrom.startArrowhead,
9384
9480
  endArrowhead: elementStylesToCopyFrom.endArrowhead
9385
9481
  });
9386
9482
  }
9387
9483
  if (isFrameLikeElement4(element)) {
9388
- newElement6 = newElementWith4(newElement6, {
9484
+ newElement6 = newElementWith5(newElement6, {
9389
9485
  roundness: null,
9390
9486
  backgroundColor: "transparent"
9391
9487
  });
@@ -9479,7 +9575,7 @@ var actionShortcuts = register({
9479
9575
 
9480
9576
  // actions/actionGroup.tsx
9481
9577
  import { getNonDeletedElements as getNonDeletedElements9 } from "@excalidraw/element";
9482
- import { newElementWith as newElementWith5 } from "@excalidraw/element";
9578
+ import { newElementWith as newElementWith6 } from "@excalidraw/element";
9483
9579
  import { isBoundToContainer as isBoundToContainer3 } from "@excalidraw/element";
9484
9580
  import {
9485
9581
  frameAndChildrenSelectedTogether,
@@ -9583,7 +9679,7 @@ var actionGroup = register({
9583
9679
  if (!selectElementIds.get(element.id)) {
9584
9680
  return element;
9585
9681
  }
9586
- return newElementWith5(element, {
9682
+ return newElementWith6(element, {
9587
9683
  groupIds: addToGroup(
9588
9684
  element.groupIds,
9589
9685
  newGroupId,
@@ -9660,7 +9756,7 @@ var actionUngroup = register({
9660
9756
  if (nextGroupIds.length === element.groupIds.length) {
9661
9757
  return element;
9662
9758
  }
9663
- return newElementWith5(element, {
9759
+ return newElementWith6(element, {
9664
9760
  groupIds: nextGroupIds
9665
9761
  });
9666
9762
  });
@@ -10459,7 +10555,7 @@ import {
10459
10555
  isBindingEnabled as isBindingEnabled2
10460
10556
  } from "@excalidraw/element";
10461
10557
  import { getCommonBoundingBox } from "@excalidraw/element";
10462
- import { newElementWith as newElementWith6 } from "@excalidraw/element";
10558
+ import { newElementWith as newElementWith7 } from "@excalidraw/element";
10463
10559
  import { deepCopyElement as deepCopyElement3 } from "@excalidraw/element";
10464
10560
  import { resizeMultipleElements } from "@excalidraw/element";
10465
10561
  import {
@@ -10545,7 +10641,7 @@ var flipElements = (selectedElements, elementsMap, appState, flipDirection, app)
10545
10641
  )) {
10546
10642
  return selectedElements.map((element) => {
10547
10643
  const _element = element;
10548
- return newElementWith6(_element, {
10644
+ return newElementWith7(_element, {
10549
10645
  startArrowhead: _element.endArrowhead,
10550
10646
  endArrowhead: _element.startArrowhead
10551
10647
  });
@@ -11222,7 +11318,7 @@ import {
11222
11318
  useRef as useRef12,
11223
11319
  useState as useState9
11224
11320
  } from "react";
11225
- import { EVENT as EVENT5, HYPERLINK_TOOLTIP_DELAY, KEYS as KEYS27 } from "@excalidraw/common";
11321
+ import { EVENT as EVENT6, HYPERLINK_TOOLTIP_DELAY, KEYS as KEYS27 } from "@excalidraw/common";
11226
11322
  import { getElementAbsoluteCoords } from "@excalidraw/element";
11227
11323
  import { hitElementBoundingBox } from "@excalidraw/element";
11228
11324
  import { isElementLink } from "@excalidraw/element";
@@ -11353,9 +11449,9 @@ var Hyperlink = ({
11353
11449
  }, AUTO_HIDE_TIMEOUT);
11354
11450
  }
11355
11451
  };
11356
- window.addEventListener(EVENT5.POINTER_MOVE, handlePointerMove, false);
11452
+ window.addEventListener(EVENT6.POINTER_MOVE, handlePointerMove, false);
11357
11453
  return () => {
11358
- window.removeEventListener(EVENT5.POINTER_MOVE, handlePointerMove, false);
11454
+ window.removeEventListener(EVENT6.POINTER_MOVE, handlePointerMove, false);
11359
11455
  if (timeoutId) {
11360
11456
  clearTimeout(timeoutId);
11361
11457
  }
@@ -11414,7 +11510,7 @@ var Hyperlink = ({
11414
11510
  onClick: (event) => {
11415
11511
  if (element.link && onLinkOpen) {
11416
11512
  const customEvent = wrapEvent(
11417
- EVENT5.EXCALIDRAW_LINK,
11513
+ EVENT6.EXCALIDRAW_LINK,
11418
11514
  event.nativeEvent
11419
11515
  );
11420
11516
  onLinkOpen(
@@ -11616,7 +11712,7 @@ var actionLink = register({
11616
11712
  import { KEYS as KEYS29, arrayToMap as arrayToMap11, randomId as randomId4 } from "@excalidraw/common";
11617
11713
  import {
11618
11714
  elementsAreInSameGroup,
11619
- newElementWith as newElementWith7,
11715
+ newElementWith as newElementWith8,
11620
11716
  selectGroupsFromGivenElements
11621
11717
  } from "@excalidraw/element";
11622
11718
  import { CaptureUpdateAction as CaptureUpdateAction25 } from "@excalidraw/element";
@@ -11677,7 +11773,7 @@ var actionToggleElementLock = register({
11677
11773
  (groupId) => !appState.lockedMultiSelections[groupId]
11678
11774
  );
11679
11775
  }
11680
- return newElementWith7(element, {
11776
+ return newElementWith8(element, {
11681
11777
  locked: nextLockState,
11682
11778
  // do not recreate the array unncessarily
11683
11779
  groupIds: nextGroupIds.length !== element.groupIds.length ? nextGroupIds : element.groupIds
@@ -11726,7 +11822,7 @@ var actionUnlockAllElements = register({
11726
11822
  const nextGroupIds = element.groupIds.filter(
11727
11823
  (gid) => !appState.lockedMultiSelections[gid]
11728
11824
  );
11729
- return newElementWith7(element, {
11825
+ return newElementWith8(element, {
11730
11826
  locked: false,
11731
11827
  groupIds: (
11732
11828
  // do not recreate the array unncessarily
@@ -11778,7 +11874,7 @@ import fuzzy from "fuzzy";
11778
11874
  import { useEffect as useEffect27, useRef as useRef23, useState as useState22 } from "react";
11779
11875
  import {
11780
11876
  DEFAULT_SIDEBAR as DEFAULT_SIDEBAR2,
11781
- EVENT as EVENT8,
11877
+ EVENT as EVENT9,
11782
11878
  KEYS as KEYS35,
11783
11879
  capitalizeString as capitalizeString2,
11784
11880
  getShortcutKey as getShortcutKey11,
@@ -12813,7 +12909,7 @@ import {
12813
12909
  URL_HASH_KEYS,
12814
12910
  URL_QUERY_KEYS,
12815
12911
  APP_NAME,
12816
- EVENT as EVENT6,
12912
+ EVENT as EVENT7,
12817
12913
  DEFAULT_SIDEBAR,
12818
12914
  LIBRARY_SIDEBAR_TAB,
12819
12915
  arrayToMap as arrayToMap12,
@@ -12842,7 +12938,8 @@ var exportToCanvas2 = ({
12842
12938
  const { elements: restoredElements, appState: restoredAppState } = restore(
12843
12939
  { elements, appState },
12844
12940
  null,
12845
- null
12941
+ null,
12942
+ { deleteInvisibleElements: true }
12846
12943
  );
12847
12944
  const { exportBackground, viewBackgroundColor } = restoredAppState;
12848
12945
  return exportToCanvas(
@@ -12936,7 +13033,8 @@ var exportToSvg2 = async ({
12936
13033
  const { elements: restoredElements, appState: restoredAppState } = restore(
12937
13034
  { elements, appState },
12938
13035
  null,
12939
- null
13036
+ null,
13037
+ { deleteInvisibleElements: true }
12940
13038
  );
12941
13039
  const exportAppState = {
12942
13040
  ...restoredAppState,
@@ -13519,9 +13617,9 @@ var useHandleLibrary = (opts) => {
13519
13617
  isLibraryLoadedRef.current = true;
13520
13618
  });
13521
13619
  }
13522
- window.addEventListener(EVENT6.HASHCHANGE, onHashChange);
13620
+ window.addEventListener(EVENT7.HASHCHANGE, onHashChange);
13523
13621
  return () => {
13524
- window.removeEventListener(EVENT6.HASHCHANGE, onHashChange);
13622
+ window.removeEventListener(EVENT7.HASHCHANGE, onHashChange);
13525
13623
  };
13526
13624
  }, [
13527
13625
  // important this useEffect only depends on excalidrawAPI so it only reruns
@@ -13566,9 +13664,9 @@ var useHandleLibrary = (opts) => {
13566
13664
  preventUnload(event);
13567
13665
  }
13568
13666
  };
13569
- window.addEventListener(EVENT6.BEFORE_UNLOAD, onUnload);
13667
+ window.addEventListener(EVENT7.BEFORE_UNLOAD, onUnload);
13570
13668
  return () => {
13571
- window.removeEventListener(EVENT6.BEFORE_UNLOAD, onUnload);
13669
+ window.removeEventListener(EVENT7.BEFORE_UNLOAD, onUnload);
13572
13670
  unsubOnLibraryUpdate();
13573
13671
  lastSavedLibraryItemsHash = 0;
13574
13672
  librarySaveCounter = 0;
@@ -14353,7 +14451,7 @@ var PublishLibrary_default = PublishLibrary;
14353
14451
  // components/dropdownMenu/DropdownMenuContent.tsx
14354
14452
  import clsx23 from "clsx";
14355
14453
  import { useEffect as useEffect21, useRef as useRef16 } from "react";
14356
- import { EVENT as EVENT7, KEYS as KEYS30 } from "@excalidraw/common";
14454
+ import { EVENT as EVENT8, KEYS as KEYS30 } from "@excalidraw/common";
14357
14455
 
14358
14456
  // components/Stack.tsx
14359
14457
  import { forwardRef as forwardRef2 } from "react";
@@ -14427,9 +14525,9 @@ var MenuContent = ({
14427
14525
  // event handlers that were bound before this one
14428
14526
  capture: true
14429
14527
  };
14430
- document.addEventListener(EVENT7.KEYDOWN, onKeyDown, option);
14528
+ document.addEventListener(EVENT8.KEYDOWN, onKeyDown, option);
14431
14529
  return () => {
14432
- document.removeEventListener(EVENT7.KEYDOWN, onKeyDown, option);
14530
+ document.removeEventListener(EVENT8.KEYDOWN, onKeyDown, option);
14433
14531
  };
14434
14532
  }, [callbacksRef]);
14435
14533
  const classNames = clsx23(`dropdown-menu ${className}`, {
@@ -14893,7 +14991,7 @@ var LibraryUnit = memo(
14893
14991
  };
14894
14992
  }, [svg]);
14895
14993
  const [isHovered, setIsHovered] = useState15(false);
14896
- const isMobile = useDevice().editor.isMobile;
14994
+ const isMobile2 = useDevice().editor.isMobile;
14897
14995
  const adder = isPending && /* @__PURE__ */ jsx63("div", { className: "library-unit__adder", children: PlusIcon });
14898
14996
  return /* @__PURE__ */ jsxs33(
14899
14997
  "div",
@@ -14933,7 +15031,7 @@ var LibraryUnit = memo(
14933
15031
  }
14934
15032
  ),
14935
15033
  adder,
14936
- id && elements && (isHovered || isMobile || selected) && /* @__PURE__ */ jsx63(
15034
+ id && elements && (isHovered || isMobile2 || selected) && /* @__PURE__ */ jsx63(
14937
15035
  CheckboxItem,
14938
15036
  {
14939
15037
  checked: selected,
@@ -15766,8 +15864,20 @@ var SHAPES = [
15766
15864
  fillable: false
15767
15865
  }
15768
15866
  ];
15769
- var findShapeByKey = (key) => {
15770
- const shape = SHAPES.find((shape2, index) => {
15867
+ var getToolbarTools = (app) => {
15868
+ return app.defaultSelectionTool === "lasso" ? [
15869
+ {
15870
+ value: "lasso",
15871
+ icon: SelectionIcon,
15872
+ key: KEYS33.V,
15873
+ numericKey: KEYS33["1"],
15874
+ fillable: true
15875
+ },
15876
+ ...SHAPES.slice(1)
15877
+ ] : SHAPES;
15878
+ };
15879
+ var findShapeByKey = (key, app) => {
15880
+ const shape = getToolbarTools(app).find((shape2, index) => {
15771
15881
  return shape2.numericKey != null && key === shape2.numericKey.toString() || shape2.key && (typeof shape2.key === "string" ? shape2.key === key : shape2.key.includes(key));
15772
15882
  });
15773
15883
  return shape?.value || null;
@@ -15943,58 +16053,60 @@ var ShapesSwitcher = ({
15943
16053
  const [isExtraToolsMenuOpen, setIsExtraToolsMenuOpen] = useState21(false);
15944
16054
  const frameToolSelected = activeTool.type === "frame";
15945
16055
  const laserToolSelected = activeTool.type === "laser";
15946
- const lassoToolSelected = activeTool.type === "lasso";
16056
+ const lassoToolSelected = activeTool.type === "lasso" && app.defaultSelectionTool !== "lasso";
15947
16057
  const embeddableToolSelected = activeTool.type === "embeddable";
15948
16058
  const { TTDDialogTriggerTunnel } = useTunnels();
15949
16059
  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" });
16060
+ getToolbarTools(app).map(
16061
+ ({ value, icon, key, numericKey, fillable }, index) => {
16062
+ if (UIOptions.tools?.[value] === false) {
16063
+ return null;
16064
+ }
16065
+ const label = t(`toolBar.${value}`);
16066
+ const letter = key && capitalizeString(typeof key === "string" ? key : key[0]);
16067
+ const shortcut = letter ? `${letter} ${t("helpDialog.or")} ${numericKey}` : `${numericKey}`;
16068
+ return /* @__PURE__ */ jsx71(
16069
+ ToolButton,
16070
+ {
16071
+ className: clsx31("Shape", { fillable }),
16072
+ type: "radio",
16073
+ icon,
16074
+ checked: activeTool.type === value,
16075
+ name: "editor-current-shape",
16076
+ title: `${capitalizeString(label)} \u2014 ${shortcut}`,
16077
+ keyBindingLabel: numericKey || letter,
16078
+ "aria-label": capitalizeString(label),
16079
+ "aria-keyshortcuts": shortcut,
16080
+ "data-testid": `toolbar-${value}`,
16081
+ onPointerDown: ({ pointerType }) => {
16082
+ if (!appState.penDetected && pointerType === "pen") {
16083
+ app.togglePenMode(true);
16084
+ }
16085
+ if (value === "selection") {
16086
+ if (appState.activeTool.type === "selection") {
16087
+ app.setActiveTool({ type: "lasso" });
16088
+ } else {
16089
+ app.setActiveTool({ type: "selection" });
16090
+ }
16091
+ }
16092
+ },
16093
+ onChange: ({ pointerType }) => {
16094
+ if (appState.activeTool.type !== value) {
16095
+ trackEvent("toolbar", value, "ui");
16096
+ }
16097
+ if (value === "image") {
16098
+ app.setActiveTool({
16099
+ type: value
16100
+ });
15977
16101
  } else {
15978
- app.setActiveTool({ type: "selection" });
16102
+ app.setActiveTool({ type: value });
15979
16103
  }
15980
16104
  }
15981
16105
  },
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
- }),
16106
+ value
16107
+ );
16108
+ }
16109
+ ),
15998
16110
  /* @__PURE__ */ jsx71("div", { className: "App-toolbar__divider" }),
15999
16111
  /* @__PURE__ */ jsxs39(DropdownMenu_default, { open: isExtraToolsMenuOpen, children: [
16000
16112
  /* @__PURE__ */ jsx71(
@@ -16050,7 +16162,7 @@ var ShapesSwitcher = ({
16050
16162
  children: t("toolBar.laser")
16051
16163
  }
16052
16164
  ),
16053
- /* @__PURE__ */ jsx71(
16165
+ app.defaultSelectionTool !== "lasso" && /* @__PURE__ */ jsx71(
16054
16166
  DropdownMenu_default.Item,
16055
16167
  {
16056
16168
  onSelect: () => app.setActiveTool({ type: "lasso" }),
@@ -16243,10 +16355,10 @@ var CommandPalette = Object.assign(
16243
16355
  });
16244
16356
  }
16245
16357
  };
16246
- window.addEventListener(EVENT8.KEYDOWN, commandPaletteShortcut, {
16358
+ window.addEventListener(EVENT9.KEYDOWN, commandPaletteShortcut, {
16247
16359
  capture: true
16248
16360
  });
16249
- return () => window.removeEventListener(EVENT8.KEYDOWN, commandPaletteShortcut, {
16361
+ return () => window.removeEventListener(EVENT9.KEYDOWN, commandPaletteShortcut, {
16250
16362
  capture: true
16251
16363
  });
16252
16364
  }, [setAppState]);
@@ -16740,10 +16852,10 @@ function CommandPaletteInner({
16740
16852
  event.preventDefault();
16741
16853
  });
16742
16854
  useEffect27(() => {
16743
- window.addEventListener(EVENT8.KEYDOWN, handleKeyDown, {
16855
+ window.addEventListener(EVENT9.KEYDOWN, handleKeyDown, {
16744
16856
  capture: true
16745
16857
  });
16746
- return () => window.removeEventListener(EVENT8.KEYDOWN, handleKeyDown, {
16858
+ return () => window.removeEventListener(EVENT9.KEYDOWN, handleKeyDown, {
16747
16859
  capture: true
16748
16860
  });
16749
16861
  }, [handleKeyDown]);
@@ -16954,9 +17066,9 @@ var getCurvePathOps = (shape) => {
16954
17066
 
16955
17067
  // ../element/src/shape.ts
16956
17068
  import {
16957
- pointFrom as pointFrom17,
17069
+ pointFrom as pointFrom18,
16958
17070
  pointDistance as pointDistance7,
16959
- pointRotateRads as pointRotateRads11
17071
+ pointRotateRads as pointRotateRads12
16960
17072
  } from "@excalidraw/math";
16961
17073
  import {
16962
17074
  ROUGHNESS,
@@ -16996,17 +17108,17 @@ import {
16996
17108
  degreesToRadians,
16997
17109
  lineSegment as lineSegment5,
16998
17110
  pointDistance as pointDistance6,
16999
- pointFrom as pointFrom13,
17111
+ pointFrom as pointFrom14,
17000
17112
  pointFromArray as pointFromArray3,
17001
- pointRotateRads as pointRotateRads8
17113
+ pointRotateRads as pointRotateRads9
17002
17114
  } from "@excalidraw/math";
17003
17115
  import { pointsOnBezierCurves as pointsOnBezierCurves2 } from "points-on-curve";
17004
17116
 
17005
17117
  // ../element/src/linearElementEditor.ts
17006
17118
  import {
17007
17119
  pointCenter,
17008
- pointFrom as pointFrom12,
17009
- pointRotateRads as pointRotateRads7,
17120
+ pointFrom as pointFrom13,
17121
+ pointRotateRads as pointRotateRads8,
17010
17122
  pointsEqual as pointsEqual7,
17011
17123
  pointDistance as pointDistance5,
17012
17124
  vectorFromPoint as vectorFromPoint6,
@@ -17039,8 +17151,8 @@ import {
17039
17151
  } from "@excalidraw/common";
17040
17152
  import {
17041
17153
  lineSegment as lineSegment4,
17042
- pointFrom as pointFrom11,
17043
- pointRotateRads as pointRotateRads6,
17154
+ pointFrom as pointFrom12,
17155
+ pointRotateRads as pointRotateRads7,
17044
17156
  vectorFromPoint as vectorFromPoint5,
17045
17157
  pointDistanceSq,
17046
17158
  clamp as clamp3,
@@ -17061,9 +17173,9 @@ import {
17061
17173
  isPointWithinBounds,
17062
17174
  lineSegment as lineSegment3,
17063
17175
  lineSegmentIntersectionPoints,
17064
- pointFrom as pointFrom8,
17176
+ pointFrom as pointFrom9,
17065
17177
  pointFromVector as pointFromVector2,
17066
- pointRotateRads as pointRotateRads4,
17178
+ pointRotateRads as pointRotateRads5,
17067
17179
  pointsEqual as pointsEqual2,
17068
17180
  vectorFromPoint as vectorFromPoint2,
17069
17181
  vectorNormalize,
@@ -17160,6 +17272,7 @@ import {
17160
17272
  isProdEnv as isProdEnv2,
17161
17273
  invariant as invariant2
17162
17274
  } from "@excalidraw/common";
17275
+ import { pointFrom as pointFrom8, pointRotateRads as pointRotateRads3 } from "@excalidraw/math";
17163
17276
 
17164
17277
  // ../element/src/textMeasurements.ts
17165
17278
  import {
@@ -17179,16 +17292,16 @@ import { isDevEnv as isDevEnv4, isTestEnv as isTestEnv2 } from "@excalidraw/comm
17179
17292
  import {
17180
17293
  curvePointDistance,
17181
17294
  distanceToLineSegment,
17182
- pointRotateRads as pointRotateRads3
17295
+ pointRotateRads as pointRotateRads4
17183
17296
  } from "@excalidraw/math";
17184
17297
  import { ellipse, ellipseDistanceFromPoint } from "@excalidraw/math/ellipse";
17185
17298
 
17186
17299
  // ../element/src/heading.ts
17187
17300
  import { invariant as invariant3, isDevEnv as isDevEnv5, isTestEnv as isTestEnv3 } from "@excalidraw/common";
17188
17301
  import {
17189
- pointFrom as pointFrom9,
17302
+ pointFrom as pointFrom10,
17190
17303
  pointFromVector as pointFromVector3,
17191
- pointRotateRads as pointRotateRads5,
17304
+ pointRotateRads as pointRotateRads6,
17192
17305
  pointScaleFromOrigin,
17193
17306
  pointsEqual as pointsEqual3,
17194
17307
  triangleIncludesPoint,
@@ -17222,7 +17335,7 @@ var headingIsHorizontal = (a) => compareHeading(a, HEADING_RIGHT) || compareHead
17222
17335
  import {
17223
17336
  clamp as clamp2,
17224
17337
  pointDistance as pointDistance3,
17225
- pointFrom as pointFrom10,
17338
+ pointFrom as pointFrom11,
17226
17339
  pointScaleFromOrigin as pointScaleFromOrigin2,
17227
17340
  pointsEqual as pointsEqual4,
17228
17341
  pointTranslate,
@@ -17301,17 +17414,17 @@ var getArrowheadPoints = (element, shape, position, arrowhead) => {
17301
17414
  const index = position === "start" ? 1 : ops.length - 1;
17302
17415
  const data = ops[index].data;
17303
17416
  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]);
17417
+ const p3 = pointFrom14(data[4], data[5]);
17418
+ const p2 = pointFrom14(data[2], data[3]);
17419
+ const p1 = pointFrom14(data[0], data[1]);
17307
17420
  const prevOp = ops[index - 1];
17308
- let p0 = pointFrom13(0, 0);
17421
+ let p0 = pointFrom14(0, 0);
17309
17422
  if (prevOp.op === "move") {
17310
17423
  const p = pointFromArray3(prevOp.data);
17311
17424
  invariant7(p != null, "Op data is not a point");
17312
17425
  p0 = p;
17313
17426
  } else if (prevOp.op === "bcurveTo") {
17314
- p0 = pointFrom13(prevOp.data[4], prevOp.data[5]);
17427
+ p0 = pointFrom14(prevOp.data[4], prevOp.data[5]);
17315
17428
  }
17316
17429
  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
17430
  const [x2, y2] = position === "start" ? p0 : p3;
@@ -17336,26 +17449,26 @@ var getArrowheadPoints = (element, shape, position, arrowhead) => {
17336
17449
  }
17337
17450
  const angle = getArrowheadAngle(arrowhead);
17338
17451
  if (arrowhead === "crowfoot_many" || arrowhead === "crowfoot_one_or_many") {
17339
- const [x32, y32] = pointRotateRads8(
17340
- pointFrom13(x2, y2),
17341
- pointFrom13(xs, ys),
17452
+ const [x32, y32] = pointRotateRads9(
17453
+ pointFrom14(x2, y2),
17454
+ pointFrom14(xs, ys),
17342
17455
  degreesToRadians(-angle)
17343
17456
  );
17344
- const [x42, y42] = pointRotateRads8(
17345
- pointFrom13(x2, y2),
17346
- pointFrom13(xs, ys),
17457
+ const [x42, y42] = pointRotateRads9(
17458
+ pointFrom14(x2, y2),
17459
+ pointFrom14(xs, ys),
17347
17460
  degreesToRadians(angle)
17348
17461
  );
17349
17462
  return [xs, ys, x32, y32, x42, y42];
17350
17463
  }
17351
- const [x3, y3] = pointRotateRads8(
17352
- pointFrom13(xs, ys),
17353
- pointFrom13(x2, y2),
17464
+ const [x3, y3] = pointRotateRads9(
17465
+ pointFrom14(xs, ys),
17466
+ pointFrom14(x2, y2),
17354
17467
  -angle * Math.PI / 180
17355
17468
  );
17356
- const [x4, y4] = pointRotateRads8(
17357
- pointFrom13(xs, ys),
17358
- pointFrom13(x2, y2),
17469
+ const [x4, y4] = pointRotateRads9(
17470
+ pointFrom14(xs, ys),
17471
+ pointFrom14(x2, y2),
17359
17472
  degreesToRadians(angle)
17360
17473
  );
17361
17474
  if (arrowhead === "diamond" || arrowhead === "diamond_outline") {
@@ -17363,16 +17476,16 @@ var getArrowheadPoints = (element, shape, position, arrowhead) => {
17363
17476
  let oy;
17364
17477
  if (position === "start") {
17365
17478
  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),
17479
+ [ox, oy] = pointRotateRads9(
17480
+ pointFrom14(x2 + minSize * 2, y2),
17481
+ pointFrom14(x2, y2),
17369
17482
  Math.atan2(py - y2, px - x2)
17370
17483
  );
17371
17484
  } else {
17372
17485
  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),
17486
+ [ox, oy] = pointRotateRads9(
17487
+ pointFrom14(x2 - minSize * 2, y2),
17488
+ pointFrom14(x2, y2),
17376
17489
  Math.atan2(y2 - py, x2 - px)
17377
17490
  );
17378
17491
  }
@@ -17383,9 +17496,9 @@ var getArrowheadPoints = (element, shape, position, arrowhead) => {
17383
17496
 
17384
17497
  // ../element/src/cropElement.ts
17385
17498
  import {
17386
- pointFrom as pointFrom14,
17499
+ pointFrom as pointFrom15,
17387
17500
  pointCenter as pointCenter2,
17388
- pointRotateRads as pointRotateRads9,
17501
+ pointRotateRads as pointRotateRads10,
17389
17502
  vectorFromPoint as vectorFromPoint7,
17390
17503
  vectorNormalize as vectorNormalize3,
17391
17504
  vectorSubtract,
@@ -17398,7 +17511,7 @@ import {
17398
17511
 
17399
17512
  // ../element/src/frame.ts
17400
17513
  import { arrayToMap as arrayToMap19 } from "@excalidraw/common";
17401
- import { isPointWithinBounds as isPointWithinBounds2, pointFrom as pointFrom16 } from "@excalidraw/math";
17514
+ import { isPointWithinBounds as isPointWithinBounds2, pointFrom as pointFrom17 } from "@excalidraw/math";
17402
17515
 
17403
17516
  // ../utils/src/bbox.ts
17404
17517
  import {
@@ -17418,24 +17531,24 @@ import {
17418
17531
  } from "@excalidraw/element";
17419
17532
  import {
17420
17533
  rangeIncludesValue,
17421
- pointFrom as pointFrom15,
17422
- pointRotateRads as pointRotateRads10,
17534
+ pointFrom as pointFrom16,
17535
+ pointRotateRads as pointRotateRads11,
17423
17536
  rangeInclusive
17424
17537
  } from "@excalidraw/math";
17425
17538
  var getNonLinearElementRelativePoints = (element) => {
17426
17539
  if (element.type === "diamond") {
17427
17540
  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)
17541
+ pointFrom16(element.width / 2, 0),
17542
+ pointFrom16(element.width, element.height / 2),
17543
+ pointFrom16(element.width / 2, element.height),
17544
+ pointFrom16(0, element.height / 2)
17432
17545
  ];
17433
17546
  }
17434
17547
  return [
17435
- pointFrom15(0, 0),
17436
- pointFrom15(0 + element.width, 0),
17437
- pointFrom15(0 + element.width, element.height),
17438
- pointFrom15(0, element.height)
17548
+ pointFrom16(0, 0),
17549
+ pointFrom16(0 + element.width, 0),
17550
+ pointFrom16(0 + element.width, element.height),
17551
+ pointFrom16(0, element.height)
17439
17552
  ];
17440
17553
  };
17441
17554
  var getElementRelativePoints = (element) => {
@@ -17469,9 +17582,9 @@ var getMinMaxPoints = (points) => {
17469
17582
  var getRotatedBBox = (element) => {
17470
17583
  const points = getElementRelativePoints(element);
17471
17584
  const { cx, cy } = getMinMaxPoints(points);
17472
- const centerPoint = pointFrom15(cx, cy);
17585
+ const centerPoint = pointFrom16(cx, cy);
17473
17586
  const rotatedPoints = points.map(
17474
- (p) => pointRotateRads10(p, centerPoint, element.angle)
17587
+ (p) => pointRotateRads11(p, centerPoint, element.angle)
17475
17588
  );
17476
17589
  const { minX, minY, maxX, maxY } = getMinMaxPoints(rotatedPoints);
17477
17590
  return [
@@ -18080,7 +18193,7 @@ var generateElementShape = (element, generator, {
18080
18193
  case "arrow": {
18081
18194
  let shape;
18082
18195
  const options = generateRoughOptions(element);
18083
- const points = element.points.length ? element.points : [pointFrom17(0, 0)];
18196
+ const points = element.points.length ? element.points : [pointFrom18(0, 0)];
18084
18197
  if (isElbowArrow6(element)) {
18085
18198
  if (!points.every(
18086
18199
  (point) => Math.abs(point[0]) <= 1e6 && Math.abs(point[1]) <= 1e6
@@ -18225,7 +18338,7 @@ var generateElbowArrowShape = (points, radius) => {
18225
18338
  };
18226
18339
 
18227
18340
  // ../element/src/mutateElement.ts
18228
- var newElementWith8 = (element, updates, force = false) => {
18341
+ var newElementWith9 = (element, updates, force = false) => {
18229
18342
  let didChange = false;
18230
18343
  for (const key in updates) {
18231
18344
  const value = updates[key];
@@ -18354,7 +18467,7 @@ var actionTogglePolygon = register({
18354
18467
  if (!targetElementsMap.has(element.id) || !isLineElement4(element)) {
18355
18468
  return element;
18356
18469
  }
18357
- return newElementWith8(element, {
18470
+ return newElementWith9(element, {
18358
18471
  backgroundColor: nextPolygonState ? element.backgroundColor : "transparent",
18359
18472
  ...toggleLinePolygonState3(element, nextPolygonState)
18360
18473
  });
@@ -18946,7 +19059,7 @@ var createRedoAction = (history) => ({
18946
19059
 
18947
19060
  // actions/actionTextAutoResize.ts
18948
19061
  import { getFontString as getFontString6 } from "@excalidraw/common";
18949
- import { newElementWith as newElementWith9 } from "@excalidraw/element";
19062
+ import { newElementWith as newElementWith10 } from "@excalidraw/element";
18950
19063
  import { measureText as measureText4 } from "@excalidraw/element";
18951
19064
  import { isTextElement as isTextElement9 } from "@excalidraw/element";
18952
19065
  import { CaptureUpdateAction as CaptureUpdateAction34 } from "@excalidraw/element";
@@ -18970,7 +19083,7 @@ var actionTextAutoResize = register({
18970
19083
  getFontString6(element),
18971
19084
  element.lineHeight
18972
19085
  );
18973
- return newElementWith9(element, {
19086
+ return newElementWith10(element, {
18974
19087
  autoResize: true,
18975
19088
  width: metrics.width,
18976
19089
  height: metrics.height,
@@ -19209,8 +19322,8 @@ var sum = (array, mapper) => array.reduce((acc, item) => acc + mapper(item), 0);
19209
19322
 
19210
19323
  // snapping.ts
19211
19324
  import {
19212
- pointFrom as pointFrom18,
19213
- pointRotateRads as pointRotateRads12,
19325
+ pointFrom as pointFrom19,
19326
+ pointRotateRads as pointRotateRads13,
19214
19327
  rangeInclusive as rangeInclusive2,
19215
19328
  rangeIntersection,
19216
19329
  rangesOverlap
@@ -19260,7 +19373,8 @@ var isSnappingEnabled = ({
19260
19373
  selectedElements
19261
19374
  }) => {
19262
19375
  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));
19376
+ const isLassoDragging = app.state.activeTool.type === "lasso" && app.state.selectedElementsAreBeingDragged;
19377
+ 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
19378
  }
19265
19379
  if (selectedElements.length === 1 && selectedElements[0].type === "arrow") {
19266
19380
  return false;
@@ -19296,50 +19410,50 @@ var getElementsCorners = (elements, elementsMap, {
19296
19410
  const halfWidth = (x2 - x1) / 2;
19297
19411
  const halfHeight = (y2 - y1) / 2;
19298
19412
  if ((element.type === "diamond" || element.type === "ellipse") && !boundingBoxCorners) {
19299
- const leftMid = pointRotateRads12(
19300
- pointFrom18(x1, y1 + halfHeight),
19301
- pointFrom18(cx, cy),
19413
+ const leftMid = pointRotateRads13(
19414
+ pointFrom19(x1, y1 + halfHeight),
19415
+ pointFrom19(cx, cy),
19302
19416
  element.angle
19303
19417
  );
19304
- const topMid = pointRotateRads12(
19305
- pointFrom18(x1 + halfWidth, y1),
19306
- pointFrom18(cx, cy),
19418
+ const topMid = pointRotateRads13(
19419
+ pointFrom19(x1 + halfWidth, y1),
19420
+ pointFrom19(cx, cy),
19307
19421
  element.angle
19308
19422
  );
19309
- const rightMid = pointRotateRads12(
19310
- pointFrom18(x2, y1 + halfHeight),
19311
- pointFrom18(cx, cy),
19423
+ const rightMid = pointRotateRads13(
19424
+ pointFrom19(x2, y1 + halfHeight),
19425
+ pointFrom19(cx, cy),
19312
19426
  element.angle
19313
19427
  );
19314
- const bottomMid = pointRotateRads12(
19315
- pointFrom18(x1 + halfWidth, y2),
19316
- pointFrom18(cx, cy),
19428
+ const bottomMid = pointRotateRads13(
19429
+ pointFrom19(x1 + halfWidth, y2),
19430
+ pointFrom19(cx, cy),
19317
19431
  element.angle
19318
19432
  );
19319
- const center = pointFrom18(cx, cy);
19433
+ const center = pointFrom19(cx, cy);
19320
19434
  result = omitCenter ? [leftMid, topMid, rightMid, bottomMid] : [leftMid, topMid, rightMid, bottomMid, center];
19321
19435
  } else {
19322
- const topLeft = pointRotateRads12(
19323
- pointFrom18(x1, y1),
19324
- pointFrom18(cx, cy),
19436
+ const topLeft = pointRotateRads13(
19437
+ pointFrom19(x1, y1),
19438
+ pointFrom19(cx, cy),
19325
19439
  element.angle
19326
19440
  );
19327
- const topRight = pointRotateRads12(
19328
- pointFrom18(x2, y1),
19329
- pointFrom18(cx, cy),
19441
+ const topRight = pointRotateRads13(
19442
+ pointFrom19(x2, y1),
19443
+ pointFrom19(cx, cy),
19330
19444
  element.angle
19331
19445
  );
19332
- const bottomLeft = pointRotateRads12(
19333
- pointFrom18(x1, y2),
19334
- pointFrom18(cx, cy),
19446
+ const bottomLeft = pointRotateRads13(
19447
+ pointFrom19(x1, y2),
19448
+ pointFrom19(cx, cy),
19335
19449
  element.angle
19336
19450
  );
19337
- const bottomRight = pointRotateRads12(
19338
- pointFrom18(x2, y2),
19339
- pointFrom18(cx, cy),
19451
+ const bottomRight = pointRotateRads13(
19452
+ pointFrom19(x2, y2),
19453
+ pointFrom19(cx, cy),
19340
19454
  element.angle
19341
19455
  );
19342
- const center = pointFrom18(cx, cy);
19456
+ const center = pointFrom19(cx, cy);
19343
19457
  result = omitCenter ? [topLeft, topRight, bottomLeft, bottomRight] : [topLeft, topRight, bottomLeft, bottomRight, center];
19344
19458
  }
19345
19459
  } else if (elements.length > 1) {
@@ -19349,14 +19463,14 @@ var getElementsCorners = (elements, elementsMap, {
19349
19463
  );
19350
19464
  const width = maxX - minX;
19351
19465
  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);
19466
+ const topLeft = pointFrom19(minX, minY);
19467
+ const topRight = pointFrom19(maxX, minY);
19468
+ const bottomLeft = pointFrom19(minX, maxY);
19469
+ const bottomRight = pointFrom19(maxX, maxY);
19470
+ const center = pointFrom19(minX + width / 2, minY + height / 2);
19357
19471
  result = omitCenter ? [topLeft, topRight, bottomLeft, bottomRight] : [topLeft, topRight, bottomLeft, bottomRight, center];
19358
19472
  }
19359
- return result.map((p) => pointFrom18(round(p[0]), round(p[1])));
19473
+ return result.map((p) => pointFrom19(round(p[0]), round(p[1])));
19360
19474
  };
19361
19475
  var getReferenceElements = (elements, selectedElements, appState, elementsMap) => getVisibleAndNonSelectedElements(
19362
19476
  elements,
@@ -19399,10 +19513,10 @@ var getVisibleGaps = (elements, selectedElements, appState, elementsMap) => {
19399
19513
  startBounds,
19400
19514
  endBounds,
19401
19515
  startSide: [
19402
- pointFrom18(startMaxX, startMinY),
19403
- pointFrom18(startMaxX, startMaxY)
19516
+ pointFrom19(startMaxX, startMinY),
19517
+ pointFrom19(startMaxX, startMaxY)
19404
19518
  ],
19405
- endSide: [pointFrom18(endMinX, endMinY), pointFrom18(endMinX, endMaxY)],
19519
+ endSide: [pointFrom19(endMinX, endMinY), pointFrom19(endMinX, endMaxY)],
19406
19520
  length: endMinX - startMaxX,
19407
19521
  overlap: rangeIntersection(
19408
19522
  rangeInclusive2(startMinY, startMaxY),
@@ -19433,10 +19547,10 @@ var getVisibleGaps = (elements, selectedElements, appState, elementsMap) => {
19433
19547
  startBounds,
19434
19548
  endBounds,
19435
19549
  startSide: [
19436
- pointFrom18(startMinX, startMaxY),
19437
- pointFrom18(startMaxX, startMaxY)
19550
+ pointFrom19(startMinX, startMaxY),
19551
+ pointFrom19(startMaxX, startMaxY)
19438
19552
  ],
19439
- endSide: [pointFrom18(endMinX, endMinY), pointFrom18(endMaxX, endMinY)],
19553
+ endSide: [pointFrom19(endMinX, endMinY), pointFrom19(endMaxX, endMinY)],
19440
19554
  length: endMinY - startMaxY,
19441
19555
  overlap: rangeIntersection(
19442
19556
  rangeInclusive2(startMinX, startMaxX),
@@ -19741,7 +19855,7 @@ var createPointSnapLines = (nearestSnapsX, nearestSnapsY) => {
19741
19855
  }
19742
19856
  snapsX[key].push(
19743
19857
  ...snap.points.map(
19744
- (p) => pointFrom18(round(p[0]), round(p[1]))
19858
+ (p) => pointFrom19(round(p[0]), round(p[1]))
19745
19859
  )
19746
19860
  );
19747
19861
  }
@@ -19756,7 +19870,7 @@ var createPointSnapLines = (nearestSnapsX, nearestSnapsY) => {
19756
19870
  }
19757
19871
  snapsY[key].push(
19758
19872
  ...snap.points.map(
19759
- (p) => pointFrom18(round(p[0]), round(p[1]))
19873
+ (p) => pointFrom19(round(p[0]), round(p[1]))
19760
19874
  )
19761
19875
  );
19762
19876
  }
@@ -19767,7 +19881,7 @@ var createPointSnapLines = (nearestSnapsX, nearestSnapsY) => {
19767
19881
  type: "points",
19768
19882
  points: dedupePoints(
19769
19883
  points.map((p) => {
19770
- return pointFrom18(Number(key), p[1]);
19884
+ return pointFrom19(Number(key), p[1]);
19771
19885
  }).sort((a, b) => a[1] - b[1])
19772
19886
  )
19773
19887
  };
@@ -19777,7 +19891,7 @@ var createPointSnapLines = (nearestSnapsX, nearestSnapsY) => {
19777
19891
  type: "points",
19778
19892
  points: dedupePoints(
19779
19893
  points.map((p) => {
19780
- return pointFrom18(p[0], Number(key));
19894
+ return pointFrom19(p[0], Number(key));
19781
19895
  }).sort((a, b) => a[0] - b[0])
19782
19896
  )
19783
19897
  };
@@ -19820,16 +19934,16 @@ var createGapSnapLines = (selectedElements, dragOffset, gapSnaps) => {
19820
19934
  type: "gap",
19821
19935
  direction: "horizontal",
19822
19936
  points: [
19823
- pointFrom18(gapSnap.gap.startSide[0][0], gapLineY),
19824
- pointFrom18(minX, gapLineY)
19937
+ pointFrom19(gapSnap.gap.startSide[0][0], gapLineY),
19938
+ pointFrom19(minX, gapLineY)
19825
19939
  ]
19826
19940
  },
19827
19941
  {
19828
19942
  type: "gap",
19829
19943
  direction: "horizontal",
19830
19944
  points: [
19831
- pointFrom18(maxX, gapLineY),
19832
- pointFrom18(gapSnap.gap.endSide[0][0], gapLineY)
19945
+ pointFrom19(maxX, gapLineY),
19946
+ pointFrom19(gapSnap.gap.endSide[0][0], gapLineY)
19833
19947
  ]
19834
19948
  }
19835
19949
  );
@@ -19844,16 +19958,16 @@ var createGapSnapLines = (selectedElements, dragOffset, gapSnaps) => {
19844
19958
  type: "gap",
19845
19959
  direction: "vertical",
19846
19960
  points: [
19847
- pointFrom18(gapLineX, gapSnap.gap.startSide[0][1]),
19848
- pointFrom18(gapLineX, minY)
19961
+ pointFrom19(gapLineX, gapSnap.gap.startSide[0][1]),
19962
+ pointFrom19(gapLineX, minY)
19849
19963
  ]
19850
19964
  },
19851
19965
  {
19852
19966
  type: "gap",
19853
19967
  direction: "vertical",
19854
19968
  points: [
19855
- pointFrom18(gapLineX, maxY),
19856
- pointFrom18(gapLineX, gapSnap.gap.endSide[0][1])
19969
+ pointFrom19(gapLineX, maxY),
19970
+ pointFrom19(gapLineX, gapSnap.gap.endSide[0][1])
19857
19971
  ]
19858
19972
  }
19859
19973
  );
@@ -19868,14 +19982,14 @@ var createGapSnapLines = (selectedElements, dragOffset, gapSnaps) => {
19868
19982
  type: "gap",
19869
19983
  direction: "horizontal",
19870
19984
  points: [
19871
- pointFrom18(startMaxX, gapLineY),
19872
- pointFrom18(endMinX, gapLineY)
19985
+ pointFrom19(startMaxX, gapLineY),
19986
+ pointFrom19(endMinX, gapLineY)
19873
19987
  ]
19874
19988
  },
19875
19989
  {
19876
19990
  type: "gap",
19877
19991
  direction: "horizontal",
19878
- points: [pointFrom18(endMaxX, gapLineY), pointFrom18(minX, gapLineY)]
19992
+ points: [pointFrom19(endMaxX, gapLineY), pointFrom19(minX, gapLineY)]
19879
19993
  }
19880
19994
  );
19881
19995
  }
@@ -19889,16 +20003,16 @@ var createGapSnapLines = (selectedElements, dragOffset, gapSnaps) => {
19889
20003
  type: "gap",
19890
20004
  direction: "horizontal",
19891
20005
  points: [
19892
- pointFrom18(maxX, gapLineY),
19893
- pointFrom18(startMinX, gapLineY)
20006
+ pointFrom19(maxX, gapLineY),
20007
+ pointFrom19(startMinX, gapLineY)
19894
20008
  ]
19895
20009
  },
19896
20010
  {
19897
20011
  type: "gap",
19898
20012
  direction: "horizontal",
19899
20013
  points: [
19900
- pointFrom18(startMaxX, gapLineY),
19901
- pointFrom18(endMinX, gapLineY)
20014
+ pointFrom19(startMaxX, gapLineY),
20015
+ pointFrom19(endMinX, gapLineY)
19902
20016
  ]
19903
20017
  }
19904
20018
  );
@@ -19913,16 +20027,16 @@ var createGapSnapLines = (selectedElements, dragOffset, gapSnaps) => {
19913
20027
  type: "gap",
19914
20028
  direction: "vertical",
19915
20029
  points: [
19916
- pointFrom18(gapLineX, maxY),
19917
- pointFrom18(gapLineX, startMinY)
20030
+ pointFrom19(gapLineX, maxY),
20031
+ pointFrom19(gapLineX, startMinY)
19918
20032
  ]
19919
20033
  },
19920
20034
  {
19921
20035
  type: "gap",
19922
20036
  direction: "vertical",
19923
20037
  points: [
19924
- pointFrom18(gapLineX, startMaxY),
19925
- pointFrom18(gapLineX, endMinY)
20038
+ pointFrom19(gapLineX, startMaxY),
20039
+ pointFrom19(gapLineX, endMinY)
19926
20040
  ]
19927
20041
  }
19928
20042
  );
@@ -19937,14 +20051,14 @@ var createGapSnapLines = (selectedElements, dragOffset, gapSnaps) => {
19937
20051
  type: "gap",
19938
20052
  direction: "vertical",
19939
20053
  points: [
19940
- pointFrom18(gapLineX, startMaxY),
19941
- pointFrom18(gapLineX, endMinY)
20054
+ pointFrom19(gapLineX, startMaxY),
20055
+ pointFrom19(gapLineX, endMinY)
19942
20056
  ]
19943
20057
  },
19944
20058
  {
19945
20059
  type: "gap",
19946
20060
  direction: "vertical",
19947
- points: [pointFrom18(gapLineX, endMaxY), pointFrom18(gapLineX, minY)]
20061
+ points: [pointFrom19(gapLineX, endMaxY), pointFrom19(gapLineX, minY)]
19948
20062
  }
19949
20063
  );
19950
20064
  }
@@ -19957,7 +20071,7 @@ var createGapSnapLines = (selectedElements, dragOffset, gapSnaps) => {
19957
20071
  return {
19958
20072
  ...gapSnapLine,
19959
20073
  points: gapSnapLine.points.map(
19960
- (p) => pointFrom18(round(p[0]), round(p[1]))
20074
+ (p) => pointFrom19(round(p[0]), round(p[1]))
19961
20075
  )
19962
20076
  };
19963
20077
  })
@@ -19987,35 +20101,35 @@ var snapResizingElements = (selectedElements, selectedOriginalElements, app, eve
19987
20101
  if (transformHandle) {
19988
20102
  switch (transformHandle) {
19989
20103
  case "e": {
19990
- selectionSnapPoints.push(pointFrom18(maxX, minY), pointFrom18(maxX, maxY));
20104
+ selectionSnapPoints.push(pointFrom19(maxX, minY), pointFrom19(maxX, maxY));
19991
20105
  break;
19992
20106
  }
19993
20107
  case "w": {
19994
- selectionSnapPoints.push(pointFrom18(minX, minY), pointFrom18(minX, maxY));
20108
+ selectionSnapPoints.push(pointFrom19(minX, minY), pointFrom19(minX, maxY));
19995
20109
  break;
19996
20110
  }
19997
20111
  case "n": {
19998
- selectionSnapPoints.push(pointFrom18(minX, minY), pointFrom18(maxX, minY));
20112
+ selectionSnapPoints.push(pointFrom19(minX, minY), pointFrom19(maxX, minY));
19999
20113
  break;
20000
20114
  }
20001
20115
  case "s": {
20002
- selectionSnapPoints.push(pointFrom18(minX, maxY), pointFrom18(maxX, maxY));
20116
+ selectionSnapPoints.push(pointFrom19(minX, maxY), pointFrom19(maxX, maxY));
20003
20117
  break;
20004
20118
  }
20005
20119
  case "ne": {
20006
- selectionSnapPoints.push(pointFrom18(maxX, minY));
20120
+ selectionSnapPoints.push(pointFrom19(maxX, minY));
20007
20121
  break;
20008
20122
  }
20009
20123
  case "nw": {
20010
- selectionSnapPoints.push(pointFrom18(minX, minY));
20124
+ selectionSnapPoints.push(pointFrom19(minX, minY));
20011
20125
  break;
20012
20126
  }
20013
20127
  case "se": {
20014
- selectionSnapPoints.push(pointFrom18(maxX, maxY));
20128
+ selectionSnapPoints.push(pointFrom19(maxX, maxY));
20015
20129
  break;
20016
20130
  }
20017
20131
  case "sw": {
20018
- selectionSnapPoints.push(pointFrom18(minX, maxY));
20132
+ selectionSnapPoints.push(pointFrom19(minX, maxY));
20019
20133
  break;
20020
20134
  }
20021
20135
  }
@@ -20048,10 +20162,10 @@ var snapResizingElements = (selectedElements, selectedOriginalElements, app, eve
20048
20162
  (bound) => round(bound)
20049
20163
  );
20050
20164
  const corners = [
20051
- pointFrom18(x1, y1),
20052
- pointFrom18(x1, y2),
20053
- pointFrom18(x2, y1),
20054
- pointFrom18(x2, y2)
20165
+ pointFrom19(x1, y1),
20166
+ pointFrom19(x1, y2),
20167
+ pointFrom19(x2, y1),
20168
+ pointFrom19(x2, y2)
20055
20169
  ];
20056
20170
  getPointSnaps(
20057
20171
  selectedElements,
@@ -20076,7 +20190,7 @@ var snapNewElement = (newElement6, app, event, origin, dragOffset, elementsMap)
20076
20190
  };
20077
20191
  }
20078
20192
  const selectionSnapPoints = [
20079
- pointFrom18(origin.x + dragOffset.x, origin.y + dragOffset.y)
20193
+ pointFrom19(origin.x + dragOffset.x, origin.y + dragOffset.y)
20080
20194
  ];
20081
20195
  const snapDistance = getSnapDistance(app.state.zoom.value);
20082
20196
  const minOffset = {
@@ -20151,7 +20265,7 @@ var getSnapLinesAtPointer = (elements, app, pointer, event, elementsMap) => {
20151
20265
  }
20152
20266
  verticalSnapLines.push({
20153
20267
  type: "pointer",
20154
- points: [corner, pointFrom18(corner[0], pointer.y)],
20268
+ points: [corner, pointFrom19(corner[0], pointer.y)],
20155
20269
  direction: "vertical"
20156
20270
  });
20157
20271
  minOffset.x = offsetX;
@@ -20163,7 +20277,7 @@ var getSnapLinesAtPointer = (elements, app, pointer, event, elementsMap) => {
20163
20277
  }
20164
20278
  horizontalSnapLines.push({
20165
20279
  type: "pointer",
20166
- points: [corner, pointFrom18(pointer.x, corner[1])],
20280
+ points: [corner, pointFrom19(pointer.x, corner[1])],
20167
20281
  direction: "horizontal"
20168
20282
  });
20169
20283
  minOffset.y = offsetY;
@@ -20183,7 +20297,7 @@ var isActiveToolNonLinearSnappable = (activeToolType) => {
20183
20297
  };
20184
20298
 
20185
20299
  // data/transform.ts
20186
- import { pointFrom as pointFrom19 } from "@excalidraw/math";
20300
+ import { pointFrom as pointFrom20 } from "@excalidraw/math";
20187
20301
  import {
20188
20302
  DEFAULT_FONT_FAMILY as DEFAULT_FONT_FAMILY5,
20189
20303
  DEFAULT_FONT_SIZE as DEFAULT_FONT_SIZE6,
@@ -20482,7 +20596,7 @@ var convertToExcalidrawElements = (elementsSkeleton, opts) => {
20482
20596
  excalidrawElement = newLinearElement3({
20483
20597
  width,
20484
20598
  height,
20485
- points: [pointFrom19(0, 0), pointFrom19(width, height)],
20599
+ points: [pointFrom20(0, 0), pointFrom20(width, height)],
20486
20600
  ...element
20487
20601
  });
20488
20602
  break;
@@ -20494,7 +20608,7 @@ var convertToExcalidrawElements = (elementsSkeleton, opts) => {
20494
20608
  width,
20495
20609
  height,
20496
20610
  endArrowhead: "arrow",
20497
- points: [pointFrom19(0, 0), pointFrom19(width, height)],
20611
+ points: [pointFrom20(0, 0), pointFrom20(width, height)],
20498
20612
  ...element,
20499
20613
  type: "arrow"
20500
20614
  });
@@ -20710,7 +20824,7 @@ import { memoize, toBrandedType as toBrandedType2 } from "@excalidraw/common";
20710
20824
 
20711
20825
  // renderer/interactiveScene.ts
20712
20826
  import {
20713
- pointFrom as pointFrom21,
20827
+ pointFrom as pointFrom22,
20714
20828
  pointsEqual as pointsEqual8
20715
20829
  } from "@excalidraw/math";
20716
20830
  import oc2 from "open-color";
@@ -20748,7 +20862,7 @@ import {
20748
20862
  import { getCommonBounds as getCommonBounds7, getElementAbsoluteCoords as getElementAbsoluteCoords6 } from "@excalidraw/element";
20749
20863
 
20750
20864
  // renderer/renderSnaps.ts
20751
- import { pointFrom as pointFrom20 } from "@excalidraw/math";
20865
+ import { pointFrom as pointFrom21 } from "@excalidraw/math";
20752
20866
  import { THEME as THEME10 } from "@excalidraw/common";
20753
20867
  var SNAP_COLOR_LIGHT = "#ff6b6b";
20754
20868
  var SNAP_COLOR_DARK = "#ff0000";
@@ -20826,25 +20940,25 @@ var drawGapLine = (from, to, direction, appState, context) => {
20826
20940
  const halfPoint = [(from[0] + to[0]) / 2, from[1]];
20827
20941
  if (!appState.zenModeEnabled) {
20828
20942
  drawLine(
20829
- pointFrom20(from[0], from[1] - FULL),
20830
- pointFrom20(from[0], from[1] + FULL),
20943
+ pointFrom21(from[0], from[1] - FULL),
20944
+ pointFrom21(from[0], from[1] + FULL),
20831
20945
  context
20832
20946
  );
20833
20947
  }
20834
20948
  drawLine(
20835
- pointFrom20(halfPoint[0] - QUARTER, halfPoint[1] - HALF),
20836
- pointFrom20(halfPoint[0] - QUARTER, halfPoint[1] + HALF),
20949
+ pointFrom21(halfPoint[0] - QUARTER, halfPoint[1] - HALF),
20950
+ pointFrom21(halfPoint[0] - QUARTER, halfPoint[1] + HALF),
20837
20951
  context
20838
20952
  );
20839
20953
  drawLine(
20840
- pointFrom20(halfPoint[0] + QUARTER, halfPoint[1] - HALF),
20841
- pointFrom20(halfPoint[0] + QUARTER, halfPoint[1] + HALF),
20954
+ pointFrom21(halfPoint[0] + QUARTER, halfPoint[1] - HALF),
20955
+ pointFrom21(halfPoint[0] + QUARTER, halfPoint[1] + HALF),
20842
20956
  context
20843
20957
  );
20844
20958
  if (!appState.zenModeEnabled) {
20845
20959
  drawLine(
20846
- pointFrom20(to[0], to[1] - FULL),
20847
- pointFrom20(to[0], to[1] + FULL),
20960
+ pointFrom21(to[0], to[1] - FULL),
20961
+ pointFrom21(to[0], to[1] + FULL),
20848
20962
  context
20849
20963
  );
20850
20964
  drawLine(from, to, context);
@@ -20853,25 +20967,25 @@ var drawGapLine = (from, to, direction, appState, context) => {
20853
20967
  const halfPoint = [from[0], (from[1] + to[1]) / 2];
20854
20968
  if (!appState.zenModeEnabled) {
20855
20969
  drawLine(
20856
- pointFrom20(from[0] - FULL, from[1]),
20857
- pointFrom20(from[0] + FULL, from[1]),
20970
+ pointFrom21(from[0] - FULL, from[1]),
20971
+ pointFrom21(from[0] + FULL, from[1]),
20858
20972
  context
20859
20973
  );
20860
20974
  }
20861
20975
  drawLine(
20862
- pointFrom20(halfPoint[0] - HALF, halfPoint[1] - QUARTER),
20863
- pointFrom20(halfPoint[0] + HALF, halfPoint[1] - QUARTER),
20976
+ pointFrom21(halfPoint[0] - HALF, halfPoint[1] - QUARTER),
20977
+ pointFrom21(halfPoint[0] + HALF, halfPoint[1] - QUARTER),
20864
20978
  context
20865
20979
  );
20866
20980
  drawLine(
20867
- pointFrom20(halfPoint[0] - HALF, halfPoint[1] + QUARTER),
20868
- pointFrom20(halfPoint[0] + HALF, halfPoint[1] + QUARTER),
20981
+ pointFrom21(halfPoint[0] - HALF, halfPoint[1] + QUARTER),
20982
+ pointFrom21(halfPoint[0] + HALF, halfPoint[1] + QUARTER),
20869
20983
  context
20870
20984
  );
20871
20985
  if (!appState.zenModeEnabled) {
20872
20986
  drawLine(
20873
- pointFrom20(to[0] - FULL, to[1]),
20874
- pointFrom20(to[0] + FULL, to[1]),
20987
+ pointFrom21(to[0] - FULL, to[1]),
20988
+ pointFrom21(to[0] + FULL, to[1]),
20875
20989
  context
20876
20990
  );
20877
20991
  drawLine(from, to, context);
@@ -21224,7 +21338,7 @@ var renderLinearPointHandles = (context, appState, element, elementsMap) => {
21224
21338
  renderSingleLinearPoint(
21225
21339
  context,
21226
21340
  appState,
21227
- pointFrom21(
21341
+ pointFrom22(
21228
21342
  (p[0] + points[idx + 1][0]) / 2,
21229
21343
  (p[1] + points[idx + 1][1]) / 2
21230
21344
  ),
@@ -22169,7 +22283,8 @@ import {
22169
22283
  isWritableElement as isWritableElement2,
22170
22284
  getFontString as getFontString8,
22171
22285
  getFontFamilyString as getFontFamilyString3,
22172
- isTestEnv as isTestEnv5
22286
+ isTestEnv as isTestEnv5,
22287
+ MIME_TYPES as MIME_TYPES8
22173
22288
  } from "@excalidraw/common";
22174
22289
  import {
22175
22290
  originalContainerCache,
@@ -22304,11 +22419,12 @@ var textWysiwyg = ({
22304
22419
  );
22305
22420
  app.scene.mutateElement(container, { height: targetContainerHeight });
22306
22421
  } else {
22307
- const { y } = computeBoundTextPosition2(
22422
+ const { x, y } = computeBoundTextPosition2(
22308
22423
  container,
22309
22424
  updatedTextElement,
22310
22425
  elementsMap
22311
22426
  );
22427
+ coordX = x;
22312
22428
  coordY = y;
22313
22429
  }
22314
22430
  }
@@ -22396,12 +22512,14 @@ var textWysiwyg = ({
22396
22512
  updateWysiwygStyle();
22397
22513
  if (onChange) {
22398
22514
  editable.onpaste = async (event) => {
22399
- const clipboardData = await parseClipboard(event, true);
22400
- if (!clipboardData.text) {
22515
+ const textItem = (await parseDataTransferEvent(event)).findByType(
22516
+ MIME_TYPES8.text
22517
+ );
22518
+ if (!textItem) {
22401
22519
  return;
22402
22520
  }
22403
- const data = normalizeText2(clipboardData.text);
22404
- if (!data) {
22521
+ const text = normalizeText2(textItem.value);
22522
+ if (!text) {
22405
22523
  return;
22406
22524
  }
22407
22525
  const container = getContainerElement3(
@@ -22418,7 +22536,7 @@ var textWysiwyg = ({
22418
22536
  app.scene.getNonDeletedElementsMap()
22419
22537
  );
22420
22538
  const wrappedText = wrapText3(
22421
- `${editable.value}${data}`,
22539
+ `${editable.value}${text}`,
22422
22540
  font,
22423
22541
  getBoundTextMaxWidth3(container, boundTextElement)
22424
22542
  );
@@ -22720,7 +22838,7 @@ var isMaybeMermaidDefinition = (text) => {
22720
22838
 
22721
22839
  // lasso/index.ts
22722
22840
  import {
22723
- pointFrom as pointFrom22
22841
+ pointFrom as pointFrom23
22724
22842
  } from "@excalidraw/math";
22725
22843
  import { getElementLineSegments as getElementLineSegments2 } from "@excalidraw/element";
22726
22844
  import { LinearElementEditor as LinearElementEditor11 } from "@excalidraw/element";
@@ -22919,7 +23037,7 @@ var LassoTrail = class extends AnimatedTrail {
22919
23037
  this.updateSelection();
22920
23038
  });
22921
23039
  __publicField(this, "updateSelection", () => {
22922
- const lassoPath = super.getCurrentTrail()?.originalPoints?.map((p) => pointFrom22(p[0], p[1]));
23040
+ const lassoPath = super.getCurrentTrail()?.originalPoints?.map((p) => pointFrom23(p[0], p[1]));
22923
23041
  const currentCanvasTranslate = {
22924
23042
  scrollX: this.app.state.scrollX,
22925
23043
  scrollY: this.app.state.scrollY,
@@ -22979,7 +23097,7 @@ import {
22979
23097
  intersectElementWithLineSegment as intersectElementWithLineSegment3,
22980
23098
  isPointInElement
22981
23099
  } from "@excalidraw/element";
22982
- import { lineSegment as lineSegment7, pointFrom as pointFrom23 } from "@excalidraw/math";
23100
+ import { lineSegment as lineSegment7, pointFrom as pointFrom24 } from "@excalidraw/math";
22983
23101
  import { getElementsInGroup as getElementsInGroup6 } from "@excalidraw/element";
22984
23102
  import { shouldTestInside as shouldTestInside2 } from "@excalidraw/element";
22985
23103
  import { hasBoundTextElement as hasBoundTextElement6, isBoundToContainer as isBoundToContainer7 } from "@excalidraw/element";
@@ -23016,7 +23134,7 @@ var EraserTrail = class extends AnimatedTrail {
23016
23134
  return elementsToEraser;
23017
23135
  }
23018
23136
  updateElementsToBeErased(restoreToErase) {
23019
- const eraserPath = super.getCurrentTrail()?.originalPoints?.map((p) => pointFrom23(p[0], p[1])) || [];
23137
+ const eraserPath = super.getCurrentTrail()?.originalPoints?.map((p) => pointFrom24(p[0], p[1])) || [];
23020
23138
  if (eraserPath.length < 2) {
23021
23139
  return [];
23022
23140
  }
@@ -23543,7 +23661,7 @@ import { isNodeInFlowchart } from "@excalidraw/element";
23543
23661
  import { jsx as jsx87 } from "react/jsx-runtime";
23544
23662
  var getHints = ({
23545
23663
  appState,
23546
- isMobile,
23664
+ isMobile: isMobile2,
23547
23665
  device,
23548
23666
  app
23549
23667
  }) => {
@@ -23606,7 +23724,7 @@ var getHints = ({
23606
23724
  if (isGridModeEnabled(app) && appState.selectedElementsAreBeingDragged) {
23607
23725
  return t("hints.disableSnapping");
23608
23726
  }
23609
- if (!selectedElements.length && !isMobile) {
23727
+ if (!selectedElements.length && !isMobile2) {
23610
23728
  return [t("hints.canvasPanning")];
23611
23729
  }
23612
23730
  if (selectedElements.length === 1) {
@@ -23634,13 +23752,13 @@ var getHints = ({
23634
23752
  };
23635
23753
  var HintViewer = ({
23636
23754
  appState,
23637
- isMobile,
23755
+ isMobile: isMobile2,
23638
23756
  device,
23639
23757
  app
23640
23758
  }) => {
23641
23759
  const hints = getHints({
23642
23760
  appState,
23643
- isMobile,
23761
+ isMobile: isMobile2,
23644
23762
  device,
23645
23763
  app
23646
23764
  });
@@ -24260,7 +24378,7 @@ import {
24260
24378
  useImperativeHandle as useImperativeHandle3,
24261
24379
  useCallback as useCallback11
24262
24380
  } from "react";
24263
- import { EVENT as EVENT9, isDevEnv as isDevEnv9, KEYS as KEYS46, updateObject } from "@excalidraw/common";
24381
+ import { EVENT as EVENT10, isDevEnv as isDevEnv9, KEYS as KEYS46, updateObject } from "@excalidraw/common";
24264
24382
 
24265
24383
  // components/Sidebar/SidebarHeader.tsx
24266
24384
  import clsx41 from "clsx";
@@ -24498,9 +24616,9 @@ var SidebarInner = forwardRef4(
24498
24616
  closeLibrary();
24499
24617
  }
24500
24618
  };
24501
- document.addEventListener(EVENT9.KEYDOWN, handleKeyDown);
24619
+ document.addEventListener(EVENT10.KEYDOWN, handleKeyDown);
24502
24620
  return () => {
24503
- document.removeEventListener(EVENT9.KEYDOWN, handleKeyDown);
24621
+ document.removeEventListener(EVENT10.KEYDOWN, handleKeyDown);
24504
24622
  };
24505
24623
  }, [closeLibrary, docked, device.editor.canFitSidebar]);
24506
24624
  return /* @__PURE__ */ jsx101(
@@ -25284,7 +25402,7 @@ import debounce2 from "lodash.debounce";
25284
25402
  import { Fragment as Fragment17, memo as memo4, useEffect as useEffect32, useMemo as useMemo8, useRef as useRef28, useState as useState28 } from "react";
25285
25403
  import {
25286
25404
  CLASSES as CLASSES5,
25287
- EVENT as EVENT10,
25405
+ EVENT as EVENT11,
25288
25406
  FONT_FAMILY as FONT_FAMILY4,
25289
25407
  FRAME_STYLE as FRAME_STYLE3,
25290
25408
  getLineHeight as getLineHeight4
@@ -25505,7 +25623,7 @@ var SearchMenu2 = () => {
25505
25623
  }
25506
25624
  }
25507
25625
  };
25508
- return addEventListener(window, EVENT10.KEYDOWN, eventHandler, {
25626
+ return addEventListener(window, EVENT11.KEYDOWN, eventHandler, {
25509
25627
  capture: true,
25510
25628
  passive: false
25511
25629
  });
@@ -25976,7 +26094,7 @@ import { EDITOR_LS_KEYS as EDITOR_LS_KEYS3, debounce as debounce3, isDevEnv as i
25976
26094
 
25977
26095
  // components/TTDDialog/TTDDialogInput.tsx
25978
26096
  import { useEffect as useEffect33, useRef as useRef29 } from "react";
25979
- import { EVENT as EVENT11, KEYS as KEYS48 } from "@excalidraw/common";
26097
+ import { EVENT as EVENT12, KEYS as KEYS48 } from "@excalidraw/common";
25980
26098
  import { jsx as jsx112 } from "react/jsx-runtime";
25981
26099
  var TTDDialogInput = ({
25982
26100
  input,
@@ -26000,9 +26118,9 @@ var TTDDialogInput = ({
26000
26118
  }
26001
26119
  };
26002
26120
  textarea.focus();
26003
- textarea.addEventListener(EVENT11.KEYDOWN, handleKeyDown);
26121
+ textarea.addEventListener(EVENT12.KEYDOWN, handleKeyDown);
26004
26122
  return () => {
26005
- textarea.removeEventListener(EVENT11.KEYDOWN, handleKeyDown);
26123
+ textarea.removeEventListener(EVENT12.KEYDOWN, handleKeyDown);
26006
26124
  };
26007
26125
  }
26008
26126
  }, []);
@@ -26701,12 +26819,12 @@ import { updateBindings as updateBindings3 } from "@excalidraw/element";
26701
26819
  // components/Stats/DragInput.tsx
26702
26820
  import clsx50 from "clsx";
26703
26821
  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";
26822
+ import { EVENT as EVENT13, KEYS as KEYS49, cloneJSON as cloneJSON4 } from "@excalidraw/common";
26705
26823
  import { deepCopyElement as deepCopyElement4 } from "@excalidraw/element";
26706
26824
  import { CaptureUpdateAction as CaptureUpdateAction36 } from "@excalidraw/element";
26707
26825
 
26708
26826
  // components/Stats/utils.ts
26709
- import { pointFrom as pointFrom24, pointRotateRads as pointRotateRads13 } from "@excalidraw/math";
26827
+ import { pointFrom as pointFrom25, pointRotateRads as pointRotateRads14 } from "@excalidraw/math";
26710
26828
  import { getBoundTextElement as getBoundTextElement9 } from "@excalidraw/element";
26711
26829
  import { isFrameLikeElement as isFrameLikeElement12 } from "@excalidraw/element";
26712
26830
  import {
@@ -26744,16 +26862,16 @@ var moveElement = (newTopLeftX, newTopLeftY, originalElement, scene, originalEle
26744
26862
  originalElement.x + originalElement.width / 2,
26745
26863
  originalElement.y + originalElement.height / 2
26746
26864
  ];
26747
- const [topLeftX, topLeftY] = pointRotateRads13(
26748
- pointFrom24(originalElement.x, originalElement.y),
26749
- pointFrom24(cx, cy),
26865
+ const [topLeftX, topLeftY] = pointRotateRads14(
26866
+ pointFrom25(originalElement.x, originalElement.y),
26867
+ pointFrom25(cx, cy),
26750
26868
  originalElement.angle
26751
26869
  );
26752
26870
  const changeInX = newTopLeftX - topLeftX;
26753
26871
  const changeInY = newTopLeftY - topLeftY;
26754
- const [x, y] = pointRotateRads13(
26755
- pointFrom24(newTopLeftX, newTopLeftY),
26756
- pointFrom24(cx + changeInX, cy + changeInY),
26872
+ const [x, y] = pointRotateRads14(
26873
+ pointFrom25(newTopLeftX, newTopLeftY),
26874
+ pointFrom25(cx + changeInX, cy + changeInY),
26757
26875
  -originalElement.angle
26758
26876
  );
26759
26877
  scene.mutateElement(
@@ -26794,16 +26912,16 @@ var moveElement = (newTopLeftX, newTopLeftY, originalElement, scene, originalEle
26794
26912
  child.x + child.width / 2,
26795
26913
  child.y + child.height / 2
26796
26914
  ];
26797
- const [childTopLeftX, childTopLeftY] = pointRotateRads13(
26798
- pointFrom24(child.x, child.y),
26799
- pointFrom24(childCX, childCY),
26915
+ const [childTopLeftX, childTopLeftY] = pointRotateRads14(
26916
+ pointFrom25(child.x, child.y),
26917
+ pointFrom25(childCX, childCY),
26800
26918
  child.angle
26801
26919
  );
26802
26920
  const childNewTopLeftX = Math.round(childTopLeftX + changeInX);
26803
26921
  const childNewTopLeftY = Math.round(childTopLeftY + changeInY);
26804
- const [childX, childY] = pointRotateRads13(
26805
- pointFrom24(childNewTopLeftX, childNewTopLeftY),
26806
- pointFrom24(childCX + changeInX, childCY + changeInY),
26922
+ const [childX, childY] = pointRotateRads14(
26923
+ pointFrom25(childNewTopLeftX, childNewTopLeftY),
26924
+ pointFrom25(childCX + changeInX, childCY + changeInY),
26807
26925
  -child.angle
26808
26926
  );
26809
26927
  scene.mutateElement(
@@ -26920,12 +27038,12 @@ var StatsDragInput = ({
26920
27038
  );
26921
27039
  }
26922
27040
  window.removeEventListener(
26923
- EVENT12.POINTER_MOVE,
27041
+ EVENT13.POINTER_MOVE,
26924
27042
  callbacks.onPointerMove,
26925
27043
  false
26926
27044
  );
26927
27045
  window.removeEventListener(
26928
- EVENT12.POINTER_UP,
27046
+ EVENT13.POINTER_UP,
26929
27047
  callbacks.onPointerUp,
26930
27048
  false
26931
27049
  );
@@ -27004,7 +27122,7 @@ var StatsDragInput = ({
27004
27122
  };
27005
27123
  const onPointerUp = () => {
27006
27124
  window.removeEventListener(
27007
- EVENT12.POINTER_MOVE,
27125
+ EVENT13.POINTER_MOVE,
27008
27126
  onPointerMove,
27009
27127
  false
27010
27128
  );
@@ -27023,12 +27141,12 @@ var StatsDragInput = ({
27023
27141
  originalElements = null;
27024
27142
  originalElementsMap = null;
27025
27143
  document.body.classList.remove("excalidraw-cursor-resize");
27026
- window.removeEventListener(EVENT12.POINTER_UP, onPointerUp, false);
27144
+ window.removeEventListener(EVENT13.POINTER_UP, onPointerUp, false);
27027
27145
  };
27028
27146
  callbacksRef.current.onPointerMove = onPointerMove;
27029
27147
  callbacksRef.current.onPointerUp = onPointerUp;
27030
- window.addEventListener(EVENT12.POINTER_MOVE, onPointerMove, false);
27031
- window.addEventListener(EVENT12.POINTER_UP, onPointerUp, false);
27148
+ window.addEventListener(EVENT13.POINTER_MOVE, onPointerMove, false);
27149
+ window.addEventListener(EVENT13.POINTER_UP, onPointerUp, false);
27032
27150
  }
27033
27151
  },
27034
27152
  onPointerEnter: () => {
@@ -27633,7 +27751,7 @@ var MultiAngle = ({
27633
27751
  var MultiAngle_default = MultiAngle;
27634
27752
 
27635
27753
  // components/Stats/MultiDimension.tsx
27636
- import { pointFrom as pointFrom25 } from "@excalidraw/math";
27754
+ import { pointFrom as pointFrom26 } from "@excalidraw/math";
27637
27755
  import { useMemo as useMemo9 } from "react";
27638
27756
  import { MIN_WIDTH_OR_HEIGHT as MIN_WIDTH_OR_HEIGHT2 } from "@excalidraw/common";
27639
27757
  import {
@@ -27761,7 +27879,7 @@ var handleDimensionChange2 = ({
27761
27879
  nextHeight,
27762
27880
  initialHeight,
27763
27881
  aspectRatio,
27764
- pointFrom25(x1, y1),
27882
+ pointFrom26(x1, y1),
27765
27883
  property,
27766
27884
  latestElements,
27767
27885
  originalElements2,
@@ -27863,7 +27981,7 @@ var handleDimensionChange2 = ({
27863
27981
  nextHeight,
27864
27982
  initialHeight,
27865
27983
  aspectRatio,
27866
- pointFrom25(x1, y1),
27984
+ pointFrom26(x1, y1),
27867
27985
  property,
27868
27986
  latestElements,
27869
27987
  originalElements2,
@@ -28108,7 +28226,7 @@ var MultiFontSize = ({
28108
28226
  var MultiFontSize_default = MultiFontSize;
28109
28227
 
28110
28228
  // components/Stats/MultiPosition.tsx
28111
- import { pointFrom as pointFrom26, pointRotateRads as pointRotateRads14 } from "@excalidraw/math";
28229
+ import { pointFrom as pointFrom27, pointRotateRads as pointRotateRads15 } from "@excalidraw/math";
28112
28230
  import { useMemo as useMemo10 } from "react";
28113
28231
  import { isTextElement as isTextElement18 } from "@excalidraw/element";
28114
28232
  import { getCommonBounds as getCommonBounds9 } from "@excalidraw/element";
@@ -28120,9 +28238,9 @@ var moveElements = (property, changeInTopX, changeInTopY, originalElements, orig
28120
28238
  origElement.x + origElement.width / 2,
28121
28239
  origElement.y + origElement.height / 2
28122
28240
  ];
28123
- const [topLeftX, topLeftY] = pointRotateRads14(
28124
- pointFrom26(origElement.x, origElement.y),
28125
- pointFrom26(cx, cy),
28241
+ const [topLeftX, topLeftY] = pointRotateRads15(
28242
+ pointFrom27(origElement.x, origElement.y),
28243
+ pointFrom27(cx, cy),
28126
28244
  origElement.angle
28127
28245
  );
28128
28246
  const newTopLeftX = property === "x" ? Math.round(topLeftX + changeInTopX) : topLeftX;
@@ -28153,9 +28271,9 @@ var moveGroupTo = (nextX, nextY, originalElements, originalElementsMap, scene) =
28153
28271
  latestElement.x + latestElement.width / 2,
28154
28272
  latestElement.y + latestElement.height / 2
28155
28273
  ];
28156
- const [topLeftX, topLeftY] = pointRotateRads14(
28157
- pointFrom26(latestElement.x, latestElement.y),
28158
- pointFrom26(cx, cy),
28274
+ const [topLeftX, topLeftY] = pointRotateRads15(
28275
+ pointFrom27(latestElement.x, latestElement.y),
28276
+ pointFrom27(cx, cy),
28159
28277
  latestElement.angle
28160
28278
  );
28161
28279
  moveElement(
@@ -28211,9 +28329,9 @@ var handlePositionChange = ({
28211
28329
  origElement.x + origElement.width / 2,
28212
28330
  origElement.y + origElement.height / 2
28213
28331
  ];
28214
- const [topLeftX, topLeftY] = pointRotateRads14(
28215
- pointFrom26(origElement.x, origElement.y),
28216
- pointFrom26(cx, cy),
28332
+ const [topLeftX, topLeftY] = pointRotateRads15(
28333
+ pointFrom27(origElement.x, origElement.y),
28334
+ pointFrom27(cx, cy),
28217
28335
  origElement.angle
28218
28336
  );
28219
28337
  const newTopLeftX = property === "x" ? nextValue : topLeftX;
@@ -28262,9 +28380,9 @@ var MultiPosition = ({
28262
28380
  }
28263
28381
  const [el] = elementsInUnit;
28264
28382
  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),
28383
+ const [topLeftX, topLeftY] = pointRotateRads15(
28384
+ pointFrom27(el.x, el.y),
28385
+ pointFrom27(cx, cy),
28268
28386
  el.angle
28269
28387
  );
28270
28388
  return Math.round((property === "x" ? topLeftX : topLeftY) * 100) / 100;
@@ -28288,7 +28406,7 @@ var MultiPosition = ({
28288
28406
  var MultiPosition_default = MultiPosition;
28289
28407
 
28290
28408
  // components/Stats/Position.tsx
28291
- import { clamp as clamp6, pointFrom as pointFrom27, pointRotateRads as pointRotateRads15, round as round4 } from "@excalidraw/math";
28409
+ import { clamp as clamp6, pointFrom as pointFrom28, pointRotateRads as pointRotateRads16, round as round4 } from "@excalidraw/math";
28292
28410
  import {
28293
28411
  getFlipAdjustedCropPosition,
28294
28412
  getUncroppedWidthAndHeight as getUncroppedWidthAndHeight2
@@ -28312,9 +28430,9 @@ var handlePositionChange2 = ({
28312
28430
  origElement.x + origElement.width / 2,
28313
28431
  origElement.y + origElement.height / 2
28314
28432
  ];
28315
- const [topLeftX, topLeftY] = pointRotateRads15(
28316
- pointFrom27(origElement.x, origElement.y),
28317
- pointFrom27(cx, cy),
28433
+ const [topLeftX, topLeftY] = pointRotateRads16(
28434
+ pointFrom28(origElement.x, origElement.y),
28435
+ pointFrom28(cx, cy),
28318
28436
  origElement.angle
28319
28437
  );
28320
28438
  if (originalAppState.croppingElementId === origElement.id) {
@@ -28412,9 +28530,9 @@ var Position = ({
28412
28530
  scene,
28413
28531
  appState
28414
28532
  }) => {
28415
- const [topLeftX, topLeftY] = pointRotateRads15(
28416
- pointFrom27(element.x, element.y),
28417
- pointFrom27(element.x + element.width / 2, element.y + element.height / 2),
28533
+ const [topLeftX, topLeftY] = pointRotateRads16(
28534
+ pointFrom28(element.x, element.y),
28535
+ pointFrom28(element.x + element.width / 2, element.y + element.height / 2),
28418
28536
  element.angle
28419
28537
  );
28420
28538
  let value = round4(property === "x" ? topLeftX : topLeftY, 2);
@@ -31183,6 +31301,7 @@ var useExcalidrawSetAppState = () => useContext3(ExcalidrawSetAppStateContext);
31183
31301
  var useExcalidrawActionManager = () => useContext3(ExcalidrawActionManagerContext);
31184
31302
  var didTapTwice = false;
31185
31303
  var tappedTwiceTimer = 0;
31304
+ var firstTapPosition = null;
31186
31305
  var isHoldingSpace = false;
31187
31306
  var isPanning = false;
31188
31307
  var isDraggingScrollBar = false;
@@ -31258,6 +31377,7 @@ var App = class _App extends React43.Component {
31258
31377
  __publicField(this, "onScrollChangeEmitter", new Emitter3());
31259
31378
  __publicField(this, "missingPointerEventCleanupEmitter", new Emitter3());
31260
31379
  __publicField(this, "onRemoveEventListenersEmitter", new Emitter3());
31380
+ __publicField(this, "defaultSelectionTool", "selection");
31261
31381
  __publicField(this, "updateEditorAtom", (atom2, ...args) => {
31262
31382
  const result = editorJotaiStore.set(atom2, ...args);
31263
31383
  this.triggerRender();
@@ -31600,7 +31720,7 @@ var App = class _App extends React43.Component {
31600
31720
  this.updateScene({
31601
31721
  elements: this.scene.getElementsIncludingDeleted().map((el) => {
31602
31722
  if (this.state.selectedElementIds[el.id]) {
31603
- return newElementWith10(el, {
31723
+ return newElementWith11(el, {
31604
31724
  [shouldUpdateStrokeColor ? "strokeColor" : "backgroundColor"]: color
31605
31725
  });
31606
31726
  }
@@ -31764,7 +31884,11 @@ var App = class _App extends React43.Component {
31764
31884
  }
31765
31885
  };
31766
31886
  }
31767
- const scene = restore(initialData, null, null, { repairBindings: true });
31887
+ const scene = restore(initialData, null, null, {
31888
+ repairBindings: true,
31889
+ deleteInvisibleElements: true
31890
+ });
31891
+ const activeTool = scene.appState.activeTool;
31768
31892
  scene.appState = {
31769
31893
  ...scene.appState,
31770
31894
  theme: this.props.theme || scene.appState.theme,
@@ -31773,7 +31897,10 @@ var App = class _App extends React43.Component {
31773
31897
  // update the state outside of initialData (e.g. when loading the app
31774
31898
  // with a library install link, which should auto-open the library)
31775
31899
  openSidebar: scene.appState?.openSidebar || this.state.openSidebar,
31776
- activeTool: scene.appState.activeTool.type === "image" ? { ...scene.appState.activeTool, type: "selection" } : scene.appState.activeTool,
31900
+ activeTool: activeTool.type === "image" || activeTool.type === "lasso" || activeTool.type === "selection" ? {
31901
+ ...activeTool,
31902
+ type: this.defaultSelectionTool
31903
+ } : scene.appState.activeTool,
31777
31904
  isLoading: false,
31778
31905
  toast: this.state.toast
31779
31906
  };
@@ -31803,6 +31930,12 @@ var App = class _App extends React43.Component {
31803
31930
  this.scrollToContent(window.location.href, { animate: false });
31804
31931
  }
31805
31932
  });
31933
+ __publicField(this, "isMobileOrTablet", () => {
31934
+ const hasTouch = "ontouchstart" in window || navigator.maxTouchPoints > 0;
31935
+ const hasCoarsePointer = "matchMedia" in window && window?.matchMedia("(pointer: coarse)")?.matches;
31936
+ const isTouchMobile = hasTouch && hasCoarsePointer;
31937
+ return isMobile || isTouchMobile;
31938
+ });
31806
31939
  __publicField(this, "isMobileBreakpoint", (width, height) => {
31807
31940
  return width < MQ_MAX_WIDTH_PORTRAIT || height < MQ_MAX_HEIGHT_LANDSCAPE && width < MQ_MAX_WIDTH_LANDSCAPE;
31808
31941
  });
@@ -31916,6 +32049,12 @@ var App = class _App extends React43.Component {
31916
32049
  }
31917
32050
  if (!didTapTwice) {
31918
32051
  didTapTwice = true;
32052
+ if (event.touches.length === 1) {
32053
+ firstTapPosition = {
32054
+ x: event.touches[0].clientX,
32055
+ y: event.touches[0].clientY
32056
+ };
32057
+ }
31919
32058
  clearTimeout(tappedTwiceTimer);
31920
32059
  tappedTwiceTimer = window.setTimeout(
31921
32060
  _App.resetTapTwice,
@@ -31923,12 +32062,20 @@ var App = class _App extends React43.Component {
31923
32062
  );
31924
32063
  return;
31925
32064
  }
31926
- if (didTapTwice && event.touches.length === 1) {
32065
+ if (didTapTwice && event.touches.length === 1 && firstTapPosition) {
31927
32066
  const touch = event.touches[0];
31928
- this.handleCanvasDoubleClick({
31929
- clientX: touch.clientX,
31930
- clientY: touch.clientY
31931
- });
32067
+ const distance3 = pointDistance8(
32068
+ pointFrom29(touch.clientX, touch.clientY),
32069
+ pointFrom29(firstTapPosition.x, firstTapPosition.y)
32070
+ );
32071
+ if (distance3 <= DOUBLE_TAP_POSITION_THRESHOLD) {
32072
+ this.lassoTrail.endPath();
32073
+ this.deselectElements();
32074
+ this.handleCanvasDoubleClick({
32075
+ clientX: touch.clientX,
32076
+ clientY: touch.clientY
32077
+ });
32078
+ }
31932
32079
  didTapTwice = false;
31933
32080
  clearTimeout(tappedTwiceTimer);
31934
32081
  }
@@ -31953,7 +32100,6 @@ var App = class _App extends React43.Component {
31953
32100
  gesture.pointers.clear();
31954
32101
  }
31955
32102
  });
31956
- // TODO: this is so spaghetti, we should refactor it and cover it with tests
31957
32103
  __publicField(this, "pasteFromClipboard", withBatchedUpdates(
31958
32104
  async (event) => {
31959
32105
  const isPlainPaste = !!IS_PLAIN_PASTE;
@@ -31969,37 +32115,9 @@ var App = class _App extends React43.Component {
31969
32115
  if (event && (!(elementUnderCursor instanceof HTMLCanvasElement) || isWritableElement3(target))) {
31970
32116
  return;
31971
32117
  }
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
- }
32118
+ const dataTransferList = await parseDataTransferEvent(event);
32119
+ const filesList = dataTransferList.getFiles();
32120
+ const data = await parseClipboard(dataTransferList, isPlainPaste);
32003
32121
  if (this.props.onPaste) {
32004
32122
  try {
32005
32123
  if (await this.props.onPaste(data, event) === false) {
@@ -32009,82 +32127,15 @@ var App = class _App extends React43.Component {
32009
32127
  console.error(error);
32010
32128
  }
32011
32129
  }
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" });
32130
+ await this.insertClipboardContent(data, filesList, isPlainPaste);
32131
+ this.setActiveTool({ type: this.defaultSelectionTool }, true);
32083
32132
  event?.preventDefault();
32084
32133
  }
32085
32134
  ));
32086
32135
  __publicField(this, "addElementsFromPasteOrLibrary", (opts) => {
32087
- const elements = restoreElements(opts.elements, null, void 0);
32136
+ const elements = restoreElements(opts.elements, null, {
32137
+ deleteInvisibleElements: true
32138
+ });
32088
32139
  const [minX, minY, maxX, maxY] = getCommonBounds12(elements);
32089
32140
  const elementsCenterX = distance2(minX, maxX) / 2;
32090
32141
  const elementsCenterY = distance2(minY, maxY) / 2;
@@ -32100,7 +32151,7 @@ var App = class _App extends React43.Component {
32100
32151
  const { duplicatedElements } = duplicateElements3({
32101
32152
  type: "everything",
32102
32153
  elements: elements.map((element) => {
32103
- return newElementWith10(element, {
32154
+ return newElementWith11(element, {
32104
32155
  x: element.x + gridX - minX,
32105
32156
  y: element.y + gridY - minY
32106
32157
  });
@@ -32181,7 +32232,7 @@ var App = class _App extends React43.Component {
32181
32232
  }
32182
32233
  }
32183
32234
  );
32184
- this.setActiveTool({ type: "selection" });
32235
+ this.setActiveTool({ type: this.defaultSelectionTool }, true);
32185
32236
  if (opts.fitToContent) {
32186
32237
  this.scrollToContent(duplicatedElements, {
32187
32238
  fitToContent: true,
@@ -32212,7 +32263,7 @@ var App = class _App extends React43.Component {
32212
32263
  ...prevState.activeTool,
32213
32264
  ...updateActiveTool7(
32214
32265
  this.state,
32215
- prevState.activeTool.locked ? { type: "selection" } : prevState.activeTool
32266
+ prevState.activeTool.locked ? { type: this.defaultSelectionTool } : prevState.activeTool
32216
32267
  ),
32217
32268
  locked: !prevState.activeTool.locked
32218
32269
  }
@@ -32403,11 +32454,11 @@ var App = class _App extends React43.Component {
32403
32454
  }
32404
32455
  addedFiles[fileData.id] = fileData;
32405
32456
  nextFiles[fileData.id] = fileData;
32406
- if (fileData.mimeType === MIME_TYPES8.svg) {
32457
+ if (fileData.mimeType === MIME_TYPES9.svg) {
32407
32458
  try {
32408
32459
  const restoredDataURL = getDataURL_sync(
32409
32460
  normalizeSVG(dataURLToString(fileData.dataURL)),
32410
- MIME_TYPES8.svg
32461
+ MIME_TYPES9.svg
32411
32462
  );
32412
32463
  if (fileData.dataURL !== restoredDataURL) {
32413
32464
  fileData.version = (fileData.version ?? 1) + 1;
@@ -32447,6 +32498,19 @@ var App = class _App extends React43.Component {
32447
32498
  }
32448
32499
  }
32449
32500
  ));
32501
+ __publicField(this, "applyDeltas", (deltas, options) => {
32502
+ const aggregatedDelta = StoreDelta2.squash(...deltas);
32503
+ const nextAppState = { ...this.state };
32504
+ const nextElements = new Map(
32505
+ this.scene.getElementsMapIncludingDeleted()
32506
+ );
32507
+ return StoreDelta2.applyTo(
32508
+ aggregatedDelta,
32509
+ nextElements,
32510
+ nextAppState,
32511
+ options
32512
+ );
32513
+ });
32450
32514
  __publicField(this, "mutateElement", (element, updates, informMutation = true) => {
32451
32515
  return this.scene.mutateElement(element, updates, {
32452
32516
  informMutation,
@@ -32814,7 +32878,7 @@ var App = class _App extends React43.Component {
32814
32878
  }
32815
32879
  }
32816
32880
  } else if (!event.ctrlKey && !event.altKey && !event.metaKey && !this.state.newElement && !this.state.selectionElement && !this.state.selectedElementsAreBeingDragged) {
32817
- const shape = findShapeByKey(event.key);
32881
+ const shape = findShapeByKey(event.key, this);
32818
32882
  if (shape) {
32819
32883
  if (this.state.activeTool.type !== shape) {
32820
32884
  trackEvent(
@@ -32871,7 +32935,7 @@ var App = class _App extends React43.Component {
32871
32935
  }
32872
32936
  if (event.key === KEYS52.K && !event.altKey && !event[KEYS52.CTRL_OR_CMD]) {
32873
32937
  if (this.state.activeTool.type === "laser") {
32874
- this.setActiveTool({ type: "selection" });
32938
+ this.setActiveTool({ type: this.defaultSelectionTool });
32875
32939
  } else {
32876
32940
  this.setActiveTool({ type: "laser" });
32877
32941
  }
@@ -32999,7 +33063,7 @@ var App = class _App extends React43.Component {
32999
33063
  this.setState({ suggestedBindings: [] });
33000
33064
  }
33001
33065
  if (nextActiveTool.type === "image") {
33002
- this.onImageAction();
33066
+ this.onImageToolbarButtonClick();
33003
33067
  }
33004
33068
  this.setState((prevState) => {
33005
33069
  const commonResets = {
@@ -33246,7 +33310,7 @@ var App = class _App extends React43.Component {
33246
33310
  if (this.state.multiElement) {
33247
33311
  return;
33248
33312
  }
33249
- if (this.state.activeTool.type !== "selection") {
33313
+ if (this.state.activeTool.type !== this.defaultSelectionTool) {
33250
33314
  return;
33251
33315
  }
33252
33316
  const selectedElements = this.scene.getSelectedElements(this.state);
@@ -33356,7 +33420,7 @@ var App = class _App extends React43.Component {
33356
33420
  );
33357
33421
  if (container) {
33358
33422
  if (hasBoundTextElement9(container) || !isTransparent6(container.backgroundColor) || hitElementItself({
33359
- point: pointFrom28(sceneX, sceneY),
33423
+ point: pointFrom29(sceneX, sceneY),
33360
33424
  element: container,
33361
33425
  elementsMap: this.scene.getNonDeletedElementsMap(),
33362
33426
  threshold: this.getElementHitThreshold(container)
@@ -33394,7 +33458,7 @@ var App = class _App extends React43.Component {
33394
33458
  element,
33395
33459
  this.scene.getNonDeletedElementsMap(),
33396
33460
  this.state,
33397
- pointFrom28(scenePointer.x, scenePointer.y),
33461
+ pointFrom29(scenePointer.x, scenePointer.y),
33398
33462
  this.device.editor.isMobile
33399
33463
  )) {
33400
33464
  return element;
@@ -33403,11 +33467,11 @@ var App = class _App extends React43.Component {
33403
33467
  });
33404
33468
  __publicField(this, "redirectToLink", (event, isTouchScreen) => {
33405
33469
  const draggedDistance = pointDistance8(
33406
- pointFrom28(
33470
+ pointFrom29(
33407
33471
  this.lastPointerDownEvent.clientX,
33408
33472
  this.lastPointerDownEvent.clientY
33409
33473
  ),
33410
- pointFrom28(
33474
+ pointFrom29(
33411
33475
  this.lastPointerUpEvent.clientX,
33412
33476
  this.lastPointerUpEvent.clientY
33413
33477
  )
@@ -33424,7 +33488,7 @@ var App = class _App extends React43.Component {
33424
33488
  this.hitLinkElement,
33425
33489
  elementsMap,
33426
33490
  this.state,
33427
- pointFrom28(lastPointerDownCoords.x, lastPointerDownCoords.y),
33491
+ pointFrom29(lastPointerDownCoords.x, lastPointerDownCoords.y),
33428
33492
  this.device.editor.isMobile
33429
33493
  );
33430
33494
  const lastPointerUpCoords = viewportCoordsToSceneCoords4(
@@ -33435,7 +33499,7 @@ var App = class _App extends React43.Component {
33435
33499
  this.hitLinkElement,
33436
33500
  elementsMap,
33437
33501
  this.state,
33438
- pointFrom28(lastPointerUpCoords.x, lastPointerUpCoords.y),
33502
+ pointFrom29(lastPointerUpCoords.x, lastPointerUpCoords.y),
33439
33503
  this.device.editor.isMobile
33440
33504
  );
33441
33505
  if (lastPointerDownHittingLinkIcon && lastPointerUpHittingLinkIcon) {
@@ -33445,7 +33509,7 @@ var App = class _App extends React43.Component {
33445
33509
  url = normalizeLink3(url);
33446
33510
  let customEvent;
33447
33511
  if (this.props.onLinkOpen) {
33448
- customEvent = wrapEvent2(EVENT13.EXCALIDRAW_LINK, event.nativeEvent);
33512
+ customEvent = wrapEvent2(EVENT14.EXCALIDRAW_LINK, event.nativeEvent);
33449
33513
  this.props.onLinkOpen(
33450
33514
  {
33451
33515
  ...this.hitLinkElement,
@@ -33468,7 +33532,7 @@ var App = class _App extends React43.Component {
33468
33532
  __publicField(this, "getTopLayerFrameAtSceneCoords", (sceneCoords) => {
33469
33533
  const elementsMap = this.scene.getNonDeletedElementsMap();
33470
33534
  const frames = this.scene.getNonDeletedFramesLikes().filter(
33471
- (frame) => isCursorInFrame(sceneCoords, frame, elementsMap)
33535
+ (frame) => !frame.locked && isCursorInFrame(sceneCoords, frame, elementsMap)
33472
33536
  );
33473
33537
  return frames.length ? frames[frames.length - 1] : null;
33474
33538
  });
@@ -33611,7 +33675,7 @@ var App = class _App extends React43.Component {
33611
33675
  setCursorForShape(this.interactiveCanvas, this.state);
33612
33676
  if (lastPoint === lastCommittedPoint) {
33613
33677
  if (pointDistance8(
33614
- pointFrom28(scenePointerX - rx, scenePointerY - ry),
33678
+ pointFrom29(scenePointerX - rx, scenePointerY - ry),
33615
33679
  lastPoint
33616
33680
  ) >= LINE_CONFIRM_THRESHOLD2) {
33617
33681
  this.scene.mutateElement(
@@ -33619,7 +33683,7 @@ var App = class _App extends React43.Component {
33619
33683
  {
33620
33684
  points: [
33621
33685
  ...points,
33622
- pointFrom28(scenePointerX - rx, scenePointerY - ry)
33686
+ pointFrom29(scenePointerX - rx, scenePointerY - ry)
33623
33687
  ]
33624
33688
  },
33625
33689
  { informMutation: false, isDragging: false }
@@ -33628,7 +33692,7 @@ var App = class _App extends React43.Component {
33628
33692
  setCursor(this.interactiveCanvas, CURSOR_TYPE4.POINTER);
33629
33693
  }
33630
33694
  } else if (points.length > 2 && lastCommittedPoint && pointDistance8(
33631
- pointFrom28(scenePointerX - rx, scenePointerY - ry),
33695
+ pointFrom29(scenePointerX - rx, scenePointerY - ry),
33632
33696
  lastCommittedPoint
33633
33697
  ) < LINE_CONFIRM_THRESHOLD2) {
33634
33698
  setCursor(this.interactiveCanvas, CURSOR_TYPE4.POINTER);
@@ -33666,7 +33730,7 @@ var App = class _App extends React43.Component {
33666
33730
  {
33667
33731
  points: [
33668
33732
  ...points.slice(0, -1),
33669
- pointFrom28(
33733
+ pointFrom29(
33670
33734
  lastCommittedX + dxFromLastCommitted,
33671
33735
  lastCommittedY + dyFromLastCommitted
33672
33736
  )
@@ -33682,7 +33746,7 @@ var App = class _App extends React43.Component {
33682
33746
  return;
33683
33747
  }
33684
33748
  const hasDeselectedButton = Boolean(event.buttons);
33685
- if (hasDeselectedButton || this.state.activeTool.type !== "selection" && this.state.activeTool.type !== "text" && this.state.activeTool.type !== "eraser") {
33749
+ if (hasDeselectedButton || this.state.activeTool.type !== "selection" && this.state.activeTool.type !== "lasso" && this.state.activeTool.type !== "text" && this.state.activeTool.type !== "eraser") {
33686
33750
  return;
33687
33751
  }
33688
33752
  const elements = this.scene.getNonDeletedElements();
@@ -33796,7 +33860,9 @@ var App = class _App extends React43.Component {
33796
33860
  });
33797
33861
  } else if (!hitElement || // Ebow arrows can only be moved when unconnected
33798
33862
  !isElbowArrow11(hitElement) || !(hitElement.startBinding || hitElement.endBinding)) {
33799
- setCursor(this.interactiveCanvas, CURSOR_TYPE4.MOVE);
33863
+ if (this.state.activeTool.type !== "lasso" || selectedElements.length > 0) {
33864
+ setCursor(this.interactiveCanvas, CURSOR_TYPE4.MOVE);
33865
+ }
33800
33866
  if (this.state.activeEmbeddable?.state === "hover") {
33801
33867
  this.setState({ activeEmbeddable: null });
33802
33868
  }
@@ -33957,7 +34023,7 @@ var App = class _App extends React43.Component {
33957
34023
  };
33958
34024
  const unsubPointerUp = addEventListener2(
33959
34025
  window,
33960
- EVENT13.POINTER_UP,
34026
+ EVENT14.POINTER_UP,
33961
34027
  onPointerUp2,
33962
34028
  {
33963
34029
  once: true
@@ -33994,11 +34060,76 @@ var App = class _App extends React43.Component {
33994
34060
  return;
33995
34061
  }
33996
34062
  if (this.state.activeTool.type === "lasso") {
33997
- this.lassoTrail.startPath(
33998
- pointerDownState.origin.x,
33999
- pointerDownState.origin.y,
34000
- event.shiftKey
34001
- );
34063
+ const hitSelectedElement = pointerDownState.hit.element && this.isASelectedElement(pointerDownState.hit.element);
34064
+ const isMobileOrTablet = this.isMobileOrTablet();
34065
+ if (!pointerDownState.hit.hasHitCommonBoundingBoxOfSelectedElements && !pointerDownState.resize.handleType && !hitSelectedElement) {
34066
+ this.lassoTrail.startPath(
34067
+ pointerDownState.origin.x,
34068
+ pointerDownState.origin.y,
34069
+ event.shiftKey
34070
+ );
34071
+ pointerDownState.drag.blockDragging = !isMobileOrTablet;
34072
+ }
34073
+ if (isMobileOrTablet && pointerDownState.hit.element && !hitSelectedElement) {
34074
+ this.setState((prevState) => {
34075
+ const nextSelectedElementIds = {
34076
+ ...prevState.selectedElementIds,
34077
+ [pointerDownState.hit.element.id]: true
34078
+ };
34079
+ const previouslySelectedElements = [];
34080
+ Object.keys(prevState.selectedElementIds).forEach((id) => {
34081
+ const element = this.scene.getElement(id);
34082
+ element && previouslySelectedElements.push(element);
34083
+ });
34084
+ const hitElement = pointerDownState.hit.element;
34085
+ if (isFrameLikeElement15(hitElement)) {
34086
+ getFrameChildren6(previouslySelectedElements, hitElement.id).forEach(
34087
+ (element) => {
34088
+ delete nextSelectedElementIds[element.id];
34089
+ }
34090
+ );
34091
+ } else if (hitElement.frameId) {
34092
+ if (nextSelectedElementIds[hitElement.frameId]) {
34093
+ delete nextSelectedElementIds[hitElement.id];
34094
+ }
34095
+ } else {
34096
+ const groupIds = hitElement.groupIds;
34097
+ const framesInGroups = new Set(
34098
+ groupIds.flatMap(
34099
+ (gid) => getElementsInGroup9(this.scene.getNonDeletedElements(), gid)
34100
+ ).filter((element) => isFrameLikeElement15(element)).map((frame) => frame.id)
34101
+ );
34102
+ if (framesInGroups.size > 0) {
34103
+ previouslySelectedElements.forEach((element) => {
34104
+ if (element.frameId && framesInGroups.has(element.frameId)) {
34105
+ delete nextSelectedElementIds[element.id];
34106
+ element.groupIds.flatMap(
34107
+ (gid) => getElementsInGroup9(
34108
+ this.scene.getNonDeletedElements(),
34109
+ gid
34110
+ )
34111
+ ).forEach((element2) => {
34112
+ delete nextSelectedElementIds[element2.id];
34113
+ });
34114
+ }
34115
+ });
34116
+ }
34117
+ }
34118
+ return {
34119
+ ...selectGroupsForSelectedElements6(
34120
+ {
34121
+ editingGroupId: prevState.editingGroupId,
34122
+ selectedElementIds: nextSelectedElementIds
34123
+ },
34124
+ this.scene.getNonDeletedElements(),
34125
+ prevState,
34126
+ this
34127
+ ),
34128
+ showHyperlinkPopup: hitElement.link || isEmbeddableElement4(hitElement) ? "info" : false
34129
+ };
34130
+ });
34131
+ pointerDownState.hit.wasAddedToSelection = true;
34132
+ }
34002
34133
  } else if (this.state.activeTool.type === "text") {
34003
34134
  this.handleTextOnPointerDown(event, pointerDownState);
34004
34135
  } else if (this.state.activeTool.type === "arrow" || this.state.activeTool.type === "line") {
@@ -34051,10 +34182,10 @@ var App = class _App extends React43.Component {
34051
34182
  (_event) => onPointerUp(_event || event.nativeEvent)
34052
34183
  );
34053
34184
  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);
34185
+ window.addEventListener(EVENT14.POINTER_MOVE, onPointerMove);
34186
+ window.addEventListener(EVENT14.POINTER_UP, onPointerUp);
34187
+ window.addEventListener(EVENT14.KEYDOWN, onKeyDown);
34188
+ window.addEventListener(EVENT14.KEYUP, onKeyUp);
34058
34189
  pointerDownState.eventListeners.onMove = onPointerMove;
34059
34190
  pointerDownState.eventListeners.onUp = onPointerUp;
34060
34191
  pointerDownState.eventListeners.onKeyUp = onKeyUp;
@@ -34102,7 +34233,7 @@ var App = class _App extends React43.Component {
34102
34233
  this.hitLinkElement,
34103
34234
  this.scene.getNonDeletedElementsMap(),
34104
34235
  this.state,
34105
- pointFrom28(scenePointer.x, scenePointer.y)
34236
+ pointFrom29(scenePointer.x, scenePointer.y)
34106
34237
  )) {
34107
34238
  this.handleEmbeddableCenterClick(this.hitLinkElement);
34108
34239
  } else {
@@ -34166,17 +34297,17 @@ var App = class _App extends React43.Component {
34166
34297
  if (isLinux && !nextPastePrevented && (Math.abs(deltaX) > 1 || Math.abs(deltaY) > 1)) {
34167
34298
  nextPastePrevented = true;
34168
34299
  const preventNextPaste = (event3) => {
34169
- document.body.removeEventListener(EVENT13.PASTE, preventNextPaste);
34300
+ document.body.removeEventListener(EVENT14.PASTE, preventNextPaste);
34170
34301
  event3.stopPropagation();
34171
34302
  };
34172
34303
  const enableNextPaste = () => {
34173
34304
  setTimeout(() => {
34174
- document.body.removeEventListener(EVENT13.PASTE, preventNextPaste);
34175
- window.removeEventListener(EVENT13.POINTER_UP, enableNextPaste);
34305
+ document.body.removeEventListener(EVENT14.PASTE, preventNextPaste);
34306
+ window.removeEventListener(EVENT14.POINTER_UP, enableNextPaste);
34176
34307
  }, 100);
34177
34308
  };
34178
- document.body.addEventListener(EVENT13.PASTE, preventNextPaste);
34179
- window.addEventListener(EVENT13.POINTER_UP, enableNextPaste);
34309
+ document.body.addEventListener(EVENT14.PASTE, preventNextPaste);
34310
+ window.addEventListener(EVENT14.POINTER_UP, enableNextPaste);
34180
34311
  }
34181
34312
  this.translateCanvas({
34182
34313
  scrollX: this.state.scrollX - deltaX / this.state.zoom.value,
@@ -34198,17 +34329,17 @@ var App = class _App extends React43.Component {
34198
34329
  cursorButton: "up"
34199
34330
  });
34200
34331
  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);
34332
+ window.removeEventListener(EVENT14.POINTER_MOVE, onPointerMove);
34333
+ window.removeEventListener(EVENT14.POINTER_UP, teardown);
34334
+ window.removeEventListener(EVENT14.BLUR, teardown);
34204
34335
  onPointerMove.flush();
34205
34336
  }
34206
34337
  );
34207
- window.addEventListener(EVENT13.BLUR, teardown);
34208
- window.addEventListener(EVENT13.POINTER_MOVE, onPointerMove, {
34338
+ window.addEventListener(EVENT14.BLUR, teardown);
34339
+ window.addEventListener(EVENT14.POINTER_MOVE, onPointerMove, {
34209
34340
  passive: true
34210
34341
  });
34211
- window.addEventListener(EVENT13.POINTER_UP, teardown);
34342
+ window.addEventListener(EVENT14.POINTER_UP, teardown);
34212
34343
  return true;
34213
34344
  });
34214
34345
  __publicField(this, "clearSelectionIfNotUsingSelection", () => {
@@ -34225,7 +34356,7 @@ var App = class _App extends React43.Component {
34225
34356
  * @returns whether the pointer event has been completely handled
34226
34357
  */
34227
34358
  __publicField(this, "handleSelectionOnPointerDown", (event, pointerDownState) => {
34228
- if (this.state.activeTool.type === "selection") {
34359
+ if (this.state.activeTool.type === "selection" || this.state.activeTool.type === "lasso") {
34229
34360
  const elements = this.scene.getNonDeletedElements();
34230
34361
  const elementsMap = this.scene.getNonDeletedElementsMap();
34231
34362
  const selectedElements = this.scene.getSelectedElements(this.state);
@@ -34375,6 +34506,15 @@ var App = class _App extends React43.Component {
34375
34506
  } else if (hitElement != null) {
34376
34507
  if (event[KEYS52.CTRL_OR_CMD]) {
34377
34508
  if (event.altKey) {
34509
+ if (this.state.openDialog?.name === "elementLinkSelector") {
34510
+ this.setOpenDialog(null);
34511
+ }
34512
+ this.lassoTrail.startPath(
34513
+ pointerDownState.origin.x,
34514
+ pointerDownState.origin.y,
34515
+ event.shiftKey
34516
+ );
34517
+ this.setActiveTool({ type: "lasso", fromSelection: true });
34378
34518
  return false;
34379
34519
  }
34380
34520
  if (!this.state.selectedElementIds[hitElement.id]) {
@@ -34501,7 +34641,9 @@ var App = class _App extends React43.Component {
34501
34641
  resetCursor(this.interactiveCanvas);
34502
34642
  if (!this.state.activeTool.locked) {
34503
34643
  this.setState({
34504
- activeTool: updateActiveTool7(this.state, { type: "selection" })
34644
+ activeTool: updateActiveTool7(this.state, {
34645
+ type: this.defaultSelectionTool
34646
+ })
34505
34647
  });
34506
34648
  }
34507
34649
  });
@@ -34531,7 +34673,7 @@ var App = class _App extends React43.Component {
34531
34673
  simulatePressure,
34532
34674
  locked: false,
34533
34675
  frameId: topLayerFrame ? topLayerFrame.id : null,
34534
- points: [pointFrom28(0, 0)],
34676
+ points: [pointFrom29(0, 0)],
34535
34677
  pressures: simulatePressure ? [] : [event.pressure]
34536
34678
  });
34537
34679
  this.scene.insertElement(element);
@@ -34630,11 +34772,10 @@ var App = class _App extends React43.Component {
34630
34772
  this.scene.insertElement(element);
34631
34773
  return element;
34632
34774
  });
34633
- __publicField(this, "createImageElement", async ({
34775
+ __publicField(this, "newImagePlaceholder", ({
34634
34776
  sceneX,
34635
34777
  sceneY,
34636
- addToFrameUnderCursor = true,
34637
- imageFile
34778
+ addToFrameUnderCursor = true
34638
34779
  }) => {
34639
34780
  const [gridX, gridY] = getGridPoint2(
34640
34781
  sceneX,
@@ -34646,7 +34787,7 @@ var App = class _App extends React43.Component {
34646
34787
  y: gridY
34647
34788
  }) : null;
34648
34789
  const placeholderSize = 100 / this.state.zoom.value;
34649
- const placeholderImageElement = newImageElement2({
34790
+ return newImageElement2({
34650
34791
  type: "image",
34651
34792
  strokeColor: this.state.currentItemStrokeColor,
34652
34793
  backgroundColor: this.state.currentItemBackgroundColor,
@@ -34663,11 +34804,6 @@ var App = class _App extends React43.Component {
34663
34804
  width: placeholderSize,
34664
34805
  height: placeholderSize
34665
34806
  });
34666
- const initializedImageElement = await this.insertImageElement(
34667
- placeholderImageElement,
34668
- imageFile
34669
- );
34670
- return initializedImageElement;
34671
34807
  });
34672
34808
  __publicField(this, "handleLinearElementOnPointerDown", (event, elementType, pointerDownState) => {
34673
34809
  if (this.state.multiElement) {
@@ -34688,7 +34824,7 @@ var App = class _App extends React43.Component {
34688
34824
  }
34689
34825
  const { x: rx, y: ry, lastCommittedPoint } = multiElement;
34690
34826
  if (multiElement.points.length > 1 && lastCommittedPoint && pointDistance8(
34691
- pointFrom28(
34827
+ pointFrom29(
34692
34828
  pointerDownState.origin.x - rx,
34693
34829
  pointerDownState.origin.y - ry
34694
34830
  ),
@@ -34772,7 +34908,7 @@ var App = class _App extends React43.Component {
34772
34908
  };
34773
34909
  });
34774
34910
  this.scene.mutateElement(element, {
34775
- points: [...element.points, pointFrom28(0, 0)]
34911
+ points: [...element.points, pointFrom29(0, 0)]
34776
34912
  });
34777
34913
  const boundElement = getHoveredElementForBinding2(
34778
34914
  pointerDownState.origin,
@@ -34867,7 +35003,7 @@ var App = class _App extends React43.Component {
34867
35003
  const elements = this.scene.getElementsIncludingDeleted().map((ele) => {
34868
35004
  if (this.elementsPendingErasure.has(ele.id) || ele.frameId && this.elementsPendingErasure.has(ele.frameId) || isBoundToContainer8(ele) && this.elementsPendingErasure.has(ele.containerId)) {
34869
35005
  didChange = true;
34870
- return newElementWith10(ele, { isDeleted: true });
35006
+ return newElementWith11(ele, { isDeleted: true });
34871
35007
  }
34872
35008
  return ele;
34873
35009
  });
@@ -34883,7 +35019,7 @@ var App = class _App extends React43.Component {
34883
35019
  }
34884
35020
  const mimeType = imageFile.type;
34885
35021
  setCursor(this.interactiveCanvas, "wait");
34886
- if (mimeType === MIME_TYPES8.svg) {
35022
+ if (mimeType === MIME_TYPES9.svg) {
34887
35023
  try {
34888
35024
  imageFile = SVGStringToFile(
34889
35025
  normalizeSVG(await imageFile.text()),
@@ -34976,57 +35112,14 @@ var App = class _App extends React43.Component {
34976
35112
  */
34977
35113
  __publicField(this, "getLatestInitializedImageElement", (imagePlaceholder, fileId) => {
34978
35114
  const latestImageElement = this.scene.getElement(imagePlaceholder.id) ?? imagePlaceholder;
34979
- return newElementWith10(
35115
+ return newElementWith11(
34980
35116
  latestImageElement,
34981
35117
  {
34982
35118
  fileId
34983
35119
  }
34984
35120
  );
34985
35121
  });
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 () => {
35122
+ __publicField(this, "onImageToolbarButtonClick", async () => {
35030
35123
  try {
35031
35124
  const clientX = this.state.width / 2 + this.state.offsetLeft;
35032
35125
  const clientY = this.state.height / 2 + this.state.offsetTop;
@@ -35034,21 +35127,14 @@ var App = class _App extends React43.Component {
35034
35127
  { clientX, clientY },
35035
35128
  this.state
35036
35129
  );
35037
- const imageFile = await fileOpen({
35130
+ const imageFiles = await fileOpen({
35038
35131
  description: "Image",
35039
35132
  extensions: Object.keys(
35040
35133
  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);
35134
+ ),
35135
+ multiple: true
35051
35136
  });
35137
+ this.insertImages(imageFiles, x, y);
35052
35138
  } catch (error) {
35053
35139
  if (error.name !== "AbortError") {
35054
35140
  console.error(error);
@@ -35058,7 +35144,9 @@ var App = class _App extends React43.Component {
35058
35144
  this.setState(
35059
35145
  {
35060
35146
  newElement: null,
35061
- activeTool: updateActiveTool7(this.state, { type: "selection" })
35147
+ activeTool: updateActiveTool7(this.state, {
35148
+ type: this.defaultSelectionTool
35149
+ })
35062
35150
  },
35063
35151
  () => {
35064
35152
  this.actionManager.executeAction(actionFinalize);
@@ -35095,9 +35183,9 @@ var App = class _App extends React43.Component {
35095
35183
  if (erroredFiles.size) {
35096
35184
  this.store.scheduleAction(CaptureUpdateAction37.NEVER);
35097
35185
  this.scene.replaceAllElements(
35098
- elements.map((element) => {
35186
+ this.scene.getElementsIncludingDeleted().map((element) => {
35099
35187
  if (isInitializedImageElement3(element) && erroredFiles.has(element.fileId)) {
35100
- return newElementWith10(element, {
35188
+ return newElementWith11(element, {
35101
35189
  status: "error"
35102
35190
  });
35103
35191
  }
@@ -35159,64 +35247,105 @@ var App = class _App extends React43.Component {
35159
35247
  if (canvas !== null) {
35160
35248
  this.interactiveCanvas = canvas;
35161
35249
  this.interactiveCanvas.addEventListener(
35162
- EVENT13.TOUCH_START,
35250
+ EVENT14.TOUCH_START,
35163
35251
  this.onTouchStart,
35164
35252
  { passive: false }
35165
35253
  );
35166
- this.interactiveCanvas.addEventListener(EVENT13.TOUCH_END, this.onTouchEnd);
35254
+ this.interactiveCanvas.addEventListener(EVENT14.TOUCH_END, this.onTouchEnd);
35167
35255
  } else {
35168
35256
  this.interactiveCanvas?.removeEventListener(
35169
- EVENT13.TOUCH_START,
35257
+ EVENT14.TOUCH_START,
35170
35258
  this.onTouchStart
35171
35259
  );
35172
35260
  this.interactiveCanvas?.removeEventListener(
35173
- EVENT13.TOUCH_END,
35261
+ EVENT14.TOUCH_END,
35174
35262
  this.onTouchEnd
35175
35263
  );
35176
35264
  }
35177
35265
  });
35266
+ __publicField(this, "insertImages", async (imageFiles, sceneX, sceneY) => {
35267
+ const gridPadding = 50 / this.state.zoom.value;
35268
+ const placeholders = positionElementsOnGrid(
35269
+ imageFiles.map(() => this.newImagePlaceholder({ sceneX, sceneY })),
35270
+ sceneX,
35271
+ sceneY,
35272
+ gridPadding
35273
+ );
35274
+ placeholders.forEach((el) => this.scene.insertElement(el));
35275
+ const initialized = await Promise.all(
35276
+ placeholders.map(async (placeholder, i) => {
35277
+ try {
35278
+ return await this.initializeImage(placeholder, imageFiles[i]);
35279
+ } catch (error) {
35280
+ this.setState({
35281
+ errorMessage: error.message || t("errors.imageInsertError")
35282
+ });
35283
+ return newElementWith11(placeholder, { isDeleted: true });
35284
+ }
35285
+ })
35286
+ );
35287
+ const initializedMap = arrayToMap27(initialized);
35288
+ const positioned = positionElementsOnGrid(
35289
+ initialized.filter((el) => !el.isDeleted),
35290
+ sceneX,
35291
+ sceneY,
35292
+ gridPadding
35293
+ );
35294
+ const positionedMap = arrayToMap27(positioned);
35295
+ const nextElements = this.scene.getElementsIncludingDeleted().map((el) => positionedMap.get(el.id) ?? initializedMap.get(el.id) ?? el);
35296
+ this.updateScene({
35297
+ appState: {
35298
+ selectedElementIds: makeNextSelectedElementIds2(
35299
+ Object.fromEntries(positioned.map((el) => [el.id, true])),
35300
+ this.state
35301
+ )
35302
+ },
35303
+ elements: nextElements,
35304
+ captureUpdate: CaptureUpdateAction37.IMMEDIATELY
35305
+ });
35306
+ this.setState({}, () => {
35307
+ this.actionManager.executeAction(actionFinalize);
35308
+ });
35309
+ });
35178
35310
  __publicField(this, "handleAppOnDrop", async (event) => {
35179
- const { file: file2, fileHandle } = await getFileFromEvent(event);
35180
35311
  const { x: sceneX, y: sceneY } = viewportCoordsToSceneCoords4(
35181
35312
  event,
35182
35313
  this.state
35183
35314
  );
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
- }
35315
+ const dataTransferList = await parseDataTransferEvent(event);
35316
+ const fileItems = dataTransferList.getFiles();
35317
+ if (fileItems.length === 1) {
35318
+ const { file: file2, fileHandle } = fileItems[0];
35319
+ if (file2 && (file2.type === MIME_TYPES9.png || file2.type === MIME_TYPES9.svg)) {
35320
+ try {
35321
+ const scene = await loadFromBlob(
35322
+ file2,
35323
+ this.state,
35324
+ this.scene.getElementsIncludingDeleted(),
35325
+ fileHandle
35326
+ );
35327
+ this.syncActionResult({
35328
+ ...scene,
35329
+ appState: {
35330
+ ...scene.appState || this.state,
35331
+ isLoading: false
35332
+ },
35333
+ replaceFiles: true,
35334
+ captureUpdate: CaptureUpdateAction37.IMMEDIATELY
35335
+ });
35336
+ return;
35337
+ } catch (error) {
35338
+ if (error.name !== "EncodingError") {
35339
+ throw new Error(t("alerts.couldNotLoadInvalidFile"));
35208
35340
  }
35209
35341
  }
35210
- this.createImageElement({ sceneX, sceneY, imageFile: file2 });
35211
- return;
35212
35342
  }
35213
- } catch (error) {
35214
- return this.setState({
35215
- isLoading: false,
35216
- errorMessage: error.message
35217
- });
35218
35343
  }
35219
- const libraryJSON = event.dataTransfer.getData(MIME_TYPES8.excalidrawlib);
35344
+ const imageFiles = fileItems.map((data) => data.file).filter((file2) => isSupportedImageFile(file2));
35345
+ if (imageFiles.length > 0 && this.isToolSupported("image")) {
35346
+ return this.insertImages(imageFiles, sceneX, sceneY);
35347
+ }
35348
+ const libraryJSON = dataTransferList.getData(MIME_TYPES9.excalidrawlib);
35220
35349
  if (libraryJSON && typeof libraryJSON === "string") {
35221
35350
  try {
35222
35351
  const libraryItems = parseLibraryJSON(libraryJSON);
@@ -35230,11 +35359,15 @@ var App = class _App extends React43.Component {
35230
35359
  }
35231
35360
  return;
35232
35361
  }
35233
- if (file2) {
35234
- await this.loadFileToCanvas(file2, fileHandle);
35362
+ if (fileItems.length > 0) {
35363
+ const { file: file2, fileHandle } = fileItems[0];
35364
+ if (file2) {
35365
+ await this.loadFileToCanvas(file2, fileHandle);
35366
+ }
35235
35367
  }
35236
- if (event.dataTransfer?.types?.includes("text/plain")) {
35237
- const text = event.dataTransfer?.getData("text");
35368
+ const textItem = dataTransferList.findByType(MIME_TYPES9.text);
35369
+ if (textItem) {
35370
+ const text = textItem.value;
35238
35371
  if (text && embeddableURLValidator2(text, this.props.validateEmbeddable) && (/^(http|https):\/\/[^\s/$.?#].[^\s]*$/.test(text) || getEmbedLink2(text)?.type === "video")) {
35239
35372
  const embeddable = this.insertEmbeddableElement({
35240
35373
  sceneX,
@@ -35278,7 +35411,7 @@ var App = class _App extends React43.Component {
35278
35411
  if (!ret) {
35279
35412
  return;
35280
35413
  }
35281
- if (ret.type === MIME_TYPES8.excalidraw) {
35414
+ if (ret.type === MIME_TYPES9.excalidraw) {
35282
35415
  syncInvalidIndices2(elements.concat(ret.data.elements));
35283
35416
  this.store.scheduleMicroAction({
35284
35417
  action: CaptureUpdateAction37.NEVER,
@@ -35295,7 +35428,7 @@ var App = class _App extends React43.Component {
35295
35428
  replaceFiles: true,
35296
35429
  captureUpdate: CaptureUpdateAction37.IMMEDIATELY
35297
35430
  });
35298
- } else if (ret.type === MIME_TYPES8.excalidrawlib) {
35431
+ } else if (ret.type === MIME_TYPES9.excalidrawlib) {
35299
35432
  await this.library.updateLibrary({
35300
35433
  libraryItems: file2,
35301
35434
  merge: true,
@@ -35312,7 +35445,7 @@ var App = class _App extends React43.Component {
35312
35445
  __publicField(this, "handleCanvasContextMenu", (event) => {
35313
35446
  event.preventDefault();
35314
35447
  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") {
35448
+ event.button !== POINTER_BUTTON2.SECONDARY) && this.state.activeTool.type !== this.defaultSelectionTool) {
35316
35449
  return;
35317
35450
  }
35318
35451
  const { x, y } = viewportCoordsToSceneCoords4(event, this.state);
@@ -35801,6 +35934,7 @@ var App = class _App extends React43.Component {
35801
35934
  this.setState({ ...this.getCanvasOffsets() });
35802
35935
  });
35803
35936
  const defaultAppState = getDefaultAppState();
35937
+ this.defaultSelectionTool = this.isMobileOrTablet() ? "lasso" : "selection";
35804
35938
  const {
35805
35939
  excalidrawAPI,
35806
35940
  viewModeEnabled = false,
@@ -35841,6 +35975,7 @@ var App = class _App extends React43.Component {
35841
35975
  if (excalidrawAPI) {
35842
35976
  const api = {
35843
35977
  updateScene: this.updateScene,
35978
+ applyDeltas: this.applyDeltas,
35844
35979
  mutateElement: this.mutateElement,
35845
35980
  updateLibrary: this.library.updateLibrary,
35846
35981
  addFiles: this.addFiles,
@@ -36320,7 +36455,7 @@ var App = class _App extends React43.Component {
36320
36455
  showExitZenModeBtn: typeof this.props?.zenModeEnabled === "undefined" && this.state.zenModeEnabled,
36321
36456
  UIOptions: this.props.UIOptions,
36322
36457
  onExportImage: this.onExportImage,
36323
- renderWelcomeScreen: !this.state.isLoading && this.state.showWelcomeScreen && this.state.activeTool.type === "selection" && !this.state.zenModeEnabled && !this.scene.getElementsIncludingDeleted().length,
36458
+ renderWelcomeScreen: !this.state.isLoading && this.state.showWelcomeScreen && this.state.activeTool.type === this.defaultSelectionTool && !this.state.zenModeEnabled && !this.scene.getElementsIncludingDeleted().length,
36324
36459
  app: this,
36325
36460
  isCollaborating: this.props.isCollaborating,
36326
36461
  generateLinkForSelection: this.props.generateLinkForSelection,
@@ -36754,26 +36889,26 @@ var App = class _App extends React43.Component {
36754
36889
  this.removeEventListeners();
36755
36890
  if (this.props.handleKeyboardGlobally) {
36756
36891
  this.onRemoveEventListenersEmitter.once(
36757
- addEventListener2(document, EVENT13.KEYDOWN, this.onKeyDown, false)
36892
+ addEventListener2(document, EVENT14.KEYDOWN, this.onKeyDown, false)
36758
36893
  );
36759
36894
  }
36760
36895
  this.onRemoveEventListenersEmitter.once(
36761
36896
  addEventListener2(
36762
36897
  this.excalidrawContainerRef.current,
36763
- EVENT13.WHEEL,
36898
+ EVENT14.WHEEL,
36764
36899
  this.handleWheel,
36765
36900
  { passive: false }
36766
36901
  ),
36767
- addEventListener2(window, EVENT13.MESSAGE, this.onWindowMessage, false),
36768
- addEventListener2(document, EVENT13.POINTER_UP, this.removePointer, {
36902
+ addEventListener2(window, EVENT14.MESSAGE, this.onWindowMessage, false),
36903
+ addEventListener2(document, EVENT14.POINTER_UP, this.removePointer, {
36769
36904
  passive: false
36770
36905
  }),
36771
36906
  // #3553
36772
- addEventListener2(document, EVENT13.COPY, this.onCopy, { passive: false }),
36773
- addEventListener2(document, EVENT13.KEYUP, this.onKeyUp, { passive: true }),
36907
+ addEventListener2(document, EVENT14.COPY, this.onCopy, { passive: false }),
36908
+ addEventListener2(document, EVENT14.KEYUP, this.onKeyUp, { passive: true }),
36774
36909
  addEventListener2(
36775
36910
  document,
36776
- EVENT13.POINTER_MOVE,
36911
+ EVENT14.POINTER_MOVE,
36777
36912
  this.updateCurrentCursorPosition,
36778
36913
  { passive: false }
36779
36914
  ),
@@ -36790,25 +36925,25 @@ var App = class _App extends React43.Component {
36790
36925
  // Safari-only desktop pinch zoom
36791
36926
  addEventListener2(
36792
36927
  document,
36793
- EVENT13.GESTURE_START,
36928
+ EVENT14.GESTURE_START,
36794
36929
  this.onGestureStart,
36795
36930
  false
36796
36931
  ),
36797
36932
  addEventListener2(
36798
36933
  document,
36799
- EVENT13.GESTURE_CHANGE,
36934
+ EVENT14.GESTURE_CHANGE,
36800
36935
  this.onGestureChange,
36801
36936
  false
36802
36937
  ),
36803
36938
  addEventListener2(
36804
36939
  document,
36805
- EVENT13.GESTURE_END,
36940
+ EVENT14.GESTURE_END,
36806
36941
  this.onGestureEnd,
36807
36942
  false
36808
36943
  ),
36809
36944
  addEventListener2(
36810
36945
  window,
36811
- EVENT13.FOCUS,
36946
+ EVENT14.FOCUS,
36812
36947
  () => {
36813
36948
  this.maybeCleanupAfterMissingPointerUp(null);
36814
36949
  this.triggerRender(true);
@@ -36822,32 +36957,32 @@ var App = class _App extends React43.Component {
36822
36957
  this.onRemoveEventListenersEmitter.once(
36823
36958
  addEventListener2(
36824
36959
  document,
36825
- EVENT13.FULLSCREENCHANGE,
36960
+ EVENT14.FULLSCREENCHANGE,
36826
36961
  this.onFullscreenChange,
36827
36962
  { passive: false }
36828
36963
  ),
36829
- addEventListener2(document, EVENT13.PASTE, this.pasteFromClipboard, {
36964
+ addEventListener2(document, EVENT14.PASTE, this.pasteFromClipboard, {
36830
36965
  passive: false
36831
36966
  }),
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),
36967
+ addEventListener2(document, EVENT14.CUT, this.onCut, { passive: false }),
36968
+ addEventListener2(window, EVENT14.RESIZE, this.onResize, false),
36969
+ addEventListener2(window, EVENT14.UNLOAD, this.onUnload, false),
36970
+ addEventListener2(window, EVENT14.BLUR, this.onBlur, false),
36836
36971
  addEventListener2(
36837
36972
  this.excalidrawContainerRef.current,
36838
- EVENT13.WHEEL,
36973
+ EVENT14.WHEEL,
36839
36974
  this.handleWheel,
36840
36975
  { passive: false }
36841
36976
  ),
36842
36977
  addEventListener2(
36843
36978
  this.excalidrawContainerRef.current,
36844
- EVENT13.DRAG_OVER,
36979
+ EVENT14.DRAG_OVER,
36845
36980
  this.disableEvent,
36846
36981
  false
36847
36982
  ),
36848
36983
  addEventListener2(
36849
36984
  this.excalidrawContainerRef.current,
36850
- EVENT13.DROP,
36985
+ EVENT14.DROP,
36851
36986
  this.disableEvent,
36852
36987
  false
36853
36988
  )
@@ -36856,7 +36991,7 @@ var App = class _App extends React43.Component {
36856
36991
  this.onRemoveEventListenersEmitter.once(
36857
36992
  addEventListener2(
36858
36993
  getNearestScrollableContainer(this.excalidrawContainerRef.current),
36859
- EVENT13.SCROLL,
36994
+ EVENT14.SCROLL,
36860
36995
  this.onScroll,
36861
36996
  { passive: false }
36862
36997
  )
@@ -36962,6 +37097,115 @@ var App = class _App extends React43.Component {
36962
37097
  }
36963
37098
  static resetTapTwice() {
36964
37099
  didTapTwice = false;
37100
+ firstTapPosition = null;
37101
+ }
37102
+ // TODO: Cover with tests
37103
+ async insertClipboardContent(data, dataTransferFiles, isPlainPaste) {
37104
+ const { x: sceneX, y: sceneY } = viewportCoordsToSceneCoords4(
37105
+ {
37106
+ clientX: this.lastViewportPosition.x,
37107
+ clientY: this.lastViewportPosition.y
37108
+ },
37109
+ this.state
37110
+ );
37111
+ if (data.errorMessage) {
37112
+ this.setState({ errorMessage: data.errorMessage });
37113
+ return;
37114
+ }
37115
+ if (dataTransferFiles.length === 0 && !isPlainPaste && data.mixedContent) {
37116
+ await this.addElementsFromMixedContentPaste(data.mixedContent, {
37117
+ isPlainPaste,
37118
+ sceneX,
37119
+ sceneY
37120
+ });
37121
+ return;
37122
+ }
37123
+ if (data.spreadsheet && !isPlainPaste) {
37124
+ this.setState({
37125
+ pasteDialog: {
37126
+ data: data.spreadsheet,
37127
+ shown: true
37128
+ }
37129
+ });
37130
+ return;
37131
+ }
37132
+ const imageFiles = dataTransferFiles.map((data2) => data2.file);
37133
+ if (imageFiles.length === 0 && data.text && !isPlainPaste) {
37134
+ const trimmedText = data.text.trim();
37135
+ if (trimmedText.startsWith("<svg") && trimmedText.endsWith("</svg>")) {
37136
+ imageFiles.push(SVGStringToFile(trimmedText));
37137
+ }
37138
+ }
37139
+ if (imageFiles.length > 0) {
37140
+ if (this.isToolSupported("image")) {
37141
+ await this.insertImages(imageFiles, sceneX, sceneY);
37142
+ } else {
37143
+ this.setState({ errorMessage: t("errors.imageToolNotSupported") });
37144
+ }
37145
+ return;
37146
+ }
37147
+ if (data.elements) {
37148
+ const elements = data.programmaticAPI ? convertToExcalidrawElements(
37149
+ data.elements
37150
+ ) : data.elements;
37151
+ this.addElementsFromPasteOrLibrary({
37152
+ elements,
37153
+ files: data.files || null,
37154
+ position: this.isMobileOrTablet() ? "center" : "cursor",
37155
+ retainSeed: isPlainPaste
37156
+ });
37157
+ return;
37158
+ }
37159
+ if (!data.text) {
37160
+ return;
37161
+ }
37162
+ if (!isPlainPaste && isMaybeMermaidDefinition(data.text)) {
37163
+ const api = await import("@excalidraw/mermaid-to-excalidraw");
37164
+ try {
37165
+ const { elements: skeletonElements, files } = await api.parseMermaidToExcalidraw(data.text);
37166
+ const elements = convertToExcalidrawElements(skeletonElements, {
37167
+ regenerateIds: true
37168
+ });
37169
+ this.addElementsFromPasteOrLibrary({
37170
+ elements,
37171
+ files,
37172
+ position: this.isMobileOrTablet() ? "center" : "cursor"
37173
+ });
37174
+ return;
37175
+ } catch (err) {
37176
+ console.warn(
37177
+ `parsing pasted text as mermaid definition failed: ${err.message}`
37178
+ );
37179
+ }
37180
+ }
37181
+ const nonEmptyLines = normalizeEOL2(data.text).split(/\n+/).map((s) => s.trim()).filter(Boolean);
37182
+ const embbeddableUrls = nonEmptyLines.map((str) => maybeParseEmbedSrc(str)).filter(
37183
+ (string) => embeddableURLValidator2(string, this.props.validateEmbeddable) && (/^(http|https):\/\/[^\s/$.?#].[^\s]*$/.test(string) || getEmbedLink2(string)?.type === "video")
37184
+ );
37185
+ if (!isPlainPaste && embbeddableUrls.length > 0 && embbeddableUrls.length === nonEmptyLines.length) {
37186
+ const embeddables = [];
37187
+ for (const url of embbeddableUrls) {
37188
+ const prevEmbeddable = embeddables[embeddables.length - 1];
37189
+ const embeddable = this.insertEmbeddableElement({
37190
+ sceneX: prevEmbeddable ? prevEmbeddable.x + prevEmbeddable.width + 20 : sceneX,
37191
+ sceneY,
37192
+ link: normalizeLink3(url)
37193
+ });
37194
+ if (embeddable) {
37195
+ embeddables.push(embeddable);
37196
+ }
37197
+ }
37198
+ if (embeddables.length) {
37199
+ this.store.scheduleCapture();
37200
+ this.setState({
37201
+ selectedElementIds: Object.fromEntries(
37202
+ embeddables.map((embeddable) => [embeddable.id, true])
37203
+ )
37204
+ });
37205
+ }
37206
+ return;
37207
+ }
37208
+ this.addTextFromPaste(data.text, isPlainPaste);
36965
37209
  }
36966
37210
  // TODO rewrite this to paste both text & images at the same time if
36967
37211
  // pasted data contains both
@@ -36987,37 +37231,8 @@ var App = class _App extends React43.Component {
36987
37231
  }
36988
37232
  })
36989
37233
  );
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
- });
37234
+ const imageFiles = responses.filter((response) => !!response.file).map((response) => response.file);
37235
+ await this.insertImages(imageFiles, sceneX, sceneY);
37021
37236
  const error = responses.find((response) => !!response.errorMessage);
37022
37237
  if (error && error.errorMessage) {
37023
37238
  this.setState({ errorMessage: error.errorMessage });
@@ -37134,7 +37349,7 @@ var App = class _App extends React43.Component {
37134
37349
  // Not sure why we include deleted elements as well hence using deleted elements map
37135
37350
  ...this.scene.getElementsIncludingDeleted().map((_element) => {
37136
37351
  if (_element.id === element.id && isTextElement19(_element)) {
37137
- return newElementWith10(_element, {
37352
+ return newElementWith11(_element, {
37138
37353
  originalText: nextOriginalText,
37139
37354
  isDeleted: isDeleted ?? _element.isDeleted,
37140
37355
  // returns (wrapped) text and new dimensions
@@ -37174,13 +37389,7 @@ var App = class _App extends React43.Component {
37174
37389
  }),
37175
37390
  onSubmit: withBatchedUpdates(({ viaKeyboard, nextOriginalText }) => {
37176
37391
  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
- }
37392
+ updateElement(nextOriginalText, isDeleted);
37184
37393
  if (!isDeleted && viaKeyboard) {
37185
37394
  const elementIdToSelect = element.containerId ? element.containerId : element.id;
37186
37395
  flushSync3(() => {
@@ -37200,7 +37409,9 @@ var App = class _App extends React43.Component {
37200
37409
  element
37201
37410
  ]);
37202
37411
  }
37203
- this.store.scheduleCapture();
37412
+ if (!isDeleted || isExistingElement) {
37413
+ this.store.scheduleCapture();
37414
+ }
37204
37415
  flushSync3(() => {
37205
37416
  this.setState({
37206
37417
  newElement: null,
@@ -37262,7 +37473,7 @@ var App = class _App extends React43.Component {
37262
37473
  }
37263
37474
  const elementWithHighestZIndex = allHitElements[allHitElements.length - 1];
37264
37475
  return hitElementItself({
37265
- point: pointFrom28(x, y),
37476
+ point: pointFrom29(x, y),
37266
37477
  element: elementWithHighestZIndex,
37267
37478
  // when overlapping, we would like to be more precise
37268
37479
  // this also avoids the need to update past tests
@@ -37306,7 +37517,7 @@ var App = class _App extends React43.Component {
37306
37517
  hitElement(x, y, element, considerBoundingBox = true) {
37307
37518
  if (considerBoundingBox && this.state.selectedElementIds[element.id] && shouldShowBoundingBox2([element], this.state)) {
37308
37519
  if (hitElementBoundingBox2(
37309
- pointFrom28(x, y),
37520
+ pointFrom29(x, y),
37310
37521
  element,
37311
37522
  this.scene.getNonDeletedElementsMap(),
37312
37523
  this.getElementHitThreshold(element)
@@ -37315,7 +37526,7 @@ var App = class _App extends React43.Component {
37315
37526
  }
37316
37527
  }
37317
37528
  const hitBoundTextOfElement = hitElementBoundText(
37318
- pointFrom28(x, y),
37529
+ pointFrom29(x, y),
37319
37530
  element,
37320
37531
  this.scene.getNonDeletedElementsMap()
37321
37532
  );
@@ -37323,7 +37534,7 @@ var App = class _App extends React43.Component {
37323
37534
  return true;
37324
37535
  }
37325
37536
  return hitElementItself({
37326
- point: pointFrom28(x, y),
37537
+ point: pointFrom29(x, y),
37327
37538
  element,
37328
37539
  threshold: this.getElementHitThreshold(element),
37329
37540
  elementsMap: this.scene.getNonDeletedElementsMap(),
@@ -37346,7 +37557,7 @@ var App = class _App extends React43.Component {
37346
37557
  this.scene.getNonDeletedElementsMap()
37347
37558
  );
37348
37559
  if (isArrowElement12(elements[index]) && hitElementItself({
37349
- point: pointFrom28(x, y),
37560
+ point: pointFrom29(x, y),
37350
37561
  element: elements[index],
37351
37562
  elementsMap: this.scene.getNonDeletedElementsMap(),
37352
37563
  threshold: this.getElementHitThreshold(elements[index])
@@ -37373,7 +37584,7 @@ var App = class _App extends React43.Component {
37373
37584
  let hoverPointIndex = -1;
37374
37585
  let segmentMidPointHoveredCoords = null;
37375
37586
  if (hitElementItself({
37376
- point: pointFrom28(scenePointerX, scenePointerY),
37587
+ point: pointFrom29(scenePointerX, scenePointerY),
37377
37588
  element,
37378
37589
  elementsMap,
37379
37590
  threshold: this.getElementHitThreshold(element)
@@ -37399,7 +37610,9 @@ var App = class _App extends React43.Component {
37399
37610
  // Ebow arrows can only be moved when unconnected
37400
37611
  !isElbowArrow11(element) || !(element.startBinding || element.endBinding)
37401
37612
  ) {
37402
- setCursor(this.interactiveCanvas, CURSOR_TYPE4.MOVE);
37613
+ if (this.state.activeTool.type !== "lasso" || Object.keys(this.state.selectedElementIds).length > 0) {
37614
+ setCursor(this.interactiveCanvas, CURSOR_TYPE4.MOVE);
37615
+ }
37403
37616
  }
37404
37617
  }
37405
37618
  } else if (this.hitElement(scenePointerX, scenePointerY, element)) {
@@ -37407,7 +37620,9 @@ var App = class _App extends React43.Component {
37407
37620
  // Ebow arrows can only be moved when unconnected
37408
37621
  !isElbowArrow11(element) || !(element.startBinding || element.endBinding)
37409
37622
  ) {
37410
- setCursor(this.interactiveCanvas, CURSOR_TYPE4.MOVE);
37623
+ if (this.state.activeTool.type !== "lasso" || Object.keys(this.state.selectedElementIds).length > 0) {
37624
+ setCursor(this.interactiveCanvas, CURSOR_TYPE4.MOVE);
37625
+ }
37411
37626
  }
37412
37627
  }
37413
37628
  if (this.state.selectedLinearElement.hoverPointIndex !== hoverPointIndex) {
@@ -37492,7 +37707,8 @@ var App = class _App extends React43.Component {
37492
37707
  drag: {
37493
37708
  hasOccurred: false,
37494
37709
  offset: null,
37495
- origin: { ...origin }
37710
+ origin: { ...origin },
37711
+ blockDragging: false
37496
37712
  },
37497
37713
  eventListeners: {
37498
37714
  onMove: null,
@@ -37528,13 +37744,13 @@ var App = class _App extends React43.Component {
37528
37744
  cursorButton: "up"
37529
37745
  });
37530
37746
  this.savePointer(event.clientX, event.clientY, "up");
37531
- window.removeEventListener(EVENT13.POINTER_MOVE, onPointerMove);
37532
- window.removeEventListener(EVENT13.POINTER_UP, onPointerUp);
37747
+ window.removeEventListener(EVENT14.POINTER_MOVE, onPointerMove);
37748
+ window.removeEventListener(EVENT14.POINTER_UP, onPointerUp);
37533
37749
  onPointerMove.flush();
37534
37750
  });
37535
37751
  lastPointerUp = onPointerUp;
37536
- window.addEventListener(EVENT13.POINTER_MOVE, onPointerMove);
37537
- window.addEventListener(EVENT13.POINTER_UP, onPointerUp);
37752
+ window.addEventListener(EVENT14.POINTER_MOVE, onPointerMove);
37753
+ window.addEventListener(EVENT14.POINTER_UP, onPointerUp);
37538
37754
  return true;
37539
37755
  }
37540
37756
  isASelectedElement(hitElement) {
@@ -37688,8 +37904,8 @@ var App = class _App extends React43.Component {
37688
37904
  );
37689
37905
  if (!pointerDownState.drag.hasOccurred && (this.state.activeTool.type === "arrow" || this.state.activeTool.type === "line")) {
37690
37906
  if (pointDistance8(
37691
- pointFrom28(pointerCoords.x, pointerCoords.y),
37692
- pointFrom28(pointerDownState.origin.x, pointerDownState.origin.y)
37907
+ pointFrom29(pointerCoords.x, pointerCoords.y),
37908
+ pointFrom29(pointerDownState.origin.x, pointerDownState.origin.y)
37693
37909
  ) * this.state.zoom.value < MINIMUM_ARROW_SIZE) {
37694
37910
  return;
37695
37911
  }
@@ -37758,9 +37974,9 @@ var App = class _App extends React43.Component {
37758
37974
  (element) => this.isASelectedElement(element)
37759
37975
  );
37760
37976
  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") {
37977
+ if ((hasHitASelectedElement || pointerDownState.hit.hasHitCommonBoundingBoxOfSelectedElements) && !isSelectingPointsInLineEditor && !pointerDownState.drag.blockDragging) {
37762
37978
  const selectedElements = this.scene.getSelectedElements(this.state);
37763
- if (selectedElements.every((element) => element.locked)) {
37979
+ if (selectedElements.length > 0 && selectedElements.every((element) => element.locked)) {
37764
37980
  return;
37765
37981
  }
37766
37982
  const selectedElementsHasAFrame = selectedElements.find(
@@ -37774,6 +37990,12 @@ var App = class _App extends React43.Component {
37774
37990
  });
37775
37991
  }
37776
37992
  pointerDownState.drag.hasOccurred = true;
37993
+ if (this.state.activeTool.type === "lasso" && this.lassoTrail.hasCurrentTrail && !(this.isMobileOrTablet() && pointerDownState.hit.element) && !this.state.activeTool.fromSelection) {
37994
+ return;
37995
+ }
37996
+ if (this.state.activeTool.type === "lasso" && selectedElements.length > 0 && pointerDownState.drag.hasOccurred && !this.state.activeTool.fromSelection) {
37997
+ this.lassoTrail.endPath();
37998
+ }
37777
37999
  if (selectedElements.length > 0 && !pointerDownState.withCmdOrCtrl && !this.state.editingTextElement && this.state.activeEmbeddable?.state !== "active") {
37778
38000
  const dragOffset = {
37779
38001
  x: pointerCoords.x - pointerDownState.drag.origin.x,
@@ -37813,23 +38035,23 @@ var App = class _App extends React43.Component {
37813
38035
  elementsMap
37814
38036
  );
37815
38037
  const topLeft = vectorFromPoint9(
37816
- pointRotateRads16(
37817
- pointFrom28(x1, y1),
37818
- pointFrom28(cx, cy),
38038
+ pointRotateRads17(
38039
+ pointFrom29(x1, y1),
38040
+ pointFrom29(cx, cy),
37819
38041
  croppingElement.angle
37820
38042
  )
37821
38043
  );
37822
38044
  const topRight = vectorFromPoint9(
37823
- pointRotateRads16(
37824
- pointFrom28(x2, y1),
37825
- pointFrom28(cx, cy),
38045
+ pointRotateRads17(
38046
+ pointFrom29(x2, y1),
38047
+ pointFrom29(cx, cy),
37826
38048
  croppingElement.angle
37827
38049
  )
37828
38050
  );
37829
38051
  const bottomLeft = vectorFromPoint9(
37830
- pointRotateRads16(
37831
- pointFrom28(x1, y2),
37832
- pointFrom28(cx, cy),
38052
+ pointRotateRads17(
38053
+ pointFrom29(x1, y2),
38054
+ pointFrom29(cx, cy),
37833
38055
  croppingElement.angle
37834
38056
  )
37835
38057
  );
@@ -37950,7 +38172,7 @@ var App = class _App extends React43.Component {
37950
38172
  if (idsOfElementsToDuplicate.has(el.id)) {
37951
38173
  const origEl = pointerDownState.originalElements.get(el.id);
37952
38174
  if (origEl) {
37953
- return newElementWith10(el, {
38175
+ return newElementWith11(el, {
37954
38176
  x: origEl.x,
37955
38177
  y: origEl.y
37956
38178
  });
@@ -38054,7 +38276,7 @@ var App = class _App extends React43.Component {
38054
38276
  this.scene.mutateElement(
38055
38277
  newElement6,
38056
38278
  {
38057
- points: [...points, pointFrom28(dx, dy)],
38279
+ points: [...points, pointFrom29(dx, dy)],
38058
38280
  pressures
38059
38281
  },
38060
38282
  {
@@ -38083,7 +38305,7 @@ var App = class _App extends React43.Component {
38083
38305
  this.scene.mutateElement(
38084
38306
  newElement6,
38085
38307
  {
38086
- points: [...points, pointFrom28(dx, dy)]
38308
+ points: [...points, pointFrom29(dx, dy)]
38087
38309
  },
38088
38310
  { informMutation: false, isDragging: false }
38089
38311
  );
@@ -38091,7 +38313,7 @@ var App = class _App extends React43.Component {
38091
38313
  this.scene.mutateElement(
38092
38314
  newElement6,
38093
38315
  {
38094
- points: [...points.slice(0, -1), pointFrom28(dx, dy)]
38316
+ points: [...points.slice(0, -1), pointFrom29(dx, dy)]
38095
38317
  },
38096
38318
  { isDragging: true, informMutation: false }
38097
38319
  );
@@ -38219,6 +38441,7 @@ var App = class _App extends React43.Component {
38219
38441
  onPointerUpFromPointerDownHandler(pointerDownState) {
38220
38442
  return withBatchedUpdates((childEvent) => {
38221
38443
  this.removePointer(childEvent);
38444
+ pointerDownState.drag.blockDragging = false;
38222
38445
  if (pointerDownState.eventListeners.onMove) {
38223
38446
  pointerDownState.eventListeners.onMove.flush();
38224
38447
  }
@@ -38333,19 +38556,19 @@ var App = class _App extends React43.Component {
38333
38556
  }
38334
38557
  this.missingPointerEventCleanupEmitter.clear();
38335
38558
  window.removeEventListener(
38336
- EVENT13.POINTER_MOVE,
38559
+ EVENT14.POINTER_MOVE,
38337
38560
  pointerDownState.eventListeners.onMove
38338
38561
  );
38339
38562
  window.removeEventListener(
38340
- EVENT13.POINTER_UP,
38563
+ EVENT14.POINTER_UP,
38341
38564
  pointerDownState.eventListeners.onUp
38342
38565
  );
38343
38566
  window.removeEventListener(
38344
- EVENT13.KEYDOWN,
38567
+ EVENT14.KEYDOWN,
38345
38568
  pointerDownState.eventListeners.onKeyDown
38346
38569
  );
38347
38570
  window.removeEventListener(
38348
- EVENT13.KEYUP,
38571
+ EVENT14.KEYUP,
38349
38572
  pointerDownState.eventListeners.onKeyUp
38350
38573
  );
38351
38574
  this.props?.onPointerUp?.(activeTool, pointerDownState);
@@ -38368,9 +38591,9 @@ var App = class _App extends React43.Component {
38368
38591
  }
38369
38592
  const pressures = newElement6.simulatePressure ? [] : [...newElement6.pressures, childEvent.pressure];
38370
38593
  this.scene.mutateElement(newElement6, {
38371
- points: [...points, pointFrom28(dx, dy)],
38594
+ points: [...points, pointFrom29(dx, dy)],
38372
38595
  pressures,
38373
- lastCommittedPoint: pointFrom28(dx, dy)
38596
+ lastCommittedPoint: pointFrom29(dx, dy)
38374
38597
  });
38375
38598
  this.actionManager.executeAction(actionFinalize);
38376
38599
  return;
@@ -38384,8 +38607,8 @@ var App = class _App extends React43.Component {
38384
38607
  this.state
38385
38608
  );
38386
38609
  const dragDistance = pointDistance8(
38387
- pointFrom28(pointerCoords.x, pointerCoords.y),
38388
- pointFrom28(pointerDownState.origin.x, pointerDownState.origin.y)
38610
+ pointFrom29(pointerCoords.x, pointerCoords.y),
38611
+ pointFrom29(pointerDownState.origin.x, pointerDownState.origin.y)
38389
38612
  ) * this.state.zoom.value;
38390
38613
  if ((!pointerDownState.drag.hasOccurred || dragDistance < MINIMUM_ARROW_SIZE) && newElement6 && !multiElement) {
38391
38614
  if (this.device.isTouchScreen) {
@@ -38398,8 +38621,8 @@ var App = class _App extends React43.Component {
38398
38621
  {
38399
38622
  x: newElement6.x - FIXED_DELTA_X / 2,
38400
38623
  points: [
38401
- pointFrom28(0, 0),
38402
- pointFrom28(FIXED_DELTA_X, 0)
38624
+ pointFrom29(0, 0),
38625
+ pointFrom29(FIXED_DELTA_X, 0)
38403
38626
  ]
38404
38627
  },
38405
38628
  { informMutation: false, isDragging: false }
@@ -38411,7 +38634,7 @@ var App = class _App extends React43.Component {
38411
38634
  this.scene.mutateElement(
38412
38635
  newElement6,
38413
38636
  {
38414
- points: [...newElement6.points, pointFrom28(dx, dy)]
38637
+ points: [...newElement6.points, pointFrom29(dx, dy)]
38415
38638
  },
38416
38639
  { informMutation: false, isDragging: false }
38417
38640
  );
@@ -38433,7 +38656,7 @@ var App = class _App extends React43.Component {
38433
38656
  this.setState((prevState) => ({
38434
38657
  newElement: null,
38435
38658
  activeTool: updateActiveTool7(this.state, {
38436
- type: "selection"
38659
+ type: this.defaultSelectionTool
38437
38660
  }),
38438
38661
  selectedElementIds: makeNextSelectedElementIds2(
38439
38662
  {
@@ -38660,8 +38883,8 @@ var App = class _App extends React43.Component {
38660
38883
  if (isEraserActive(this.state) && pointerStart && pointerEnd) {
38661
38884
  this.eraserTrail.endPath();
38662
38885
  const draggedDistance = pointDistance8(
38663
- pointFrom28(pointerStart.clientX, pointerStart.clientY),
38664
- pointFrom28(pointerEnd.clientX, pointerEnd.clientY)
38886
+ pointFrom29(pointerStart.clientX, pointerStart.clientY),
38887
+ pointFrom29(pointerEnd.clientX, pointerEnd.clientY)
38665
38888
  );
38666
38889
  if (draggedDistance === 0) {
38667
38890
  const scenePointer = viewportCoordsToSceneCoords4(
@@ -38807,7 +39030,7 @@ var App = class _App extends React43.Component {
38807
39030
  !this.state.isResizing && // only hitting the bounding box of the previous hit element
38808
39031
  (hitElement && hitElementBoundingBoxOnly(
38809
39032
  {
38810
- point: pointFrom28(
39033
+ point: pointFrom29(
38811
39034
  pointerDownState.origin.x,
38812
39035
  pointerDownState.origin.y
38813
39036
  ),
@@ -38870,7 +39093,9 @@ var App = class _App extends React43.Component {
38870
39093
  this.setState({
38871
39094
  newElement: null,
38872
39095
  suggestedBindings: [],
38873
- activeTool: updateActiveTool7(this.state, { type: "selection" })
39096
+ activeTool: updateActiveTool7(this.state, {
39097
+ type: this.defaultSelectionTool
39098
+ })
38874
39099
  });
38875
39100
  } else {
38876
39101
  this.setState({
@@ -39393,7 +39618,7 @@ import { isLinearElement as isLinearElement14 } from "@excalidraw/element";
39393
39618
  import {
39394
39619
  FONT_FAMILY as FONT_FAMILY5,
39395
39620
  THEME as THEME16,
39396
- MIME_TYPES as MIME_TYPES9,
39621
+ MIME_TYPES as MIME_TYPES10,
39397
39622
  ROUNDNESS as ROUNDNESS3,
39398
39623
  DEFAULT_LASER_COLOR as DEFAULT_LASER_COLOR2,
39399
39624
  UserIdleState as UserIdleState2,
@@ -39401,7 +39626,7 @@ import {
39401
39626
  } from "@excalidraw/common";
39402
39627
  import {
39403
39628
  mutateElement as mutateElement2,
39404
- newElementWith as newElementWith11,
39629
+ newElementWith as newElementWith12,
39405
39630
  bumpVersion
39406
39631
  } from "@excalidraw/element";
39407
39632
  import { CaptureUpdateAction as CaptureUpdateAction38 } from "@excalidraw/element";
@@ -39613,7 +39838,7 @@ export {
39613
39838
  FONT_FAMILY5 as FONT_FAMILY,
39614
39839
  FooterCenter_default as Footer,
39615
39840
  LiveCollaborationTrigger_default as LiveCollaborationTrigger,
39616
- MIME_TYPES9 as MIME_TYPES,
39841
+ MIME_TYPES10 as MIME_TYPES,
39617
39842
  MainMenu_default as MainMenu,
39618
39843
  ROUNDNESS3 as ROUNDNESS,
39619
39844
  Sidebar,
@@ -39652,12 +39877,13 @@ export {
39652
39877
  loadSceneOrLibraryFromBlob,
39653
39878
  mergeLibraryItems,
39654
39879
  mutateElement2 as mutateElement,
39655
- newElementWith11 as newElementWith,
39880
+ newElementWith12 as newElementWith,
39656
39881
  normalizeLink4 as normalizeLink,
39657
39882
  parseLibraryTokensFromUrl,
39658
39883
  reconcileElements,
39659
39884
  restore,
39660
39885
  restoreAppState,
39886
+ restoreElement,
39661
39887
  restoreElements,
39662
39888
  restoreLibraryItems,
39663
39889
  sceneCoordsToViewportCoords2 as sceneCoordsToViewportCoords,