@excalidraw/element 0.18.0-f0063e113 → 0.18.0-f29e9df

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 (47) hide show
  1. package/dist/dev/index.js +404 -155
  2. package/dist/dev/index.js.map +3 -3
  3. package/dist/prod/index.js +12 -12
  4. package/dist/types/common/src/constants.d.ts +2 -0
  5. package/dist/types/element/src/Scene.d.ts +6 -2
  6. package/dist/types/element/src/align.d.ts +2 -1
  7. package/dist/types/element/src/delta.d.ts +16 -4
  8. package/dist/types/element/src/distribute.d.ts +2 -1
  9. package/dist/types/element/src/groups.d.ts +1 -0
  10. package/dist/types/element/src/linearElementEditor.d.ts +2 -1
  11. package/dist/types/element/src/store.d.ts +8 -2
  12. package/dist/types/excalidraw/actions/actionAddToLibrary.d.ts +0 -3
  13. package/dist/types/excalidraw/actions/actionBoundText.d.ts +0 -2
  14. package/dist/types/excalidraw/actions/actionCanvas.d.ts +15 -14
  15. package/dist/types/excalidraw/actions/actionClipboard.d.ts +3 -8
  16. package/dist/types/excalidraw/actions/actionCropEditor.d.ts +0 -1
  17. package/dist/types/excalidraw/actions/actionDeleteSelected.d.ts +3 -6
  18. package/dist/types/excalidraw/actions/actionElementLink.d.ts +0 -1
  19. package/dist/types/excalidraw/actions/actionElementLock.d.ts +0 -2
  20. package/dist/types/excalidraw/actions/actionEmbeddable.d.ts +0 -1
  21. package/dist/types/excalidraw/actions/actionExport.d.ts +0 -9
  22. package/dist/types/excalidraw/actions/actionFinalize.d.ts +2 -3
  23. package/dist/types/excalidraw/actions/actionFrame.d.ts +0 -4
  24. package/dist/types/excalidraw/actions/actionGroup.d.ts +0 -2
  25. package/dist/types/excalidraw/actions/actionLinearEditor.d.ts +33 -3
  26. package/dist/types/excalidraw/actions/actionLink.d.ts +0 -1
  27. package/dist/types/excalidraw/actions/actionMenu.d.ts +0 -3
  28. package/dist/types/excalidraw/actions/actionNavigate.d.ts +0 -2
  29. package/dist/types/excalidraw/actions/actionProperties.d.ts +0 -15
  30. package/dist/types/excalidraw/actions/actionSelectAll.d.ts +0 -1
  31. package/dist/types/excalidraw/actions/actionStyles.d.ts +0 -1
  32. package/dist/types/excalidraw/actions/actionToggleGridMode.d.ts +0 -1
  33. package/dist/types/excalidraw/actions/actionToggleObjectsSnapMode.d.ts +0 -1
  34. package/dist/types/excalidraw/actions/actionToggleSearchMenu.d.ts +0 -1
  35. package/dist/types/excalidraw/actions/actionToggleStats.d.ts +0 -1
  36. package/dist/types/excalidraw/actions/actionToggleViewMode.d.ts +0 -1
  37. package/dist/types/excalidraw/actions/actionToggleZenMode.d.ts +0 -1
  38. package/dist/types/excalidraw/components/Actions.d.ts +0 -4
  39. package/dist/types/excalidraw/components/App.d.ts +8 -2
  40. package/dist/types/excalidraw/components/Ellipsify.d.ts +4 -0
  41. package/dist/types/excalidraw/components/shapes.d.ts +129 -1
  42. package/dist/types/excalidraw/data/reconcile.d.ts +1 -0
  43. package/dist/types/excalidraw/data/restore.d.ts +6 -1
  44. package/dist/types/excalidraw/index.d.ts +2 -1
  45. package/dist/types/excalidraw/renderer/staticScene.d.ts +4 -1
  46. package/dist/types/excalidraw/types.d.ts +7 -4
  47. package/package.json +7 -3
