@excalidraw/excalidraw 0.18.0-200a6bd94 → 0.18.0-3085f4a

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.
package/dist/dev/index.js CHANGED
@@ -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,7 +69,7 @@ import {
68
69
  serializeLibraryAsJSON,
69
70
  strokeEllipseWithRotation,
70
71
  strokeRectWithRotation
71
- } from "./chunk-VISTIWDQ.js";
72
+ } from "./chunk-5EDE7GFX.js";
72
73
  import {
73
74
  define_import_meta_env_default
74
75
  } from "./chunk-CP5DND7P.js";
@@ -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,8 @@ import {
318
321
  CaptureUpdateAction as CaptureUpdateAction37,
319
322
  hitElementBoundingBox as hitElementBoundingBox2,
320
323
  isLineElement as isLineElement7,
321
- isSimpleArrow
324
+ isSimpleArrow,
325
+ StoreDelta as StoreDelta2
322
326
  } from "@excalidraw/element";
323
327
 
324
328
  // actions/actionDeleteSelected.tsx
@@ -3119,7 +3123,9 @@ var actionDeleteSelected = register({
3119
3123
  elements: nextElements,
3120
3124
  appState: {
3121
3125
  ...nextAppState,
3122
- activeTool: updateActiveTool(appState, { type: "selection" }),
3126
+ activeTool: updateActiveTool(appState, {
3127
+ type: app.defaultSelectionTool
3128
+ }),
3123
3129
  multiElement: null,
3124
3130
  activeEmbeddable: null,
3125
3131
  selectedLinearElement: null
@@ -7375,7 +7381,7 @@ var actionClearCanvas = register({
7375
7381
  gridModeEnabled: appState.gridModeEnabled,
7376
7382
  stats: appState.stats,
7377
7383
  pasteDialog: appState.pasteDialog,
7378
- activeTool: appState.activeTool.type === "image" ? { ...appState.activeTool, type: "selection" } : appState.activeTool
7384
+ activeTool: appState.activeTool.type === "image" ? { ...appState.activeTool, type: app.defaultSelectionTool } : appState.activeTool
7379
7385
  },
7380
7386
  captureUpdate: CaptureUpdateAction6.IMMEDIATELY
7381
7387
  };
@@ -7674,12 +7680,12 @@ var actionToggleEraserTool = register({
7674
7680
  name: "toggleEraserTool",
7675
7681
  label: "toolBar.eraser",
7676
7682
  trackEvent: { category: "toolbar" },
7677
- perform: (elements, appState) => {
7683
+ perform: (elements, appState, _, app) => {
7678
7684
  let activeTool;
7679
7685
  if (isEraserActive(appState)) {
7680
7686
  activeTool = updateActiveTool2(appState, {
7681
7687
  ...appState.activeTool.lastActiveTool || {
7682
- type: "selection"
7688
+ type: app.defaultSelectionTool
7683
7689
  },
7684
7690
  lastActiveToolBeforeEraser: null
7685
7691
  });
@@ -7707,6 +7713,9 @@ var actionToggleLassoTool = register({
7707
7713
  label: "toolBar.lasso",
7708
7714
  icon: LassoIcon,
7709
7715
  trackEvent: { category: "toolbar" },
7716
+ predicate: (elements, appState, props, app) => {
7717
+ return app.defaultSelectionTool !== "lasso";
7718
+ },
7710
7719
  perform: (elements, appState, _, app) => {
7711
7720
  let activeTool;
7712
7721
  if (appState.activeTool.type !== "lasso") {
@@ -7804,7 +7813,11 @@ import {
7804
7813
  bindOrUnbindLinearElement,
7805
7814
  isBindingEnabled
7806
7815
  } from "@excalidraw/element/binding";
7807
- import { isValidPolygon, LinearElementEditor as LinearElementEditor5 } from "@excalidraw/element";
7816
+ import {
7817
+ isValidPolygon,
7818
+ LinearElementEditor as LinearElementEditor5,
7819
+ newElementWith as newElementWith4
7820
+ } from "@excalidraw/element";
7808
7821
  import {
7809
7822
  isBindingElement,
7810
7823
  isFreeDrawElement,
@@ -7849,7 +7862,14 @@ var actionFinalize = register({
7849
7862
  if (linearElementEditor !== appState.selectedLinearElement) {
7850
7863
  let newElements2 = elements;
7851
7864
  if (element2 && isInvisiblySmallElement(element2)) {
7852
- newElements2 = newElements2.filter((el) => el.id !== element2.id);
7865
+ newElements2 = newElements2.map((el) => {
7866
+ if (el.id === element2.id) {
7867
+ return newElementWith4(el, {
7868
+ isDeleted: true
7869
+ });
7870
+ }
7871
+ return el;
7872
+ });
7853
7873
  }
7854
7874
  return {
7855
7875
  elements: newElements2,
@@ -7882,7 +7902,12 @@ var actionFinalize = register({
7882
7902
  });
7883
7903
  }
7884
7904
  return {
7885
- elements: element2.points.length < 2 || isInvisiblySmallElement(element2) ? elements.filter((el) => el.id !== element2.id) : void 0,
7905
+ elements: element2.points.length < 2 || isInvisiblySmallElement(element2) ? elements.map((el) => {
7906
+ if (el.id === element2.id) {
7907
+ return newElementWith4(el, { isDeleted: true });
7908
+ }
7909
+ return el;
7910
+ }) : void 0,
7886
7911
  appState: {
7887
7912
  ...appState,
7888
7913
  cursorButton: "up",
@@ -7924,7 +7949,12 @@ var actionFinalize = register({
7924
7949
  }
7925
7950
  }
7926
7951
  if (element && isInvisiblySmallElement(element)) {
7927
- newElements = newElements.filter((el) => el.id !== element.id);
7952
+ newElements = newElements.map((el) => {
7953
+ if (el.id === element?.id) {
7954
+ return newElementWith4(el, { isDeleted: true });
7955
+ }
7956
+ return el;
7957
+ });
7928
7958
  }
7929
7959
  if (isLinearElement3(element) || isFreeDrawElement(element)) {
7930
7960
  const isLoop = isPathALoop(element.points, appState.zoom.value);
@@ -7969,13 +7999,13 @@ var actionFinalize = register({
7969
7999
  if (appState.activeTool.type === "eraser") {
7970
8000
  activeTool = updateActiveTool4(appState, {
7971
8001
  ...appState.activeTool.lastActiveTool || {
7972
- type: "selection"
8002
+ type: app.defaultSelectionTool
7973
8003
  },
7974
8004
  lastActiveToolBeforeEraser: null
7975
8005
  });
7976
8006
  } else {
7977
8007
  activeTool = updateActiveTool4(appState, {
7978
- type: "selection"
8008
+ type: app.defaultSelectionTool
7979
8009
  });
7980
8010
  }
7981
8011
  return {
@@ -8936,7 +8966,7 @@ var exportCanvas = async (type, elements, appState, files, {
8936
8966
  let blob = canvasToBlob(tempCanvas);
8937
8967
  if (appState.exportEmbedScene) {
8938
8968
  blob = blob.then(
8939
- (blob2) => import("./data/image-XM2PNARE.js").then(
8969
+ (blob2) => import("./data/image-7AP4KED2.js").then(
8940
8970
  ({ encodePngMetadata: encodePngMetadata2 }) => encodePngMetadata2({
8941
8971
  blob: blob2,
8942
8972
  metadata: serializeAsJSON(elements, appState, files, "local")
@@ -9277,7 +9307,7 @@ import {
9277
9307
  KEYS as KEYS16,
9278
9308
  getLineHeight as getLineHeight2
9279
9309
  } from "@excalidraw/common";
9280
- import { newElementWith as newElementWith4 } from "@excalidraw/element";
9310
+ import { newElementWith as newElementWith5 } from "@excalidraw/element";
9281
9311
  import {
9282
9312
  hasBoundTextElement,
9283
9313
  canApplyRoundnessTypeToElement,
@@ -9348,7 +9378,7 @@ var actionPasteStyles = register({
9348
9378
  if (!elementStylesToCopyFrom) {
9349
9379
  return element;
9350
9380
  }
9351
- let newElement6 = newElementWith4(element, {
9381
+ let newElement6 = newElementWith5(element, {
9352
9382
  backgroundColor: elementStylesToCopyFrom?.backgroundColor,
9353
9383
  strokeWidth: elementStylesToCopyFrom?.strokeWidth,
9354
9384
  strokeColor: elementStylesToCopyFrom?.strokeColor,
@@ -9364,7 +9394,7 @@ var actionPasteStyles = register({
9364
9394
  if (isTextElement3(newElement6)) {
9365
9395
  const fontSize = elementStylesToCopyFrom.fontSize || DEFAULT_FONT_SIZE3;
9366
9396
  const fontFamily = elementStylesToCopyFrom.fontFamily || DEFAULT_FONT_FAMILY3;
9367
- newElement6 = newElementWith4(newElement6, {
9397
+ newElement6 = newElementWith5(newElement6, {
9368
9398
  fontSize,
9369
9399
  fontFamily,
9370
9400
  textAlign: elementStylesToCopyFrom.textAlign || DEFAULT_TEXT_ALIGN,
@@ -9379,13 +9409,13 @@ var actionPasteStyles = register({
9379
9409
  redrawTextBoundingBox2(newElement6, container, app.scene);
9380
9410
  }
9381
9411
  if (newElement6.type === "arrow" && isArrowElement2(elementStylesToCopyFrom)) {
9382
- newElement6 = newElementWith4(newElement6, {
9412
+ newElement6 = newElementWith5(newElement6, {
9383
9413
  startArrowhead: elementStylesToCopyFrom.startArrowhead,
9384
9414
  endArrowhead: elementStylesToCopyFrom.endArrowhead
9385
9415
  });
9386
9416
  }
9387
9417
  if (isFrameLikeElement4(element)) {
9388
- newElement6 = newElementWith4(newElement6, {
9418
+ newElement6 = newElementWith5(newElement6, {
9389
9419
  roundness: null,
9390
9420
  backgroundColor: "transparent"
9391
9421
  });
@@ -9479,7 +9509,7 @@ var actionShortcuts = register({
9479
9509
 
9480
9510
  // actions/actionGroup.tsx
9481
9511
  import { getNonDeletedElements as getNonDeletedElements9 } from "@excalidraw/element";
9482
- import { newElementWith as newElementWith5 } from "@excalidraw/element";
9512
+ import { newElementWith as newElementWith6 } from "@excalidraw/element";
9483
9513
  import { isBoundToContainer as isBoundToContainer3 } from "@excalidraw/element";
9484
9514
  import {
9485
9515
  frameAndChildrenSelectedTogether,
@@ -9583,7 +9613,7 @@ var actionGroup = register({
9583
9613
  if (!selectElementIds.get(element.id)) {
9584
9614
  return element;
9585
9615
  }
9586
- return newElementWith5(element, {
9616
+ return newElementWith6(element, {
9587
9617
  groupIds: addToGroup(
9588
9618
  element.groupIds,
9589
9619
  newGroupId,
@@ -9660,7 +9690,7 @@ var actionUngroup = register({
9660
9690
  if (nextGroupIds.length === element.groupIds.length) {
9661
9691
  return element;
9662
9692
  }
9663
- return newElementWith5(element, {
9693
+ return newElementWith6(element, {
9664
9694
  groupIds: nextGroupIds
9665
9695
  });
9666
9696
  });
@@ -10459,7 +10489,7 @@ import {
10459
10489
  isBindingEnabled as isBindingEnabled2
10460
10490
  } from "@excalidraw/element";
10461
10491
  import { getCommonBoundingBox } from "@excalidraw/element";
10462
- import { newElementWith as newElementWith6 } from "@excalidraw/element";
10492
+ import { newElementWith as newElementWith7 } from "@excalidraw/element";
10463
10493
  import { deepCopyElement as deepCopyElement3 } from "@excalidraw/element";
10464
10494
  import { resizeMultipleElements } from "@excalidraw/element";
10465
10495
  import {
@@ -10545,7 +10575,7 @@ var flipElements = (selectedElements, elementsMap, appState, flipDirection, app)
10545
10575
  )) {
10546
10576
  return selectedElements.map((element) => {
10547
10577
  const _element = element;
10548
- return newElementWith6(_element, {
10578
+ return newElementWith7(_element, {
10549
10579
  startArrowhead: _element.endArrowhead,
10550
10580
  endArrowhead: _element.startArrowhead
10551
10581
  });
@@ -11616,7 +11646,7 @@ var actionLink = register({
11616
11646
  import { KEYS as KEYS29, arrayToMap as arrayToMap11, randomId as randomId4 } from "@excalidraw/common";
11617
11647
  import {
11618
11648
  elementsAreInSameGroup,
11619
- newElementWith as newElementWith7,
11649
+ newElementWith as newElementWith8,
11620
11650
  selectGroupsFromGivenElements
11621
11651
  } from "@excalidraw/element";
11622
11652
  import { CaptureUpdateAction as CaptureUpdateAction25 } from "@excalidraw/element";
@@ -11677,7 +11707,7 @@ var actionToggleElementLock = register({
11677
11707
  (groupId) => !appState.lockedMultiSelections[groupId]
11678
11708
  );
11679
11709
  }
11680
- return newElementWith7(element, {
11710
+ return newElementWith8(element, {
11681
11711
  locked: nextLockState,
11682
11712
  // do not recreate the array unncessarily
11683
11713
  groupIds: nextGroupIds.length !== element.groupIds.length ? nextGroupIds : element.groupIds
@@ -11726,7 +11756,7 @@ var actionUnlockAllElements = register({
11726
11756
  const nextGroupIds = element.groupIds.filter(
11727
11757
  (gid) => !appState.lockedMultiSelections[gid]
11728
11758
  );
11729
- return newElementWith7(element, {
11759
+ return newElementWith8(element, {
11730
11760
  locked: false,
11731
11761
  groupIds: (
11732
11762
  // do not recreate the array unncessarily
@@ -12842,7 +12872,8 @@ var exportToCanvas2 = ({
12842
12872
  const { elements: restoredElements, appState: restoredAppState } = restore(
12843
12873
  { elements, appState },
12844
12874
  null,
12845
- null
12875
+ null,
12876
+ { deleteInvisibleElements: true }
12846
12877
  );
12847
12878
  const { exportBackground, viewBackgroundColor } = restoredAppState;
12848
12879
  return exportToCanvas(
@@ -12936,7 +12967,8 @@ var exportToSvg2 = async ({
12936
12967
  const { elements: restoredElements, appState: restoredAppState } = restore(
12937
12968
  { elements, appState },
12938
12969
  null,
12939
- null
12970
+ null,
12971
+ { deleteInvisibleElements: true }
12940
12972
  );
12941
12973
  const exportAppState = {
12942
12974
  ...restoredAppState,
@@ -14893,7 +14925,7 @@ var LibraryUnit = memo(
14893
14925
  };
14894
14926
  }, [svg]);
14895
14927
  const [isHovered, setIsHovered] = useState15(false);
14896
- const isMobile = useDevice().editor.isMobile;
14928
+ const isMobile2 = useDevice().editor.isMobile;
14897
14929
  const adder = isPending && /* @__PURE__ */ jsx63("div", { className: "library-unit__adder", children: PlusIcon });
14898
14930
  return /* @__PURE__ */ jsxs33(
14899
14931
  "div",
@@ -14933,7 +14965,7 @@ var LibraryUnit = memo(
14933
14965
  }
14934
14966
  ),
14935
14967
  adder,
14936
- id && elements && (isHovered || isMobile || selected) && /* @__PURE__ */ jsx63(
14968
+ id && elements && (isHovered || isMobile2 || selected) && /* @__PURE__ */ jsx63(
14937
14969
  CheckboxItem,
14938
14970
  {
14939
14971
  checked: selected,
@@ -15766,8 +15798,20 @@ var SHAPES = [
15766
15798
  fillable: false
15767
15799
  }
15768
15800
  ];
15769
- var findShapeByKey = (key) => {
15770
- const shape = SHAPES.find((shape2, index) => {
15801
+ var getToolbarTools = (app) => {
15802
+ return app.defaultSelectionTool === "lasso" ? [
15803
+ {
15804
+ value: "lasso",
15805
+ icon: SelectionIcon,
15806
+ key: KEYS33.V,
15807
+ numericKey: KEYS33["1"],
15808
+ fillable: true
15809
+ },
15810
+ ...SHAPES.slice(1)
15811
+ ] : SHAPES;
15812
+ };
15813
+ var findShapeByKey = (key, app) => {
15814
+ const shape = getToolbarTools(app).find((shape2, index) => {
15771
15815
  return shape2.numericKey != null && key === shape2.numericKey.toString() || shape2.key && (typeof shape2.key === "string" ? shape2.key === key : shape2.key.includes(key));
15772
15816
  });
15773
15817
  return shape?.value || null;
@@ -15943,58 +15987,60 @@ var ShapesSwitcher = ({
15943
15987
  const [isExtraToolsMenuOpen, setIsExtraToolsMenuOpen] = useState21(false);
15944
15988
  const frameToolSelected = activeTool.type === "frame";
15945
15989
  const laserToolSelected = activeTool.type === "laser";
15946
- const lassoToolSelected = activeTool.type === "lasso";
15990
+ const lassoToolSelected = activeTool.type === "lasso" && app.defaultSelectionTool !== "lasso";
15947
15991
  const embeddableToolSelected = activeTool.type === "embeddable";
15948
15992
  const { TTDDialogTriggerTunnel } = useTunnels();
15949
15993
  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" });
15994
+ getToolbarTools(app).map(
15995
+ ({ value, icon, key, numericKey, fillable }, index) => {
15996
+ if (UIOptions.tools?.[value] === false) {
15997
+ return null;
15998
+ }
15999
+ const label = t(`toolBar.${value}`);
16000
+ const letter = key && capitalizeString(typeof key === "string" ? key : key[0]);
16001
+ const shortcut = letter ? `${letter} ${t("helpDialog.or")} ${numericKey}` : `${numericKey}`;
16002
+ return /* @__PURE__ */ jsx71(
16003
+ ToolButton,
16004
+ {
16005
+ className: clsx31("Shape", { fillable }),
16006
+ type: "radio",
16007
+ icon,
16008
+ checked: activeTool.type === value,
16009
+ name: "editor-current-shape",
16010
+ title: `${capitalizeString(label)} \u2014 ${shortcut}`,
16011
+ keyBindingLabel: numericKey || letter,
16012
+ "aria-label": capitalizeString(label),
16013
+ "aria-keyshortcuts": shortcut,
16014
+ "data-testid": `toolbar-${value}`,
16015
+ onPointerDown: ({ pointerType }) => {
16016
+ if (!appState.penDetected && pointerType === "pen") {
16017
+ app.togglePenMode(true);
16018
+ }
16019
+ if (value === "selection") {
16020
+ if (appState.activeTool.type === "selection") {
16021
+ app.setActiveTool({ type: "lasso" });
16022
+ } else {
16023
+ app.setActiveTool({ type: "selection" });
16024
+ }
16025
+ }
16026
+ },
16027
+ onChange: ({ pointerType }) => {
16028
+ if (appState.activeTool.type !== value) {
16029
+ trackEvent("toolbar", value, "ui");
16030
+ }
16031
+ if (value === "image") {
16032
+ app.setActiveTool({
16033
+ type: value
16034
+ });
15977
16035
  } else {
15978
- app.setActiveTool({ type: "selection" });
16036
+ app.setActiveTool({ type: value });
15979
16037
  }
15980
16038
  }
15981
16039
  },
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
- }),
16040
+ value
16041
+ );
16042
+ }
16043
+ ),
15998
16044
  /* @__PURE__ */ jsx71("div", { className: "App-toolbar__divider" }),
15999
16045
  /* @__PURE__ */ jsxs39(DropdownMenu_default, { open: isExtraToolsMenuOpen, children: [
16000
16046
  /* @__PURE__ */ jsx71(
@@ -16050,7 +16096,7 @@ var ShapesSwitcher = ({
16050
16096
  children: t("toolBar.laser")
16051
16097
  }
16052
16098
  ),
16053
- /* @__PURE__ */ jsx71(
16099
+ app.defaultSelectionTool !== "lasso" && /* @__PURE__ */ jsx71(
16054
16100
  DropdownMenu_default.Item,
16055
16101
  {
16056
16102
  onSelect: () => app.setActiveTool({ type: "lasso" }),
@@ -18225,7 +18271,7 @@ var generateElbowArrowShape = (points, radius) => {
18225
18271
  };
18226
18272
 
18227
18273
  // ../element/src/mutateElement.ts
18228
- var newElementWith8 = (element, updates, force = false) => {
18274
+ var newElementWith9 = (element, updates, force = false) => {
18229
18275
  let didChange = false;
18230
18276
  for (const key in updates) {
18231
18277
  const value = updates[key];
@@ -18354,7 +18400,7 @@ var actionTogglePolygon = register({
18354
18400
  if (!targetElementsMap.has(element.id) || !isLineElement4(element)) {
18355
18401
  return element;
18356
18402
  }
18357
- return newElementWith8(element, {
18403
+ return newElementWith9(element, {
18358
18404
  backgroundColor: nextPolygonState ? element.backgroundColor : "transparent",
18359
18405
  ...toggleLinePolygonState3(element, nextPolygonState)
18360
18406
  });
@@ -18946,7 +18992,7 @@ var createRedoAction = (history) => ({
18946
18992
 
18947
18993
  // actions/actionTextAutoResize.ts
18948
18994
  import { getFontString as getFontString6 } from "@excalidraw/common";
18949
- import { newElementWith as newElementWith9 } from "@excalidraw/element";
18995
+ import { newElementWith as newElementWith10 } from "@excalidraw/element";
18950
18996
  import { measureText as measureText4 } from "@excalidraw/element";
18951
18997
  import { isTextElement as isTextElement9 } from "@excalidraw/element";
18952
18998
  import { CaptureUpdateAction as CaptureUpdateAction34 } from "@excalidraw/element";
@@ -18970,7 +19016,7 @@ var actionTextAutoResize = register({
18970
19016
  getFontString6(element),
18971
19017
  element.lineHeight
18972
19018
  );
18973
- return newElementWith9(element, {
19019
+ return newElementWith10(element, {
18974
19020
  autoResize: true,
18975
19021
  width: metrics.width,
18976
19022
  height: metrics.height,
@@ -19260,7 +19306,8 @@ var isSnappingEnabled = ({
19260
19306
  selectedElements
19261
19307
  }) => {
19262
19308
  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));
19309
+ const isLassoDragging = app.state.activeTool.type === "lasso" && app.state.selectedElementsAreBeingDragged;
19310
+ 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
19311
  }
19265
19312
  if (selectedElements.length === 1 && selectedElements[0].type === "arrow") {
19266
19313
  return false;
@@ -23543,7 +23590,7 @@ import { isNodeInFlowchart } from "@excalidraw/element";
23543
23590
  import { jsx as jsx87 } from "react/jsx-runtime";
23544
23591
  var getHints = ({
23545
23592
  appState,
23546
- isMobile,
23593
+ isMobile: isMobile2,
23547
23594
  device,
23548
23595
  app
23549
23596
  }) => {
@@ -23606,7 +23653,7 @@ var getHints = ({
23606
23653
  if (isGridModeEnabled(app) && appState.selectedElementsAreBeingDragged) {
23607
23654
  return t("hints.disableSnapping");
23608
23655
  }
23609
- if (!selectedElements.length && !isMobile) {
23656
+ if (!selectedElements.length && !isMobile2) {
23610
23657
  return [t("hints.canvasPanning")];
23611
23658
  }
23612
23659
  if (selectedElements.length === 1) {
@@ -23634,13 +23681,13 @@ var getHints = ({
23634
23681
  };
23635
23682
  var HintViewer = ({
23636
23683
  appState,
23637
- isMobile,
23684
+ isMobile: isMobile2,
23638
23685
  device,
23639
23686
  app
23640
23687
  }) => {
23641
23688
  const hints = getHints({
23642
23689
  appState,
23643
- isMobile,
23690
+ isMobile: isMobile2,
23644
23691
  device,
23645
23692
  app
23646
23693
  });
@@ -31183,6 +31230,7 @@ var useExcalidrawSetAppState = () => useContext3(ExcalidrawSetAppStateContext);
31183
31230
  var useExcalidrawActionManager = () => useContext3(ExcalidrawActionManagerContext);
31184
31231
  var didTapTwice = false;
31185
31232
  var tappedTwiceTimer = 0;
31233
+ var firstTapPosition = null;
31186
31234
  var isHoldingSpace = false;
31187
31235
  var isPanning = false;
31188
31236
  var isDraggingScrollBar = false;
@@ -31258,6 +31306,7 @@ var App = class _App extends React43.Component {
31258
31306
  __publicField(this, "onScrollChangeEmitter", new Emitter3());
31259
31307
  __publicField(this, "missingPointerEventCleanupEmitter", new Emitter3());
31260
31308
  __publicField(this, "onRemoveEventListenersEmitter", new Emitter3());
31309
+ __publicField(this, "defaultSelectionTool", "selection");
31261
31310
  __publicField(this, "updateEditorAtom", (atom2, ...args) => {
31262
31311
  const result = editorJotaiStore.set(atom2, ...args);
31263
31312
  this.triggerRender();
@@ -31600,7 +31649,7 @@ var App = class _App extends React43.Component {
31600
31649
  this.updateScene({
31601
31650
  elements: this.scene.getElementsIncludingDeleted().map((el) => {
31602
31651
  if (this.state.selectedElementIds[el.id]) {
31603
- return newElementWith10(el, {
31652
+ return newElementWith11(el, {
31604
31653
  [shouldUpdateStrokeColor ? "strokeColor" : "backgroundColor"]: color
31605
31654
  });
31606
31655
  }
@@ -31764,7 +31813,11 @@ var App = class _App extends React43.Component {
31764
31813
  }
31765
31814
  };
31766
31815
  }
31767
- const scene = restore(initialData, null, null, { repairBindings: true });
31816
+ const scene = restore(initialData, null, null, {
31817
+ repairBindings: true,
31818
+ deleteInvisibleElements: true
31819
+ });
31820
+ const activeTool = scene.appState.activeTool;
31768
31821
  scene.appState = {
31769
31822
  ...scene.appState,
31770
31823
  theme: this.props.theme || scene.appState.theme,
@@ -31773,7 +31826,10 @@ var App = class _App extends React43.Component {
31773
31826
  // update the state outside of initialData (e.g. when loading the app
31774
31827
  // with a library install link, which should auto-open the library)
31775
31828
  openSidebar: scene.appState?.openSidebar || this.state.openSidebar,
31776
- activeTool: scene.appState.activeTool.type === "image" ? { ...scene.appState.activeTool, type: "selection" } : scene.appState.activeTool,
31829
+ activeTool: activeTool.type === "image" || activeTool.type === "lasso" || activeTool.type === "selection" ? {
31830
+ ...activeTool,
31831
+ type: this.defaultSelectionTool
31832
+ } : scene.appState.activeTool,
31777
31833
  isLoading: false,
31778
31834
  toast: this.state.toast
31779
31835
  };
@@ -31803,6 +31859,12 @@ var App = class _App extends React43.Component {
31803
31859
  this.scrollToContent(window.location.href, { animate: false });
31804
31860
  }
31805
31861
  });
31862
+ __publicField(this, "isMobileOrTablet", () => {
31863
+ const hasTouch = "ontouchstart" in window || navigator.maxTouchPoints > 0;
31864
+ const hasCoarsePointer = "matchMedia" in window && window?.matchMedia("(pointer: coarse)")?.matches;
31865
+ const isTouchMobile = hasTouch && hasCoarsePointer;
31866
+ return isMobile || isTouchMobile;
31867
+ });
31806
31868
  __publicField(this, "isMobileBreakpoint", (width, height) => {
31807
31869
  return width < MQ_MAX_WIDTH_PORTRAIT || height < MQ_MAX_HEIGHT_LANDSCAPE && width < MQ_MAX_WIDTH_LANDSCAPE;
31808
31870
  });
@@ -31916,6 +31978,12 @@ var App = class _App extends React43.Component {
31916
31978
  }
31917
31979
  if (!didTapTwice) {
31918
31980
  didTapTwice = true;
31981
+ if (event.touches.length === 1) {
31982
+ firstTapPosition = {
31983
+ x: event.touches[0].clientX,
31984
+ y: event.touches[0].clientY
31985
+ };
31986
+ }
31919
31987
  clearTimeout(tappedTwiceTimer);
31920
31988
  tappedTwiceTimer = window.setTimeout(
31921
31989
  _App.resetTapTwice,
@@ -31923,12 +31991,20 @@ var App = class _App extends React43.Component {
31923
31991
  );
31924
31992
  return;
31925
31993
  }
31926
- if (didTapTwice && event.touches.length === 1) {
31994
+ if (didTapTwice && event.touches.length === 1 && firstTapPosition) {
31927
31995
  const touch = event.touches[0];
31928
- this.handleCanvasDoubleClick({
31929
- clientX: touch.clientX,
31930
- clientY: touch.clientY
31931
- });
31996
+ const distance3 = pointDistance8(
31997
+ pointFrom28(touch.clientX, touch.clientY),
31998
+ pointFrom28(firstTapPosition.x, firstTapPosition.y)
31999
+ );
32000
+ if (distance3 <= DOUBLE_TAP_POSITION_THRESHOLD) {
32001
+ this.lassoTrail.endPath();
32002
+ this.deselectElements();
32003
+ this.handleCanvasDoubleClick({
32004
+ clientX: touch.clientX,
32005
+ clientY: touch.clientY
32006
+ });
32007
+ }
31932
32008
  didTapTwice = false;
31933
32009
  clearTimeout(tappedTwiceTimer);
31934
32010
  }
@@ -32025,7 +32101,7 @@ var App = class _App extends React43.Component {
32025
32101
  this.addElementsFromPasteOrLibrary({
32026
32102
  elements,
32027
32103
  files: data.files || null,
32028
- position: "cursor",
32104
+ position: this.isMobileOrTablet() ? "center" : "cursor",
32029
32105
  retainSeed: isPlainPaste
32030
32106
  });
32031
32107
  } else if (data.text) {
@@ -32039,7 +32115,7 @@ var App = class _App extends React43.Component {
32039
32115
  this.addElementsFromPasteOrLibrary({
32040
32116
  elements,
32041
32117
  files,
32042
- position: "cursor"
32118
+ position: this.isMobileOrTablet() ? "center" : "cursor"
32043
32119
  });
32044
32120
  return;
32045
32121
  } catch (err) {
@@ -32079,12 +32155,14 @@ var App = class _App extends React43.Component {
32079
32155
  }
32080
32156
  this.addTextFromPaste(data.text, isPlainPaste);
32081
32157
  }
32082
- this.setActiveTool({ type: "selection" });
32158
+ this.setActiveTool({ type: this.defaultSelectionTool }, true);
32083
32159
  event?.preventDefault();
32084
32160
  }
32085
32161
  ));
32086
32162
  __publicField(this, "addElementsFromPasteOrLibrary", (opts) => {
32087
- const elements = restoreElements(opts.elements, null, void 0);
32163
+ const elements = restoreElements(opts.elements, null, {
32164
+ deleteInvisibleElements: true
32165
+ });
32088
32166
  const [minX, minY, maxX, maxY] = getCommonBounds12(elements);
32089
32167
  const elementsCenterX = distance2(minX, maxX) / 2;
32090
32168
  const elementsCenterY = distance2(minY, maxY) / 2;
@@ -32100,7 +32178,7 @@ var App = class _App extends React43.Component {
32100
32178
  const { duplicatedElements } = duplicateElements3({
32101
32179
  type: "everything",
32102
32180
  elements: elements.map((element) => {
32103
- return newElementWith10(element, {
32181
+ return newElementWith11(element, {
32104
32182
  x: element.x + gridX - minX,
32105
32183
  y: element.y + gridY - minY
32106
32184
  });
@@ -32181,7 +32259,7 @@ var App = class _App extends React43.Component {
32181
32259
  }
32182
32260
  }
32183
32261
  );
32184
- this.setActiveTool({ type: "selection" });
32262
+ this.setActiveTool({ type: this.defaultSelectionTool }, true);
32185
32263
  if (opts.fitToContent) {
32186
32264
  this.scrollToContent(duplicatedElements, {
32187
32265
  fitToContent: true,
@@ -32212,7 +32290,7 @@ var App = class _App extends React43.Component {
32212
32290
  ...prevState.activeTool,
32213
32291
  ...updateActiveTool7(
32214
32292
  this.state,
32215
- prevState.activeTool.locked ? { type: "selection" } : prevState.activeTool
32293
+ prevState.activeTool.locked ? { type: this.defaultSelectionTool } : prevState.activeTool
32216
32294
  ),
32217
32295
  locked: !prevState.activeTool.locked
32218
32296
  }
@@ -32447,6 +32525,19 @@ var App = class _App extends React43.Component {
32447
32525
  }
32448
32526
  }
32449
32527
  ));
32528
+ __publicField(this, "applyDeltas", (deltas, options) => {
32529
+ const aggregatedDelta = StoreDelta2.squash(...deltas);
32530
+ const nextAppState = { ...this.state };
32531
+ const nextElements = new Map(
32532
+ this.scene.getElementsMapIncludingDeleted()
32533
+ );
32534
+ return StoreDelta2.applyTo(
32535
+ aggregatedDelta,
32536
+ nextElements,
32537
+ nextAppState,
32538
+ options
32539
+ );
32540
+ });
32450
32541
  __publicField(this, "mutateElement", (element, updates, informMutation = true) => {
32451
32542
  return this.scene.mutateElement(element, updates, {
32452
32543
  informMutation,
@@ -32814,7 +32905,7 @@ var App = class _App extends React43.Component {
32814
32905
  }
32815
32906
  }
32816
32907
  } else if (!event.ctrlKey && !event.altKey && !event.metaKey && !this.state.newElement && !this.state.selectionElement && !this.state.selectedElementsAreBeingDragged) {
32817
- const shape = findShapeByKey(event.key);
32908
+ const shape = findShapeByKey(event.key, this);
32818
32909
  if (shape) {
32819
32910
  if (this.state.activeTool.type !== shape) {
32820
32911
  trackEvent(
@@ -32871,7 +32962,7 @@ var App = class _App extends React43.Component {
32871
32962
  }
32872
32963
  if (event.key === KEYS52.K && !event.altKey && !event[KEYS52.CTRL_OR_CMD]) {
32873
32964
  if (this.state.activeTool.type === "laser") {
32874
- this.setActiveTool({ type: "selection" });
32965
+ this.setActiveTool({ type: this.defaultSelectionTool });
32875
32966
  } else {
32876
32967
  this.setActiveTool({ type: "laser" });
32877
32968
  }
@@ -33246,7 +33337,7 @@ var App = class _App extends React43.Component {
33246
33337
  if (this.state.multiElement) {
33247
33338
  return;
33248
33339
  }
33249
- if (this.state.activeTool.type !== "selection") {
33340
+ if (this.state.activeTool.type !== this.defaultSelectionTool) {
33250
33341
  return;
33251
33342
  }
33252
33343
  const selectedElements = this.scene.getSelectedElements(this.state);
@@ -33468,7 +33559,7 @@ var App = class _App extends React43.Component {
33468
33559
  __publicField(this, "getTopLayerFrameAtSceneCoords", (sceneCoords) => {
33469
33560
  const elementsMap = this.scene.getNonDeletedElementsMap();
33470
33561
  const frames = this.scene.getNonDeletedFramesLikes().filter(
33471
- (frame) => isCursorInFrame(sceneCoords, frame, elementsMap)
33562
+ (frame) => !frame.locked && isCursorInFrame(sceneCoords, frame, elementsMap)
33472
33563
  );
33473
33564
  return frames.length ? frames[frames.length - 1] : null;
33474
33565
  });
@@ -33682,7 +33773,7 @@ var App = class _App extends React43.Component {
33682
33773
  return;
33683
33774
  }
33684
33775
  const hasDeselectedButton = Boolean(event.buttons);
33685
- if (hasDeselectedButton || this.state.activeTool.type !== "selection" && this.state.activeTool.type !== "text" && this.state.activeTool.type !== "eraser") {
33776
+ if (hasDeselectedButton || this.state.activeTool.type !== "selection" && this.state.activeTool.type !== "lasso" && this.state.activeTool.type !== "text" && this.state.activeTool.type !== "eraser") {
33686
33777
  return;
33687
33778
  }
33688
33779
  const elements = this.scene.getNonDeletedElements();
@@ -33796,7 +33887,9 @@ var App = class _App extends React43.Component {
33796
33887
  });
33797
33888
  } else if (!hitElement || // Ebow arrows can only be moved when unconnected
33798
33889
  !isElbowArrow11(hitElement) || !(hitElement.startBinding || hitElement.endBinding)) {
33799
- setCursor(this.interactiveCanvas, CURSOR_TYPE4.MOVE);
33890
+ if (this.state.activeTool.type !== "lasso" || selectedElements.length > 0) {
33891
+ setCursor(this.interactiveCanvas, CURSOR_TYPE4.MOVE);
33892
+ }
33800
33893
  if (this.state.activeEmbeddable?.state === "hover") {
33801
33894
  this.setState({ activeEmbeddable: null });
33802
33895
  }
@@ -33994,11 +34087,76 @@ var App = class _App extends React43.Component {
33994
34087
  return;
33995
34088
  }
33996
34089
  if (this.state.activeTool.type === "lasso") {
33997
- this.lassoTrail.startPath(
33998
- pointerDownState.origin.x,
33999
- pointerDownState.origin.y,
34000
- event.shiftKey
34001
- );
34090
+ const hitSelectedElement = pointerDownState.hit.element && this.isASelectedElement(pointerDownState.hit.element);
34091
+ const isMobileOrTablet = this.isMobileOrTablet();
34092
+ if (!pointerDownState.hit.hasHitCommonBoundingBoxOfSelectedElements && !pointerDownState.resize.handleType && !hitSelectedElement) {
34093
+ this.lassoTrail.startPath(
34094
+ pointerDownState.origin.x,
34095
+ pointerDownState.origin.y,
34096
+ event.shiftKey
34097
+ );
34098
+ pointerDownState.drag.blockDragging = !isMobileOrTablet;
34099
+ }
34100
+ if (isMobileOrTablet && pointerDownState.hit.element && !hitSelectedElement) {
34101
+ this.setState((prevState) => {
34102
+ const nextSelectedElementIds = {
34103
+ ...prevState.selectedElementIds,
34104
+ [pointerDownState.hit.element.id]: true
34105
+ };
34106
+ const previouslySelectedElements = [];
34107
+ Object.keys(prevState.selectedElementIds).forEach((id) => {
34108
+ const element = this.scene.getElement(id);
34109
+ element && previouslySelectedElements.push(element);
34110
+ });
34111
+ const hitElement = pointerDownState.hit.element;
34112
+ if (isFrameLikeElement15(hitElement)) {
34113
+ getFrameChildren6(previouslySelectedElements, hitElement.id).forEach(
34114
+ (element) => {
34115
+ delete nextSelectedElementIds[element.id];
34116
+ }
34117
+ );
34118
+ } else if (hitElement.frameId) {
34119
+ if (nextSelectedElementIds[hitElement.frameId]) {
34120
+ delete nextSelectedElementIds[hitElement.id];
34121
+ }
34122
+ } else {
34123
+ const groupIds = hitElement.groupIds;
34124
+ const framesInGroups = new Set(
34125
+ groupIds.flatMap(
34126
+ (gid) => getElementsInGroup9(this.scene.getNonDeletedElements(), gid)
34127
+ ).filter((element) => isFrameLikeElement15(element)).map((frame) => frame.id)
34128
+ );
34129
+ if (framesInGroups.size > 0) {
34130
+ previouslySelectedElements.forEach((element) => {
34131
+ if (element.frameId && framesInGroups.has(element.frameId)) {
34132
+ delete nextSelectedElementIds[element.id];
34133
+ element.groupIds.flatMap(
34134
+ (gid) => getElementsInGroup9(
34135
+ this.scene.getNonDeletedElements(),
34136
+ gid
34137
+ )
34138
+ ).forEach((element2) => {
34139
+ delete nextSelectedElementIds[element2.id];
34140
+ });
34141
+ }
34142
+ });
34143
+ }
34144
+ }
34145
+ return {
34146
+ ...selectGroupsForSelectedElements6(
34147
+ {
34148
+ editingGroupId: prevState.editingGroupId,
34149
+ selectedElementIds: nextSelectedElementIds
34150
+ },
34151
+ this.scene.getNonDeletedElements(),
34152
+ prevState,
34153
+ this
34154
+ ),
34155
+ showHyperlinkPopup: hitElement.link || isEmbeddableElement4(hitElement) ? "info" : false
34156
+ };
34157
+ });
34158
+ pointerDownState.hit.wasAddedToSelection = true;
34159
+ }
34002
34160
  } else if (this.state.activeTool.type === "text") {
34003
34161
  this.handleTextOnPointerDown(event, pointerDownState);
34004
34162
  } else if (this.state.activeTool.type === "arrow" || this.state.activeTool.type === "line") {
@@ -34225,7 +34383,7 @@ var App = class _App extends React43.Component {
34225
34383
  * @returns whether the pointer event has been completely handled
34226
34384
  */
34227
34385
  __publicField(this, "handleSelectionOnPointerDown", (event, pointerDownState) => {
34228
- if (this.state.activeTool.type === "selection") {
34386
+ if (this.state.activeTool.type === "selection" || this.state.activeTool.type === "lasso") {
34229
34387
  const elements = this.scene.getNonDeletedElements();
34230
34388
  const elementsMap = this.scene.getNonDeletedElementsMap();
34231
34389
  const selectedElements = this.scene.getSelectedElements(this.state);
@@ -34375,6 +34533,15 @@ var App = class _App extends React43.Component {
34375
34533
  } else if (hitElement != null) {
34376
34534
  if (event[KEYS52.CTRL_OR_CMD]) {
34377
34535
  if (event.altKey) {
34536
+ if (this.state.openDialog?.name === "elementLinkSelector") {
34537
+ this.setOpenDialog(null);
34538
+ }
34539
+ this.lassoTrail.startPath(
34540
+ pointerDownState.origin.x,
34541
+ pointerDownState.origin.y,
34542
+ event.shiftKey
34543
+ );
34544
+ this.setActiveTool({ type: "lasso", fromSelection: true });
34378
34545
  return false;
34379
34546
  }
34380
34547
  if (!this.state.selectedElementIds[hitElement.id]) {
@@ -34501,7 +34668,9 @@ var App = class _App extends React43.Component {
34501
34668
  resetCursor(this.interactiveCanvas);
34502
34669
  if (!this.state.activeTool.locked) {
34503
34670
  this.setState({
34504
- activeTool: updateActiveTool7(this.state, { type: "selection" })
34671
+ activeTool: updateActiveTool7(this.state, {
34672
+ type: this.defaultSelectionTool
34673
+ })
34505
34674
  });
34506
34675
  }
34507
34676
  });
@@ -34867,7 +35036,7 @@ var App = class _App extends React43.Component {
34867
35036
  const elements = this.scene.getElementsIncludingDeleted().map((ele) => {
34868
35037
  if (this.elementsPendingErasure.has(ele.id) || ele.frameId && this.elementsPendingErasure.has(ele.frameId) || isBoundToContainer8(ele) && this.elementsPendingErasure.has(ele.containerId)) {
34869
35038
  didChange = true;
34870
- return newElementWith10(ele, { isDeleted: true });
35039
+ return newElementWith11(ele, { isDeleted: true });
34871
35040
  }
34872
35041
  return ele;
34873
35042
  });
@@ -34976,7 +35145,7 @@ var App = class _App extends React43.Component {
34976
35145
  */
34977
35146
  __publicField(this, "getLatestInitializedImageElement", (imagePlaceholder, fileId) => {
34978
35147
  const latestImageElement = this.scene.getElement(imagePlaceholder.id) ?? imagePlaceholder;
34979
- return newElementWith10(
35148
+ return newElementWith11(
34980
35149
  latestImageElement,
34981
35150
  {
34982
35151
  fileId
@@ -35058,7 +35227,9 @@ var App = class _App extends React43.Component {
35058
35227
  this.setState(
35059
35228
  {
35060
35229
  newElement: null,
35061
- activeTool: updateActiveTool7(this.state, { type: "selection" })
35230
+ activeTool: updateActiveTool7(this.state, {
35231
+ type: this.defaultSelectionTool
35232
+ })
35062
35233
  },
35063
35234
  () => {
35064
35235
  this.actionManager.executeAction(actionFinalize);
@@ -35095,9 +35266,9 @@ var App = class _App extends React43.Component {
35095
35266
  if (erroredFiles.size) {
35096
35267
  this.store.scheduleAction(CaptureUpdateAction37.NEVER);
35097
35268
  this.scene.replaceAllElements(
35098
- elements.map((element) => {
35269
+ this.scene.getElementsIncludingDeleted().map((element) => {
35099
35270
  if (isInitializedImageElement3(element) && erroredFiles.has(element.fileId)) {
35100
- return newElementWith10(element, {
35271
+ return newElementWith11(element, {
35101
35272
  status: "error"
35102
35273
  });
35103
35274
  }
@@ -35312,7 +35483,7 @@ var App = class _App extends React43.Component {
35312
35483
  __publicField(this, "handleCanvasContextMenu", (event) => {
35313
35484
  event.preventDefault();
35314
35485
  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") {
35486
+ event.button !== POINTER_BUTTON2.SECONDARY) && this.state.activeTool.type !== this.defaultSelectionTool) {
35316
35487
  return;
35317
35488
  }
35318
35489
  const { x, y } = viewportCoordsToSceneCoords4(event, this.state);
@@ -35801,6 +35972,7 @@ var App = class _App extends React43.Component {
35801
35972
  this.setState({ ...this.getCanvasOffsets() });
35802
35973
  });
35803
35974
  const defaultAppState = getDefaultAppState();
35975
+ this.defaultSelectionTool = this.isMobileOrTablet() ? "lasso" : "selection";
35804
35976
  const {
35805
35977
  excalidrawAPI,
35806
35978
  viewModeEnabled = false,
@@ -35841,6 +36013,7 @@ var App = class _App extends React43.Component {
35841
36013
  if (excalidrawAPI) {
35842
36014
  const api = {
35843
36015
  updateScene: this.updateScene,
36016
+ applyDeltas: this.applyDeltas,
35844
36017
  mutateElement: this.mutateElement,
35845
36018
  updateLibrary: this.library.updateLibrary,
35846
36019
  addFiles: this.addFiles,
@@ -36320,7 +36493,7 @@ var App = class _App extends React43.Component {
36320
36493
  showExitZenModeBtn: typeof this.props?.zenModeEnabled === "undefined" && this.state.zenModeEnabled,
36321
36494
  UIOptions: this.props.UIOptions,
36322
36495
  onExportImage: this.onExportImage,
36323
- renderWelcomeScreen: !this.state.isLoading && this.state.showWelcomeScreen && this.state.activeTool.type === "selection" && !this.state.zenModeEnabled && !this.scene.getElementsIncludingDeleted().length,
36496
+ renderWelcomeScreen: !this.state.isLoading && this.state.showWelcomeScreen && this.state.activeTool.type === this.defaultSelectionTool && !this.state.zenModeEnabled && !this.scene.getElementsIncludingDeleted().length,
36324
36497
  app: this,
36325
36498
  isCollaborating: this.props.isCollaborating,
36326
36499
  generateLinkForSelection: this.props.generateLinkForSelection,
@@ -36962,6 +37135,7 @@ var App = class _App extends React43.Component {
36962
37135
  }
36963
37136
  static resetTapTwice() {
36964
37137
  didTapTwice = false;
37138
+ firstTapPosition = null;
36965
37139
  }
36966
37140
  // TODO rewrite this to paste both text & images at the same time if
36967
37141
  // pasted data contains both
@@ -37134,7 +37308,7 @@ var App = class _App extends React43.Component {
37134
37308
  // Not sure why we include deleted elements as well hence using deleted elements map
37135
37309
  ...this.scene.getElementsIncludingDeleted().map((_element) => {
37136
37310
  if (_element.id === element.id && isTextElement19(_element)) {
37137
- return newElementWith10(_element, {
37311
+ return newElementWith11(_element, {
37138
37312
  originalText: nextOriginalText,
37139
37313
  isDeleted: isDeleted ?? _element.isDeleted,
37140
37314
  // returns (wrapped) text and new dimensions
@@ -37174,13 +37348,7 @@ var App = class _App extends React43.Component {
37174
37348
  }),
37175
37349
  onSubmit: withBatchedUpdates(({ viaKeyboard, nextOriginalText }) => {
37176
37350
  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
- }
37351
+ updateElement(nextOriginalText, isDeleted);
37184
37352
  if (!isDeleted && viaKeyboard) {
37185
37353
  const elementIdToSelect = element.containerId ? element.containerId : element.id;
37186
37354
  flushSync3(() => {
@@ -37200,7 +37368,9 @@ var App = class _App extends React43.Component {
37200
37368
  element
37201
37369
  ]);
37202
37370
  }
37203
- this.store.scheduleCapture();
37371
+ if (!isDeleted || isExistingElement) {
37372
+ this.store.scheduleCapture();
37373
+ }
37204
37374
  flushSync3(() => {
37205
37375
  this.setState({
37206
37376
  newElement: null,
@@ -37399,7 +37569,9 @@ var App = class _App extends React43.Component {
37399
37569
  // Ebow arrows can only be moved when unconnected
37400
37570
  !isElbowArrow11(element) || !(element.startBinding || element.endBinding)
37401
37571
  ) {
37402
- setCursor(this.interactiveCanvas, CURSOR_TYPE4.MOVE);
37572
+ if (this.state.activeTool.type !== "lasso" || Object.keys(this.state.selectedElementIds).length > 0) {
37573
+ setCursor(this.interactiveCanvas, CURSOR_TYPE4.MOVE);
37574
+ }
37403
37575
  }
37404
37576
  }
37405
37577
  } else if (this.hitElement(scenePointerX, scenePointerY, element)) {
@@ -37407,7 +37579,9 @@ var App = class _App extends React43.Component {
37407
37579
  // Ebow arrows can only be moved when unconnected
37408
37580
  !isElbowArrow11(element) || !(element.startBinding || element.endBinding)
37409
37581
  ) {
37410
- setCursor(this.interactiveCanvas, CURSOR_TYPE4.MOVE);
37582
+ if (this.state.activeTool.type !== "lasso" || Object.keys(this.state.selectedElementIds).length > 0) {
37583
+ setCursor(this.interactiveCanvas, CURSOR_TYPE4.MOVE);
37584
+ }
37411
37585
  }
37412
37586
  }
37413
37587
  if (this.state.selectedLinearElement.hoverPointIndex !== hoverPointIndex) {
@@ -37492,7 +37666,8 @@ var App = class _App extends React43.Component {
37492
37666
  drag: {
37493
37667
  hasOccurred: false,
37494
37668
  offset: null,
37495
- origin: { ...origin }
37669
+ origin: { ...origin },
37670
+ blockDragging: false
37496
37671
  },
37497
37672
  eventListeners: {
37498
37673
  onMove: null,
@@ -37758,9 +37933,9 @@ var App = class _App extends React43.Component {
37758
37933
  (element) => this.isASelectedElement(element)
37759
37934
  );
37760
37935
  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") {
37936
+ if ((hasHitASelectedElement || pointerDownState.hit.hasHitCommonBoundingBoxOfSelectedElements) && !isSelectingPointsInLineEditor && !pointerDownState.drag.blockDragging) {
37762
37937
  const selectedElements = this.scene.getSelectedElements(this.state);
37763
- if (selectedElements.every((element) => element.locked)) {
37938
+ if (selectedElements.length > 0 && selectedElements.every((element) => element.locked)) {
37764
37939
  return;
37765
37940
  }
37766
37941
  const selectedElementsHasAFrame = selectedElements.find(
@@ -37774,6 +37949,12 @@ var App = class _App extends React43.Component {
37774
37949
  });
37775
37950
  }
37776
37951
  pointerDownState.drag.hasOccurred = true;
37952
+ if (this.state.activeTool.type === "lasso" && this.lassoTrail.hasCurrentTrail && !(this.isMobileOrTablet() && pointerDownState.hit.element) && !this.state.activeTool.fromSelection) {
37953
+ return;
37954
+ }
37955
+ if (this.state.activeTool.type === "lasso" && selectedElements.length > 0 && pointerDownState.drag.hasOccurred && !this.state.activeTool.fromSelection) {
37956
+ this.lassoTrail.endPath();
37957
+ }
37777
37958
  if (selectedElements.length > 0 && !pointerDownState.withCmdOrCtrl && !this.state.editingTextElement && this.state.activeEmbeddable?.state !== "active") {
37778
37959
  const dragOffset = {
37779
37960
  x: pointerCoords.x - pointerDownState.drag.origin.x,
@@ -37950,7 +38131,7 @@ var App = class _App extends React43.Component {
37950
38131
  if (idsOfElementsToDuplicate.has(el.id)) {
37951
38132
  const origEl = pointerDownState.originalElements.get(el.id);
37952
38133
  if (origEl) {
37953
- return newElementWith10(el, {
38134
+ return newElementWith11(el, {
37954
38135
  x: origEl.x,
37955
38136
  y: origEl.y
37956
38137
  });
@@ -38219,6 +38400,7 @@ var App = class _App extends React43.Component {
38219
38400
  onPointerUpFromPointerDownHandler(pointerDownState) {
38220
38401
  return withBatchedUpdates((childEvent) => {
38221
38402
  this.removePointer(childEvent);
38403
+ pointerDownState.drag.blockDragging = false;
38222
38404
  if (pointerDownState.eventListeners.onMove) {
38223
38405
  pointerDownState.eventListeners.onMove.flush();
38224
38406
  }
@@ -38433,7 +38615,7 @@ var App = class _App extends React43.Component {
38433
38615
  this.setState((prevState) => ({
38434
38616
  newElement: null,
38435
38617
  activeTool: updateActiveTool7(this.state, {
38436
- type: "selection"
38618
+ type: this.defaultSelectionTool
38437
38619
  }),
38438
38620
  selectedElementIds: makeNextSelectedElementIds2(
38439
38621
  {
@@ -38870,7 +39052,9 @@ var App = class _App extends React43.Component {
38870
39052
  this.setState({
38871
39053
  newElement: null,
38872
39054
  suggestedBindings: [],
38873
- activeTool: updateActiveTool7(this.state, { type: "selection" })
39055
+ activeTool: updateActiveTool7(this.state, {
39056
+ type: this.defaultSelectionTool
39057
+ })
38874
39058
  });
38875
39059
  } else {
38876
39060
  this.setState({
@@ -39401,7 +39585,7 @@ import {
39401
39585
  } from "@excalidraw/common";
39402
39586
  import {
39403
39587
  mutateElement as mutateElement2,
39404
- newElementWith as newElementWith11,
39588
+ newElementWith as newElementWith12,
39405
39589
  bumpVersion
39406
39590
  } from "@excalidraw/element";
39407
39591
  import { CaptureUpdateAction as CaptureUpdateAction38 } from "@excalidraw/element";
@@ -39652,12 +39836,13 @@ export {
39652
39836
  loadSceneOrLibraryFromBlob,
39653
39837
  mergeLibraryItems,
39654
39838
  mutateElement2 as mutateElement,
39655
- newElementWith11 as newElementWith,
39839
+ newElementWith12 as newElementWith,
39656
39840
  normalizeLink4 as normalizeLink,
39657
39841
  parseLibraryTokensFromUrl,
39658
39842
  reconcileElements,
39659
39843
  restore,
39660
39844
  restoreAppState,
39845
+ restoreElement,
39661
39846
  restoreElements,
39662
39847
  restoreLibraryItems,
39663
39848
  sceneCoordsToViewportCoords2 as sceneCoordsToViewportCoords,