package/dist/dev/index.js CHANGED
@@ -8127,7 +8127,8 @@ var LinearElementEditor = class _LinearElementEditor {
8127
8127
  segmentMidPointHoveredCoords;
8128
8128
  elbowed;
8129
8129
  customLineAngle;
8130
- constructor(element, elementsMap) {
8130
+ isEditing;
8131
+ constructor(element, elementsMap, isEditing = false) {
8131
8132
  this.elementId = element.id;
8132
8133
  if (!pointsEqual6(element.points[0], pointFrom8(0, 0))) {
8133
8134
  console.error("Linear element is not normalized", Error().stack);
@@ -8158,6 +8159,7 @@ var LinearElementEditor = class _LinearElementEditor {
8158
8159
  this.segmentMidPointHoveredCoords = null;
8159
8160
  this.elbowed = isElbowArrow(element) && element.elbowed;
8160
8161
  this.customLineAngle = null;
8162
+ this.isEditing = isEditing;
8161
8163
  }
8162
8164
  // ---------------------------------------------------------------------------
8163
8165
  // static methods
@@ -8175,11 +8177,11 @@ var LinearElementEditor = class _LinearElementEditor {
8175
8177
  return null;
8176
8178
  }
8177
8179
  static handleBoxSelection(event, appState, setState, elementsMap) {
8178
- if (!appState.editingLinearElement || !appState.selectionElement) {
8180
+ if (!appState.selectedLinearElement?.isEditing || !appState.selectionElement) {
8179
8181
  return false;
8180
8182
  }
8181
- const { editingLinearElement } = appState;
8182
- const { selectedPointsIndices, elementId } = editingLinearElement;
8183
+ const { selectedLinearElement } = appState;
8184
+ const { selectedPointsIndices, elementId } = selectedLinearElement;
8183
8185
  const element = _LinearElementEditor.getElement(elementId, elementsMap);
8184
8186
  if (!element) {
8185
8187
  return false;
@@ -8201,8 +8203,8 @@ var LinearElementEditor = class _LinearElementEditor {
8201
8203
  return true;
8202
8204
  });
8203
8205
  setState({
8204
- editingLinearElement: {
8205
- ...editingLinearElement,
8206
+ selectedLinearElement: {
8207
+ ...selectedLinearElement,
8206
8208
  selectedPointsIndices: nextSelectedPoints.length ? nextSelectedPoints : null
8207
8209
  }
8208
8210
  });
@@ -8356,7 +8358,6 @@ var LinearElementEditor = class _LinearElementEditor {
8356
8358
  };
8357
8359
  return {
8358
8360
  ...app.state,
8359
- editingLinearElement: app.state.editingLinearElement ? newLinearElementEditor : null,
8360
8361
  selectedLinearElement: newLinearElementEditor,
8361
8362
  suggestedBindings
8362
8363
  };
@@ -8440,7 +8441,7 @@ var LinearElementEditor = class _LinearElementEditor {
8440
8441
  }
8441
8442
  static getEditorMidPoints = (element, elementsMap, appState) => {
8442
8443
  const boundText = getBoundTextElement(element, elementsMap);
8443
- if (!isElbowArrow(element) && !appState.editingLinearElement && element.points.length > 2 && !boundText) {
8444
+ if (!isElbowArrow(element) && !appState.selectedLinearElement?.isEditing && element.points.length > 2 && !boundText) {
8444
8445
  return [];
8445
8446
  }
8446
8447
  const points = _LinearElementEditor.getPointsGlobalCoordinates(
@@ -8490,7 +8491,7 @@ var LinearElementEditor = class _LinearElementEditor {
8490
8491
  element,
8491
8492
  elementsMap
8492
8493
  );
8493
- if (points.length >= 3 && !appState.editingLinearElement && !isElbowArrow(element)) {
8494
+ if (points.length >= 3 && !appState.selectedLinearElement?.isEditing && !isElbowArrow(element)) {
8494
8495
  return null;
8495
8496
  }
8496
8497
  const threshold = (_LinearElementEditor.POINT_HANDLE_SIZE + 1) / appState.zoom.value;
@@ -8630,7 +8631,7 @@ var LinearElementEditor = class _LinearElementEditor {
8630
8631
  segmentMidpoint,
8631
8632
  elementsMap
8632
8633
  );
8633
- } else if (event.altKey && appState.editingLinearElement) {
8634
+ } else if (event.altKey && appState.selectedLinearElement?.isEditing) {
8634
8635
  if (linearElementEditor.lastUncommittedPoint == null) {
8635
8636
  scene.mutateElement(element, {
8636
8637
  points: [
@@ -8740,14 +8741,14 @@ var LinearElementEditor = class _LinearElementEditor {
8740
8741
  }
8741
8742
  static handlePointerMove(event, scenePointerX, scenePointerY, app) {
8742
8743
  const appState = app.state;
8743
- if (!appState.editingLinearElement) {
8744
+ if (!appState.selectedLinearElement?.isEditing) {
8744
8745
  return null;
8745
8746
  }
8746
- const { elementId, lastUncommittedPoint } = appState.editingLinearElement;
8747
+ const { elementId, lastUncommittedPoint } = appState.selectedLinearElement;
8747
8748
  const elementsMap = app.scene.getNonDeletedElementsMap();
8748
8749
  const element = _LinearElementEditor.getElement(elementId, elementsMap);
8749
8750
  if (!element) {
8750
- return appState.editingLinearElement;
8751
+ return appState.selectedLinearElement;
8751
8752
  }
8752
8753
  const { points } = element;
8753
8754
  const lastPoint = points[points.length - 1];
@@ -8755,10 +8756,10 @@ var LinearElementEditor = class _LinearElementEditor {
8755
8756
  if (lastPoint === lastUncommittedPoint) {
8756
8757
  _LinearElementEditor.deletePoints(element, app, [points.length - 1]);
8757
8758
  }
8758
- return {
8759
- ...appState.editingLinearElement,
8759
+ return appState.selectedLinearElement?.lastUncommittedPoint ? {
8760
+ ...appState.selectedLinearElement,
8760
8761
  lastUncommittedPoint: null
8761
- };
8762
+ } : appState.selectedLinearElement;
8762
8763
  }
8763
8764
  let newPoint;
8764
8765
  if (shouldRotateWithDiscreteAngle(event) && points.length >= 2) {
@@ -8778,8 +8779,8 @@ var LinearElementEditor = class _LinearElementEditor {
8778
8779
  newPoint = _LinearElementEditor.createPointAt(
8779
8780
  element,
8780
8781
  elementsMap,
8781
- scenePointerX - appState.editingLinearElement.pointerOffset.x,
8782
- scenePointerY - appState.editingLinearElement.pointerOffset.y,
8782
+ scenePointerX - appState.selectedLinearElement.pointerOffset.x,
8783
+ scenePointerY - appState.selectedLinearElement.pointerOffset.y,
8783
8784
  event[KEYS2.CTRL_OR_CMD] || isElbowArrow(element) ? null : app.getEffectiveGridSize()
8784
8785
  );
8785
8786
  }
@@ -8800,7 +8801,7 @@ var LinearElementEditor = class _LinearElementEditor {
8800
8801
  _LinearElementEditor.addPoints(element, app.scene, [newPoint]);
8801
8802
  }
8802
8803
  return {
8803
- ...appState.editingLinearElement,
8804
+ ...appState.selectedLinearElement,
8804
8805
  lastUncommittedPoint: element.points[element.points.length - 1]
8805
8806
  };
8806
8807
  }
@@ -8906,11 +8907,11 @@ var LinearElementEditor = class _LinearElementEditor {
8906
8907
  // ---------------------------------------------------------------------------
8907
8908
  static duplicateSelectedPoints(appState, scene) {
8908
8909
  invariant6(
8909
- appState.editingLinearElement,
8910
+ appState.selectedLinearElement?.isEditing,
8910
8911
  "Not currently editing a linear element"
8911
8912
  );
8912
8913
  const elementsMap = scene.getNonDeletedElementsMap();
8913
- const { selectedPointsIndices, elementId } = appState.editingLinearElement;
8914
+ const { selectedPointsIndices, elementId } = appState.selectedLinearElement;
8914
8915
  const element = _LinearElementEditor.getElement(elementId, elementsMap);
8915
8916
  invariant6(
8916
8917
  element,
@@ -8957,14 +8958,14 @@ var LinearElementEditor = class _LinearElementEditor {
8957
8958
  }
8958
8959
  return {
8959
8960
  ...appState,
8960
- editingLinearElement: {
8961
- ...appState.editingLinearElement,
8961
+ selectedLinearElement: {
8962
+ ...appState.selectedLinearElement,
8962
8963
  selectedPointsIndices: nextSelectedIndices
8963
8964
  }
8964
8965
  };
8965
8966
  }
8966
8967
  static deletePoints(element, app, pointIndices) {
8967
- const isUncommittedPoint = app.state.editingLinearElement?.lastUncommittedPoint === element.points[element.points.length - 1];
8968
+ const isUncommittedPoint = app.state.selectedLinearElement?.isEditing && app.state.selectedLinearElement?.lastUncommittedPoint === element.points[element.points.length - 1];
8968
8969
  const nextPoints = element.points.filter((_, idx) => {
8969
8970
  return !pointIndices.includes(idx);
8970
8971
  });
@@ -9073,7 +9074,7 @@ var LinearElementEditor = class _LinearElementEditor {
9073
9074
  pointFrom8(origin.x, origin.y),
9074
9075
  pointFrom8(pointerCoords.x, pointerCoords.y)
9075
9076
  );
9076
- if (!appState.editingLinearElement && dist < DRAGGING_THRESHOLD / appState.zoom.value) {
9077
+ if (!appState.selectedLinearElement?.isEditing && dist < DRAGGING_THRESHOLD / appState.zoom.value) {
9077
9078
  return false;
9078
9079
  }
9079
9080
  return true;
@@ -9826,6 +9827,55 @@ var getNewGroupIdsForDuplication = (groupIds, editingGroupId, mapper) => {
9826
9827
  }
9827
9828
  return copy;
9828
9829
  };
9830
+ var getSelectedElementsByGroup = (selectedElements, elementsMap, appState) => {
9831
+ const selectedGroupIds = getSelectedGroupIds(appState);
9832
+ const unboundElements = selectedElements.filter(
9833
+ (element) => !isBoundToContainer(element)
9834
+ );
9835
+ const groups = /* @__PURE__ */ new Map();
9836
+ const elements = /* @__PURE__ */ new Map();
9837
+ const addToElementsMap = (element) => {
9838
+ const currentElementMembers = elements.get(element.id) || [];
9839
+ const boundTextElement = getBoundTextElement(element, elementsMap);
9840
+ if (boundTextElement) {
9841
+ currentElementMembers.push(boundTextElement);
9842
+ }
9843
+ elements.set(element.id, [...currentElementMembers, element]);
9844
+ };
9845
+ const addToGroupsMap = (element, groupId) => {
9846
+ const currentGroupMembers = groups.get(groupId) || [];
9847
+ const boundTextElement = getBoundTextElement(element, elementsMap);
9848
+ if (boundTextElement) {
9849
+ currentGroupMembers.push(boundTextElement);
9850
+ }
9851
+ groups.set(groupId, [...currentGroupMembers, element]);
9852
+ };
9853
+ const handleSingleSelectedGroupCase = (element, selectedGroupId) => {
9854
+ const indexOfSelectedGroupId = element.groupIds.indexOf(selectedGroupId, 0);
9855
+ const nestedGroupCount = element.groupIds.slice(
9856
+ 0,
9857
+ indexOfSelectedGroupId
9858
+ ).length;
9859
+ return nestedGroupCount > 0 ? addToGroupsMap(element, element.groupIds[indexOfSelectedGroupId - 1]) : addToElementsMap(element);
9860
+ };
9861
+ const isAllInSameGroup = selectedElements.every(
9862
+ (element) => isSelectedViaGroup(appState, element)
9863
+ );
9864
+ unboundElements.forEach((element) => {
9865
+ const selectedGroupId = getSelectedGroupIdForElement(
9866
+ element,
9867
+ appState.selectedGroupIds
9868
+ );
9869
+ if (!selectedGroupId) {
9870
+ addToElementsMap(element);
9871
+ } else if (selectedGroupIds.length === 1 && isAllInSameGroup) {
9872
+ handleSingleSelectedGroupCase(element, selectedGroupId);
9873
+ } else {
9874
+ addToGroupsMap(element, selectedGroupId);
9875
+ }
9876
+ });
9877
+ return Array.from(groups.values()).concat(Array.from(elements.values()));
9878
+ };
9829
9879
 
9830
9880
  // src/selection.ts
9831
9881
  var excludeElementsInFramesFromSelection = (selectedElements) => {
@@ -10513,6 +10563,11 @@ var getCanvasPadding = (element) => {
10513
10563
  return element.strokeWidth * 12;
10514
10564
  case "text":
10515
10565
  return element.fontSize / 2;
10566
+ case "arrow":
10567
+ if (element.endArrowhead || element.endArrowhead) {
10568
+ return 40;
10569
+ }
10570
+ return 20;
10516
10571
  default:
10517
10572
  return 20;
10518
10573
  }
@@ -12742,11 +12797,11 @@ var getNormalizedDimensions = (element) => {
12742
12797
 
12743
12798
  // src/align.ts
12744
12799
  init_define_import_meta_env();
12745
- var alignElements = (selectedElements, alignment, scene) => {
12746
- const elementsMap = scene.getNonDeletedElementsMap();
12747
- const groups = getMaximumGroups(
12800
+ var alignElements = (selectedElements, alignment, scene, appState) => {
12801
+ const groups = getSelectedElementsByGroup(
12748
12802
  selectedElements,
12749
- elementsMap
12803
+ scene.getNonDeletedElementsMap(),
12804
+ appState
12750
12805
  );
12751
12806
  const selectionBoundingBox = getCommonBoundingBox(selectedElements);
12752
12807
  return groups.flatMap((group) => {
@@ -13182,8 +13237,9 @@ var Store = class {
13182
13237
  constructor(app) {
13183
13238
  this.app = app;
13184
13239
  }
13185
- // internally used by history
13240
+ // for internal use by history
13186
13241
  onDurableIncrementEmitter = new Emitter();
13242
+ // for public use as part of onIncrement API
13187
13243
  onStoreIncrementEmitter = new Emitter();
13188
13244
  scheduledMacroActions = /* @__PURE__ */ new Set();
13189
13245
  scheduledMicroActions = [];
@@ -13439,7 +13495,7 @@ var EphemeralIncrement = class extends StoreIncrement {
13439
13495
  this.change = change;
13440
13496
  }
13441
13497
  };
13442
- var StoreDelta = class {
13498
+ var StoreDelta = class _StoreDelta {
13443
13499
  constructor(id, elements, appState) {
13444
13500
  this.id = id;
13445
13501
  this.elements = elements;
@@ -13477,10 +13533,23 @@ var StoreDelta = class {
13477
13533
  */
13478
13534
  static load({
13479
13535
  id,
13480
- elements: { added, removed, updated }
13536
+ elements: { added, removed, updated },
13537
+ appState: { delta: appStateDelta }
13481
13538
  }) {
13482
13539
  const elements = ElementsDelta.create(added, removed, updated);
13483
- return new this(id, elements, AppStateDelta.empty());
13540
+ const appState = AppStateDelta.create(appStateDelta);
13541
+ return new this(id, elements, appState);
13542
+ }
13543
+ /**
13544
+ * Squash the passed deltas into the aggregated delta instance.
13545
+ */
13546
+ static squash(...deltas) {
13547
+ const aggregatedDelta = _StoreDelta.empty();
13548
+ for (const delta of deltas) {
13549
+ aggregatedDelta.elements.squash(delta.elements);
13550
+ aggregatedDelta.appState.squash(delta.appState);
13551
+ }
13552
+ return aggregatedDelta;
13484
13553
  }
13485
13554
  /**
13486
13555
  * Inverse store delta, creates new instance of `StoreDelta`.
@@ -13491,8 +13560,12 @@ var StoreDelta = class {
13491
13560
  /**
13492
13561
  * Apply the delta to the passed elements and appState, does not modify the snapshot.
13493
13562
  */
13494
- static applyTo(delta, elements, appState) {
13495
- const [nextElements, elementsContainVisibleChange] = delta.elements.applyTo(elements);
13563
+ static applyTo(delta, elements, appState, options) {
13564
+ const [nextElements, elementsContainVisibleChange] = delta.elements.applyTo(
13565
+ elements,
13566
+ StoreSnapshot.empty().elements,
13567
+ options
13568
+ );
13496
13569
  const [nextAppState, appStateContainsVisibleChange] = delta.appState.applyTo(appState, nextElements);
13497
13570
  const appliedVisibleChanges = elementsContainVisibleChange || appStateContainsVisibleChange;
13498
13571
  return [nextElements, nextAppState, appliedVisibleChanges];
@@ -13513,6 +13586,9 @@ var StoreDelta = class {
13513
13586
  }
13514
13587
  );
13515
13588
  }
13589
+ static empty() {
13590
+ return _StoreDelta.create(ElementsDelta.empty(), AppStateDelta.empty());
13591
+ }
13516
13592
  isEmpty() {
13517
13593
  return this.elements.isEmpty() && this.appState.isEmpty();
13518
13594
  }
@@ -13753,8 +13829,7 @@ var getDefaultObservedAppState = () => {
13753
13829
  viewBackgroundColor: COLOR_PALETTE2.white,
13754
13830
  selectedElementIds: {},
13755
13831
  selectedGroupIds: {},
13756
- editingLinearElementId: null,
13757
- selectedLinearElementId: null,
13832
+ selectedLinearElement: null,
13758
13833
  croppingElementId: null,
13759
13834
  activeLockedId: null,
13760
13835
  lockedMultiSelections: {}
@@ -13770,10 +13845,10 @@ var getObservedAppState = (appState) => {
13770
13845
  croppingElementId: appState.croppingElementId,
13771
13846
  activeLockedId: appState.activeLockedId,
13772
13847
  lockedMultiSelections: appState.lockedMultiSelections,
13773
- editingLinearElementId: appState.editingLinearElement?.elementId ?? // prefer app state, as it's likely newer
13774
- appState.editingLinearElementId ?? // fallback to observed app state, as it's likely older coming from a previous snapshot
13775
- null,
13776
- selectedLinearElementId: appState.selectedLinearElement?.elementId ?? appState.selectedLinearElementId ?? null
13848
+ selectedLinearElement: appState.selectedLinearElement ? {
13849
+ elementId: appState.selectedLinearElement.elementId,
13850
+ isEditing: !!appState.selectedLinearElement.isEditing
13851
+ } : null
13777
13852
  };
13778
13853
  Reflect.defineProperty(observedAppState, hiddenObservedAppStateProp, {
13779
13854
  value: true,
@@ -14337,9 +14412,9 @@ var Scene = class {
14337
14412
  getFramesIncludingDeleted() {
14338
14413
  return this.frames;
14339
14414
  }
14340
- constructor(elements = null) {
14415
+ constructor(elements = null, options) {
14341
14416
  if (elements) {
14342
- this.replaceAllElements(elements);
14417
+ this.replaceAllElements(elements, options);
14343
14418
  }
14344
14419
  }
14345
14420
  getSelectedElements(opts) {
@@ -14404,10 +14479,12 @@ var Scene = class {
14404
14479
  }
14405
14480
  return didChange;
14406
14481
  }
14407
- replaceAllElements(nextElements) {
14482
+ replaceAllElements(nextElements, options) {
14408
14483
  const _nextElements = toArray(nextElements);
14409
14484
  const nextFrameLikes = [];
14410
- validateIndicesThrottled(_nextElements);
14485
+ if (!options?.skipValidation) {
14486
+ validateIndicesThrottled(_nextElements);
14487
+ }
14411
14488
  this.elements = syncInvalidIndices2(_nextElements);
14412
14489
  this.elementsMap.clear();
14413
14490
  this.elements.forEach((element) => {
@@ -14577,10 +14654,19 @@ var Delta = class _Delta {
14577
14654
  static isEmpty(delta) {
14578
14655
  return !Object.keys(delta.deleted).length && !Object.keys(delta.inserted).length;
14579
14656
  }
14657
+ /**
14658
+ * Merges two deltas into a new one.
14659
+ */
14660
+ static merge(delta1, delta2, delta3 = _Delta.empty()) {
14661
+ return _Delta.create(
14662
+ { ...delta1.deleted, ...delta2.deleted, ...delta3.deleted },
14663
+ { ...delta1.inserted, ...delta2.inserted, ...delta3.inserted }
14664
+ );
14665
+ }
14580
14666
  /**
14581
14667
  * Merges deleted and inserted object partials.
14582
14668
  */
14583
- static mergeObjects(prev, added, removed) {
14669
+ static mergeObjects(prev, added, removed = {}) {
14584
14670
  const cloned = { ...prev };
14585
14671
  for (const key of Object.keys(removed)) {
14586
14672
  delete cloned[key];
@@ -14801,6 +14887,9 @@ var AppStateDelta = class _AppStateDelta {
14801
14887
  constructor(delta) {
14802
14888
  this.delta = delta;
14803
14889
  }
14890
+ static create(delta) {
14891
+ return new _AppStateDelta(delta);
14892
+ }
14804
14893
  static calculate(prevAppState, nextAppState) {
14805
14894
  const delta = Delta.calculate(
14806
14895
  prevAppState,
@@ -14822,50 +14911,98 @@ var AppStateDelta = class _AppStateDelta {
14822
14911
  const inversedDelta = Delta.create(this.delta.inserted, this.delta.deleted);
14823
14912
  return new _AppStateDelta(inversedDelta);
14824
14913
  }
14914
+ squash(delta) {
14915
+ if (delta.isEmpty()) {
14916
+ return this;
14917
+ }
14918
+ const mergedDeletedSelectedElementIds = Delta.mergeObjects(
14919
+ this.delta.deleted.selectedElementIds ?? {},
14920
+ delta.delta.deleted.selectedElementIds ?? {}
14921
+ );
14922
+ const mergedInsertedSelectedElementIds = Delta.mergeObjects(
14923
+ this.delta.inserted.selectedElementIds ?? {},
14924
+ delta.delta.inserted.selectedElementIds ?? {}
14925
+ );
14926
+ const mergedDeletedSelectedGroupIds = Delta.mergeObjects(
14927
+ this.delta.deleted.selectedGroupIds ?? {},
14928
+ delta.delta.deleted.selectedGroupIds ?? {}
14929
+ );
14930
+ const mergedInsertedSelectedGroupIds = Delta.mergeObjects(
14931
+ this.delta.inserted.selectedGroupIds ?? {},
14932
+ delta.delta.inserted.selectedGroupIds ?? {}
14933
+ );
14934
+ const mergedDeletedLockedMultiSelections = Delta.mergeObjects(
14935
+ this.delta.deleted.lockedMultiSelections ?? {},
14936
+ delta.delta.deleted.lockedMultiSelections ?? {}
14937
+ );
14938
+ const mergedInsertedLockedMultiSelections = Delta.mergeObjects(
14939
+ this.delta.inserted.lockedMultiSelections ?? {},
14940
+ delta.delta.inserted.lockedMultiSelections ?? {}
14941
+ );
14942
+ const mergedInserted = {};
14943
+ const mergedDeleted = {};
14944
+ if (Object.keys(mergedDeletedSelectedElementIds).length || Object.keys(mergedInsertedSelectedElementIds).length) {
14945
+ mergedDeleted.selectedElementIds = mergedDeletedSelectedElementIds;
14946
+ mergedInserted.selectedElementIds = mergedInsertedSelectedElementIds;
14947
+ }
14948
+ if (Object.keys(mergedDeletedSelectedGroupIds).length || Object.keys(mergedInsertedSelectedGroupIds).length) {
14949
+ mergedDeleted.selectedGroupIds = mergedDeletedSelectedGroupIds;
14950
+ mergedInserted.selectedGroupIds = mergedInsertedSelectedGroupIds;
14951
+ }
14952
+ if (Object.keys(mergedDeletedLockedMultiSelections).length || Object.keys(mergedInsertedLockedMultiSelections).length) {
14953
+ mergedDeleted.lockedMultiSelections = mergedDeletedLockedMultiSelections;
14954
+ mergedInserted.lockedMultiSelections = mergedInsertedLockedMultiSelections;
14955
+ }
14956
+ this.delta = Delta.merge(
14957
+ this.delta,
14958
+ delta.delta,
14959
+ Delta.create(mergedDeleted, mergedInserted)
14960
+ );
14961
+ return this;
14962
+ }
14825
14963
  applyTo(appState, nextElements) {
14826
14964
  try {
14827
14965
  const {
14828
- selectedElementIds: removedSelectedElementIds = {},
14829
- selectedGroupIds: removedSelectedGroupIds = {}
14966
+ selectedElementIds: deletedSelectedElementIds = {},
14967
+ selectedGroupIds: deletedSelectedGroupIds = {},
14968
+ lockedMultiSelections: deletedLockedMultiSelections = {}
14830
14969
  } = this.delta.deleted;
14831
14970
  const {
14832
- selectedElementIds: addedSelectedElementIds = {},
14833
- selectedGroupIds: addedSelectedGroupIds = {},
14834
- selectedLinearElementId,
14835
- editingLinearElementId,
14971
+ selectedElementIds: insertedSelectedElementIds = {},
14972
+ selectedGroupIds: insertedSelectedGroupIds = {},
14973
+ lockedMultiSelections: insertedLockedMultiSelections = {},
14974
+ selectedLinearElement: insertedSelectedLinearElement,
14836
14975
  ...directlyApplicablePartial
14837
14976
  } = this.delta.inserted;
14838
14977
  const mergedSelectedElementIds = Delta.mergeObjects(
14839
14978
  appState.selectedElementIds,
14840
- addedSelectedElementIds,
14841
- removedSelectedElementIds
14979
+ insertedSelectedElementIds,
14980
+ deletedSelectedElementIds
14842
14981
  );
14843
14982
  const mergedSelectedGroupIds = Delta.mergeObjects(
14844
14983
  appState.selectedGroupIds,
14845
- addedSelectedGroupIds,
14846
- removedSelectedGroupIds
14984
+ insertedSelectedGroupIds,
14985
+ deletedSelectedGroupIds
14847
14986
  );
14848
- const selectedLinearElement = selectedLinearElementId && nextElements.has(selectedLinearElementId) ? new LinearElementEditor(
14849
- nextElements.get(
14850
- selectedLinearElementId
14851
- ),
14852
- nextElements
14853
- ) : null;
14854
- const editingLinearElement = editingLinearElementId && nextElements.has(editingLinearElementId) ? new LinearElementEditor(
14987
+ const mergedLockedMultiSelections = Delta.mergeObjects(
14988
+ appState.lockedMultiSelections,
14989
+ insertedLockedMultiSelections,
14990
+ deletedLockedMultiSelections
14991
+ );
14992
+ const selectedLinearElement = insertedSelectedLinearElement && nextElements.has(insertedSelectedLinearElement.elementId) ? new LinearElementEditor(
14855
14993
  nextElements.get(
14856
- editingLinearElementId
14994
+ insertedSelectedLinearElement.elementId
14857
14995
  ),
14858
- nextElements
14996
+ nextElements,
14997
+ insertedSelectedLinearElement.isEditing
14859
14998
  ) : null;
14860
14999
  const nextAppState = {
14861
15000
  ...appState,
14862
15001
  ...directlyApplicablePartial,
14863
15002
  selectedElementIds: mergedSelectedElementIds,
14864
15003
  selectedGroupIds: mergedSelectedGroupIds,
14865
- selectedLinearElement: typeof selectedLinearElementId !== "undefined" ? selectedLinearElement : appState.selectedLinearElement,
14866
- // otherwise assign what we had before
14867
- editingLinearElement: typeof editingLinearElementId !== "undefined" ? editingLinearElement : appState.editingLinearElement
14868
- // otherwise assign what we had before
15004
+ lockedMultiSelections: mergedLockedMultiSelections,
15005
+ selectedLinearElement: typeof insertedSelectedLinearElement !== "undefined" ? selectedLinearElement : appState.selectedLinearElement
14869
15006
  };
14870
15007
  const constainsVisibleChanges = this.filterInvisibleChanges(
14871
15008
  appState,
@@ -14955,57 +15092,44 @@ var AppStateDelta = class _AppStateDelta {
14955
15092
  nextAppState[key] = null;
14956
15093
  }
14957
15094
  break;
14958
- case "selectedLinearElementId":
14959
- case "editingLinearElementId":
14960
- const appStateKey = _AppStateDelta.convertToAppStateKey(key);
14961
- const linearElement = nextAppState[appStateKey];
14962
- if (!linearElement) {
15095
+ case "selectedLinearElement":
15096
+ const nextLinearElement = nextAppState[key];
15097
+ if (!nextLinearElement) {
14963
15098
  visibleDifferenceFlag.value = true;
14964
15099
  } else {
14965
- const element = nextElements.get(linearElement.elementId);
15100
+ const element = nextElements.get(nextLinearElement.elementId);
14966
15101
  if (element && !element.isDeleted) {
14967
15102
  visibleDifferenceFlag.value = true;
14968
15103
  } else {
14969
- nextAppState[appStateKey] = null;
15104
+ nextAppState[key] = null;
14970
15105
  }
14971
15106
  }
14972
15107
  break;
14973
- case "lockedMultiSelections": {
15108
+ case "lockedMultiSelections":
14974
15109
  const prevLockedUnits = prevAppState[key] || {};
14975
15110
  const nextLockedUnits = nextAppState[key] || {};
14976
15111
  if (!isShallowEqual2(prevLockedUnits, nextLockedUnits)) {
14977
15112
  visibleDifferenceFlag.value = true;
14978
15113
  }
14979
15114
  break;
14980
- }
14981
- case "activeLockedId": {
15115
+ case "activeLockedId":
14982
15116
  const prevHitLockedId = prevAppState[key] || null;
14983
15117
  const nextHitLockedId = nextAppState[key] || null;
14984
15118
  if (prevHitLockedId !== nextHitLockedId) {
14985
15119
  visibleDifferenceFlag.value = true;
14986
15120
  }
14987
15121
  break;
14988
- }
14989
- default: {
15122
+ default:
14990
15123
  assertNever4(
14991
15124
  key,
14992
15125
  `Unknown ObservedElementsAppState's key "${key}"`,
14993
15126
  true
14994
15127
  );
14995
- }
14996
15128
  }
14997
15129
  }
14998
15130
  }
14999
15131
  return visibleDifferenceFlag.value;
15000
15132
  }
15001
- static convertToAppStateKey(key) {
15002
- switch (key) {
15003
- case "selectedLinearElementId":
15004
- return "selectedLinearElement";
15005
- case "editingLinearElementId":
15006
- return "editingLinearElement";
15007
- }
15008
- }
15009
15133
  static filterSelectedElements(selectedElementIds, elements, visibleDifferenceFlag) {
15010
15134
  const ids = Object.keys(selectedElementIds);
15011
15135
  if (!ids.length) {
@@ -15044,8 +15168,7 @@ var AppStateDelta = class _AppStateDelta {
15044
15168
  editingGroupId,
15045
15169
  selectedGroupIds,
15046
15170
  selectedElementIds,
15047
- editingLinearElementId,
15048
- selectedLinearElementId,
15171
+ selectedLinearElement,
15049
15172
  croppingElementId,
15050
15173
  lockedMultiSelections,
15051
15174
  activeLockedId,
@@ -15082,12 +15205,6 @@ var AppStateDelta = class _AppStateDelta {
15082
15205
  "lockedMultiSelections",
15083
15206
  (prevValue) => prevValue ?? {}
15084
15207
  );
15085
- Delta.diffObjects(
15086
- deleted,
15087
- inserted,
15088
- "activeLockedId",
15089
- (prevValue) => prevValue ?? null
15090
- );
15091
15208
  } catch (e) {
15092
15209
  console.error(`Couldn't postprocess appstate change deltas.`);
15093
15210
  if (isTestEnv8() || isDevEnv7()) {
@@ -15166,13 +15283,17 @@ var ElementsDelta = class _ElementsDelta {
15166
15283
  static satisfiesCommmonInvariants = ({
15167
15284
  deleted,
15168
15285
  inserted
15169
- }) => !!(deleted.version && inserted.version && // versions are required integers
15170
- Number.isInteger(deleted.version) && Number.isInteger(inserted.version) && // versions should be positive, zero included
15286
+ }) => !!// versions are required integers
15287
+ (Number.isInteger(deleted.version) && Number.isInteger(inserted.version) && // versions should be positive, zero included
15171
15288
  deleted.version >= 0 && inserted.version >= 0 && // versions should never be the same
15172
15289
  deleted.version !== inserted.version);
15290
+ static satisfiesUniqueInvariants = (elementsDelta, id) => {
15291
+ const { added, removed, updated } = elementsDelta;
15292
+ return [added[id], removed[id], updated[id]].filter(Boolean).length === 1;
15293
+ };
15173
15294
  static validate(elementsDelta, type, satifiesSpecialInvariants) {
15174
15295
  for (const [id, delta] of Object.entries(elementsDelta[type])) {
15175
- if (!this.satisfiesCommmonInvariants(delta) || !satifiesSpecialInvariants(delta)) {
15296
+ if (!this.satisfiesCommmonInvariants(delta) || !this.satisfiesUniqueInvariants(elementsDelta, id) || !satifiesSpecialInvariants(delta)) {
15176
15297
  console.error(
15177
15298
  `Broken invariant for "${type}" delta, element "${id}", delta:`,
15178
15299
  delta
@@ -15199,7 +15320,7 @@ var ElementsDelta = class _ElementsDelta {
15199
15320
  for (const prevElement of prevElements.values()) {
15200
15321
  const nextElement = nextElements.get(prevElement.id);
15201
15322
  if (!nextElement) {
15202
- const deleted = { ...prevElement, isDeleted: false };
15323
+ const deleted = { ...prevElement };
15203
15324
  const inserted = {
15204
15325
  isDeleted: true,
15205
15326
  version: prevElement.version + 1,
@@ -15210,7 +15331,11 @@ var ElementsDelta = class _ElementsDelta {
15210
15331
  inserted,
15211
15332
  _ElementsDelta.stripIrrelevantProps
15212
15333
  );
15213
- removed[prevElement.id] = delta;
15334
+ if (!prevElement.isDeleted) {
15335
+ removed[prevElement.id] = delta;
15336
+ } else {
15337
+ updated[prevElement.id] = delta;
15338
+ }
15214
15339
  }
15215
15340
  }
15216
15341
  for (const nextElement of nextElements.values()) {
@@ -15222,15 +15347,18 @@ var ElementsDelta = class _ElementsDelta {
15222
15347
  versionNonce: randomInteger4()
15223
15348
  };
15224
15349
  const inserted = {
15225
- ...nextElement,
15226
- isDeleted: false
15350
+ ...nextElement
15227
15351
  };
15228
15352
  const delta = Delta.create(
15229
15353
  deleted,
15230
15354
  inserted,
15231
15355
  _ElementsDelta.stripIrrelevantProps
15232
15356
  );
15233
- added[nextElement.id] = delta;
15357
+ if (!nextElement.isDeleted) {
15358
+ added[nextElement.id] = delta;
15359
+ } else {
15360
+ updated[nextElement.id] = delta;
15361
+ }
15234
15362
  continue;
15235
15363
  }
15236
15364
  if (prevElement.versionNonce !== nextElement.versionNonce) {
@@ -15251,9 +15379,7 @@ var ElementsDelta = class _ElementsDelta {
15251
15379
  }
15252
15380
  continue;
15253
15381
  }
15254
- if (!Delta.isEmpty(delta)) {
15255
- updated[nextElement.id] = delta;
15256
- }
15382
+ updated[nextElement.id] = delta;
15257
15383
  }
15258
15384
  }
15259
15385
  return _ElementsDelta.create(added, removed, updated);
@@ -15264,8 +15390,8 @@ var ElementsDelta = class _ElementsDelta {
15264
15390
  inverse() {
15265
15391
  const inverseInternal = (deltas) => {
15266
15392
  const inversedDeltas = {};
15267
- for (const [id, delta] of Object.entries(deltas)) {
15268
- inversedDeltas[id] = Delta.create(delta.inserted, delta.deleted);
15393
+ for (const [id, { inserted, deleted }] of Object.entries(deltas)) {
15394
+ inversedDeltas[id] = Delta.create({ ...inserted }, { ...deleted });
15269
15395
  }
15270
15396
  return inversedDeltas;
15271
15397
  };
@@ -15343,26 +15469,30 @@ var ElementsDelta = class _ElementsDelta {
15343
15469
  // redistribute the deltas as `isDeleted` could have been updated
15344
15470
  });
15345
15471
  }
15346
- applyTo(elements, snapshot = StoreSnapshot.empty().elements, options = {
15347
- excludedProperties: /* @__PURE__ */ new Set()
15348
- }) {
15472
+ applyTo(elements, snapshot = StoreSnapshot.empty().elements, options) {
15349
15473
  let nextElements = new Map(elements);
15350
15474
  let changedElements;
15351
15475
  const flags = {
15352
15476
  containsVisibleDifference: false,
15353
- containsZindexDifference: false
15477
+ containsZindexDifference: false,
15478
+ applyDirection: void 0
15354
15479
  };
15355
15480
  try {
15356
15481
  const applyDeltas = _ElementsDelta.createApplier(
15482
+ elements,
15357
15483
  nextElements,
15358
15484
  snapshot,
15359
- options,
15360
- flags
15485
+ flags,
15486
+ options
15361
15487
  );
15362
15488
  const addedElements = applyDeltas(this.added);
15363
15489
  const removedElements = applyDeltas(this.removed);
15364
15490
  const updatedElements = applyDeltas(this.updated);
15365
- const affectedElements = this.resolveConflicts(elements, nextElements);
15491
+ const affectedElements = this.resolveConflicts(
15492
+ elements,
15493
+ nextElements,
15494
+ flags.applyDirection
15495
+ );
15366
15496
  changedElements = new Map([
15367
15497
  ...addedElements,
15368
15498
  ...removedElements,
@@ -15382,9 +15512,7 @@ var ElementsDelta = class _ElementsDelta {
15382
15512
  changedElements,
15383
15513
  flags
15384
15514
  );
15385
- const tempScene = new Scene(nextElements);
15386
- _ElementsDelta.redrawTextBoundingBoxes(tempScene, changedElements);
15387
- _ElementsDelta.redrawBoundArrows(tempScene, changedElements);
15515
+ _ElementsDelta.redrawElements(nextElements, changedElements);
15388
15516
  } catch (e) {
15389
15517
  console.error(
15390
15518
  `Couldn't mutate elements after applying elements change`,
@@ -15397,7 +15525,82 @@ var ElementsDelta = class _ElementsDelta {
15397
15525
  return [nextElements, flags.containsVisibleDifference];
15398
15526
  }
15399
15527
  }
15400
- static createApplier = (nextElements, snapshot, options, flags) => (deltas) => {
15528
+ squash(delta) {
15529
+ if (delta.isEmpty()) {
15530
+ return this;
15531
+ }
15532
+ const { added, removed, updated } = delta;
15533
+ const mergeBoundElements = (prevDelta, nextDelta) => {
15534
+ const mergedDeletedBoundElements = Delta.mergeArrays(
15535
+ prevDelta.deleted.boundElements ?? [],
15536
+ nextDelta.deleted.boundElements ?? [],
15537
+ void 0,
15538
+ (x) => x.id
15539
+ ) ?? [];
15540
+ const mergedInsertedBoundElements = Delta.mergeArrays(
15541
+ prevDelta.inserted.boundElements ?? [],
15542
+ nextDelta.inserted.boundElements ?? [],
15543
+ void 0,
15544
+ (x) => x.id
15545
+ ) ?? [];
15546
+ if (!mergedDeletedBoundElements.length && !mergedInsertedBoundElements.length) {
15547
+ return;
15548
+ }
15549
+ return Delta.create(
15550
+ {
15551
+ boundElements: mergedDeletedBoundElements
15552
+ },
15553
+ {
15554
+ boundElements: mergedInsertedBoundElements
15555
+ }
15556
+ );
15557
+ };
15558
+ for (const [id, nextDelta] of Object.entries(added)) {
15559
+ const prevDelta = this.added[id] ?? this.removed[id] ?? this.updated[id];
15560
+ if (!prevDelta) {
15561
+ this.added[id] = nextDelta;
15562
+ } else {
15563
+ const mergedDelta = mergeBoundElements(prevDelta, nextDelta);
15564
+ delete this.removed[id];
15565
+ delete this.updated[id];
15566
+ this.added[id] = Delta.merge(prevDelta, nextDelta, mergedDelta);
15567
+ }
15568
+ }
15569
+ for (const [id, nextDelta] of Object.entries(removed)) {
15570
+ const prevDelta = this.added[id] ?? this.removed[id] ?? this.updated[id];
15571
+ if (!prevDelta) {
15572
+ this.removed[id] = nextDelta;
15573
+ } else {
15574
+ const mergedDelta = mergeBoundElements(prevDelta, nextDelta);
15575
+ delete this.added[id];
15576
+ delete this.updated[id];
15577
+ this.removed[id] = Delta.merge(prevDelta, nextDelta, mergedDelta);
15578
+ }
15579
+ }
15580
+ for (const [id, nextDelta] of Object.entries(updated)) {
15581
+ const prevDelta = this.added[id] ?? this.removed[id] ?? this.updated[id];
15582
+ if (!prevDelta) {
15583
+ this.updated[id] = nextDelta;
15584
+ } else {
15585
+ const mergedDelta = mergeBoundElements(prevDelta, nextDelta);
15586
+ const updatedDelta = Delta.merge(prevDelta, nextDelta, mergedDelta);
15587
+ if (prevDelta === this.added[id]) {
15588
+ this.added[id] = updatedDelta;
15589
+ } else if (prevDelta === this.removed[id]) {
15590
+ this.removed[id] = updatedDelta;
15591
+ } else {
15592
+ this.updated[id] = updatedDelta;
15593
+ }
15594
+ }
15595
+ }
15596
+ if (isTestEnv8() || isDevEnv7()) {
15597
+ _ElementsDelta.validate(this, "added", _ElementsDelta.satisfiesAddition);
15598
+ _ElementsDelta.validate(this, "removed", _ElementsDelta.satisfiesRemoval);
15599
+ _ElementsDelta.validate(this, "updated", _ElementsDelta.satisfiesUpdate);
15600
+ }
15601
+ return this;
15602
+ }
15603
+ static createApplier = (prevElements, nextElements, snapshot, flags, options) => (deltas) => {
15401
15604
  const getElement = _ElementsDelta.createGetter(
15402
15605
  nextElements,
15403
15606
  snapshot,
@@ -15406,14 +15609,20 @@ var ElementsDelta = class _ElementsDelta {
15406
15609
  return Object.entries(deltas).reduce((acc, [id, delta]) => {
15407
15610
  const element = getElement(id, delta.inserted);
15408
15611
  if (element) {
15409
- const newElement2 = _ElementsDelta.applyDelta(
15612
+ const nextElement = _ElementsDelta.applyDelta(
15410
15613
  element,
15411
15614
  delta,
15412
- options,
15413
- flags
15615
+ flags,
15616
+ options
15414
15617
  );
15415
- nextElements.set(newElement2.id, newElement2);
15416
- acc.set(newElement2.id, newElement2);
15618
+ nextElements.set(nextElement.id, nextElement);
15619
+ acc.set(nextElement.id, nextElement);
15620
+ if (!flags.applyDirection) {
15621
+ const prevElement = prevElements.get(id);
15622
+ if (prevElement) {
15623
+ flags.applyDirection = prevElement.version > nextElement.version ? "backward" : "forward";
15624
+ }
15625
+ }
15417
15626
  }
15418
15627
  return acc;
15419
15628
  }, /* @__PURE__ */ new Map());
@@ -15438,13 +15647,13 @@ var ElementsDelta = class _ElementsDelta {
15438
15647
  }
15439
15648
  return element;
15440
15649
  };
15441
- static applyDelta(element, delta, options, flags) {
15650
+ static applyDelta(element, delta, flags, options) {
15442
15651
  const directlyApplicablePartial = {};
15443
15652
  for (const key of Object.keys(delta.inserted)) {
15444
15653
  if (key === "boundElements") {
15445
15654
  continue;
15446
15655
  }
15447
- if (options.excludedProperties.has(key)) {
15656
+ if (options?.excludedProperties?.has(key)) {
15448
15657
  continue;
15449
15658
  }
15450
15659
  const value = delta.inserted[key];
@@ -15472,7 +15681,7 @@ var ElementsDelta = class _ElementsDelta {
15472
15681
  if (!flags.containsZindexDifference) {
15473
15682
  flags.containsZindexDifference = delta.deleted.index !== delta.inserted.index;
15474
15683
  }
15475
- return newElementWith(element, directlyApplicablePartial);
15684
+ return newElementWith(element, directlyApplicablePartial, true);
15476
15685
  }
15477
15686
  /**
15478
15687
  * Check for visible changes regardless of whether they were removed, added or updated.
@@ -15497,25 +15706,32 @@ var ElementsDelta = class _ElementsDelta {
15497
15706
  *
15498
15707
  * @returns all elements affected by the conflict resolution
15499
15708
  */
15500
- resolveConflicts(prevElements, nextElements) {
15709
+ resolveConflicts(prevElements, nextElements, applyDirection = "forward") {
15501
15710
  const nextAffectedElements = /* @__PURE__ */ new Map();
15502
15711
  const updater = (element, updates) => {
15503
15712
  const nextElement = nextElements.get(element.id);
15504
15713
  if (!nextElement) {
15505
15714
  return;
15506
15715
  }
15716
+ const prevElement = prevElements.get(element.id);
15717
+ const nextVersion = applyDirection === "forward" ? nextElement.version + 1 : nextElement.version - 1;
15718
+ const elementUpdates = updates;
15507
15719
  let affectedElement;
15508
- if (prevElements.get(element.id) === nextElement) {
15720
+ if (prevElement === nextElement) {
15509
15721
  affectedElement = newElementWith(
15510
15722
  nextElement,
15511
- updates
15723
+ {
15724
+ ...elementUpdates,
15725
+ version: nextVersion
15726
+ },
15727
+ true
15512
15728
  );
15513
15729
  } else {
15514
- affectedElement = mutateElement(
15515
- nextElement,
15516
- nextElements,
15517
- updates
15518
- );
15730
+ affectedElement = mutateElement(nextElement, nextElements, {
15731
+ ...elementUpdates,
15732
+ // don't modify the version further, if it's already different
15733
+ version: prevElement?.version !== nextElement.version ? nextElement.version : nextVersion
15734
+ });
15519
15735
  }
15520
15736
  nextAffectedElements.set(affectedElement.id, affectedElement);
15521
15737
  nextElements.set(affectedElement.id, affectedElement);
@@ -15540,19 +15756,10 @@ var ElementsDelta = class _ElementsDelta {
15540
15756
  const prevAffectedElements = new Map(
15541
15757
  Array.from(prevElements).filter(([id]) => nextAffectedElements.has(id))
15542
15758
  );
15543
- const { added, removed, updated } = _ElementsDelta.calculate(
15544
- prevAffectedElements,
15545
- nextAffectedElements
15759
+ this.squash(
15760
+ // technically we could do better here if perf. would become an issue
15761
+ _ElementsDelta.calculate(prevAffectedElements, nextAffectedElements)
15546
15762
  );
15547
- for (const [id, delta] of Object.entries(added)) {
15548
- this.added[id] = delta;
15549
- }
15550
- for (const [id, delta] of Object.entries(removed)) {
15551
- this.removed[id] = delta;
15552
- }
15553
- for (const [id, delta] of Object.entries(updated)) {
15554
- this.updated[id] = delta;
15555
- }
15556
15763
  return nextAffectedElements;
15557
15764
  }
15558
15765
  /**
@@ -15587,6 +15794,20 @@ var ElementsDelta = class _ElementsDelta {
15587
15794
  );
15588
15795
  BindableElement.rebindAffected(nextElements, nextElement(), updater);
15589
15796
  }
15797
+ static redrawElements(nextElements, changedElements) {
15798
+ try {
15799
+ const tempScene = new Scene(nextElements, { skipValidation: true });
15800
+ _ElementsDelta.redrawTextBoundingBoxes(tempScene, changedElements);
15801
+ _ElementsDelta.redrawBoundArrows(tempScene, changedElements);
15802
+ } catch (e) {
15803
+ console.error(`Couldn't redraw elements`, e);
15804
+ if (isTestEnv8() || isDevEnv7()) {
15805
+ throw e;
15806
+ }
15807
+ } finally {
15808
+ return nextElements;
15809
+ }
15810
+ }
15590
15811
  static redrawTextBoundingBoxes(scene, changed) {
15591
15812
  const elements = scene.getNonDeletedElementsMap();
15592
15813
  const boxesToRedraw = /* @__PURE__ */ new Map();
@@ -15679,10 +15900,14 @@ var ElementsDelta = class _ElementsDelta {
15679
15900
 
15680
15901
  // src/distribute.ts
15681
15902
  init_define_import_meta_env();
15682
- var distributeElements = (selectedElements, elementsMap, distribution) => {
15903
+ var distributeElements = (selectedElements, elementsMap, distribution, appState) => {
15683
15904
  const [start, mid, end, extent] = distribution.axis === "x" ? ["minX", "midX", "maxX", "width"] : ["minY", "midY", "maxY", "height"];
15684
15905
  const bounds = getCommonBoundingBox(selectedElements);
15685
- const groups = getMaximumGroups(selectedElements, elementsMap).map((group) => [group, getCommonBoundingBox(group)]).sort((a2, b2) => a2[1][mid] - b2[1][mid]);
15906
+ const groups = getSelectedElementsByGroup(
15907
+ selectedElements,
15908
+ elementsMap,
15909
+ appState
15910
+ ).map((group) => [group, getCommonBoundingBox(group)]).sort((a2, b2) => a2[1][mid] - b2[1][mid]);
15686
15911
  let span = 0;
15687
15912
  for (const group of groups) {
15688
15913
  span += group[1][extent];
@@ -16325,7 +16550,7 @@ var newImageElement = (opts) => {
16325
16550
 
16326
16551
  // src/embeddable.ts
16327
16552
  var embeddedLinkCache = /* @__PURE__ */ new Map();
16328
- var RE_YOUTUBE = /^(?:http(?:s)?:\/\/)?(?:www\.)?youtu(?:be\.com|\.be)\/(embed\/|watch\?v=|shorts\/|playlist\?list=|embed\/videoseries\?list=)?([a-zA-Z0-9_-]+)(?:\?t=|&t=|\?start=|&start=)?([a-zA-Z0-9_-]+)?[^\s]*$/;
16553
+ var RE_YOUTUBE = /^(?:http(?:s)?:\/\/)?(?:www\.)?youtu(?:be\.com|\.be)\/(embed\/|watch\?v=|shorts\/|playlist\?list=|embed\/videoseries\?list=)?([a-zA-Z0-9_-]+)/;
16329
16554
  var RE_VIMEO = /^(?:http(?:s)?:\/\/)?(?:(?:w){3}\.)?(?:player\.)?vimeo\.com\/(?:video\/)?([^?\s]+)(?:\?.*)?$/;
16330
16555
  var RE_FIGMA = /^https:\/\/(?:www\.)?figma\.com/;
16331
16556
  var RE_GH_GIST = /^https:\/\/gist\.github\.com\/([\w_-]+)\/([\w_-]+)/;
@@ -16338,6 +16563,28 @@ var RE_GENERIC_EMBED = /^<(?:iframe|blockquote)[\s\S]*?\s(?:src|href)=["']([^"']
16338
16563
  var RE_GIPHY = /giphy.com\/(?:clips|embed|gifs)\/[a-zA-Z0-9]*?-?([a-zA-Z0-9]+)(?:[^a-zA-Z0-9]|$)/;
16339
16564
  var RE_REDDIT = /^(?:http(?:s)?:\/\/)?(?:www\.)?reddit\.com\/r\/([a-zA-Z0-9_]+)\/comments\/([a-zA-Z0-9_]+)\/([a-zA-Z0-9_]+)\/?(?:\?[^#\s]*)?(?:#[^\s]*)?$/;
16340
16565
  var RE_REDDIT_EMBED = /^<blockquote[\s\S]*?\shref=["'](https?:\/\/(?:www\.)?reddit\.com\/[^"']*)/i;
16566
+ var parseYouTubeTimestamp = (url) => {
16567
+ let timeParam;
16568
+ try {
16569
+ const urlObj = new URL(url.startsWith("http") ? url : `https://${url}`);
16570
+ timeParam = urlObj.searchParams.get("t") || urlObj.searchParams.get("start");
16571
+ } catch (error) {
16572
+ const timeMatch2 = url.match(/[?&#](?:t|start)=([^&#\s]+)/);
16573
+ timeParam = timeMatch2?.[1];
16574
+ }
16575
+ if (!timeParam) {
16576
+ return 0;
16577
+ }
16578
+ if (/^\d+$/.test(timeParam)) {
16579
+ return parseInt(timeParam, 10);
16580
+ }
16581
+ const timeMatch = timeParam.match(/^(?:(\d+)h)?(?:(\d+)m)?(?:(\d+)s)?$/);
16582
+ if (!timeMatch) {
16583
+ return 0;
16584
+ }
16585
+ const [, hours = "0", minutes = "0", seconds = "0"] = timeMatch;
16586
+ return parseInt(hours) * 3600 + parseInt(minutes) * 60 + parseInt(seconds);
16587
+ };
16341
16588
  var ALLOWED_DOMAINS = /* @__PURE__ */ new Set([
16342
16589
  "youtube.com",
16343
16590
  "youtu.be",
@@ -16386,7 +16633,8 @@ var getEmbedLink = (link) => {
16386
16633
  let aspectRatio = { w: 560, h: 840 };
16387
16634
  const ytLink = link.match(RE_YOUTUBE);
16388
16635
  if (ytLink?.[2]) {
16389
- const time = ytLink[3] ? `&start=${ytLink[3]}` : ``;
16636
+ const startTime = parseYouTubeTimestamp(originalLink);
16637
+ const time = startTime > 0 ? `&start=${startTime}` : ``;
16390
16638
  const isPortrait = link.includes("shorts");
16391
16639
  type = "video";
16392
16640
  switch (ytLink[1]) {
@@ -18371,7 +18619,7 @@ var getTransformHandles = (element, zoom, elementsMap, pointerType = "mouse", om
18371
18619
  );
18372
18620
  };
18373
18621
  var shouldShowBoundingBox = (elements, appState) => {
18374
- if (appState.editingLinearElement) {
18622
+ if (appState.selectedLinearElement?.isEditing) {
18375
18623
  return false;
18376
18624
  }
18377
18625
  if (elements.length > 1) {
@@ -19119,6 +19367,7 @@ export {
19119
19367
  getRootElements,
19120
19368
  getSceneVersion,
19121
19369
  getSelectedElements,
19370
+ getSelectedElementsByGroup,
19122
19371
  getSelectedGroupForElement,
19123
19372
  getSelectedGroupIdForElement,
19124
19373
  getSelectedGroupIds,