@excalidraw/element 0.18.0-c65b684e9 → 0.18.0-c6f8ef9

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
@@ -12849,7 +12849,6 @@ import {
12849
12849
  arrayToMap as arrayToMap10,
12850
12850
  arrayToObject,
12851
12851
  assertNever as assertNever4,
12852
- invariant as invariant8,
12853
12852
  isDevEnv as isDevEnv7,
12854
12853
  isShallowEqual as isShallowEqual2,
12855
12854
  isTestEnv as isTestEnv8,
@@ -13496,7 +13495,7 @@ var EphemeralIncrement = class extends StoreIncrement {
13496
13495
  this.change = change;
13497
13496
  }
13498
13497
  };
13499
- var StoreDelta = class {
13498
+ var StoreDelta = class _StoreDelta {
13500
13499
  constructor(id, elements, appState) {
13501
13500
  this.id = id;
13502
13501
  this.elements = elements;
@@ -13534,10 +13533,23 @@ var StoreDelta = class {
13534
13533
  */
13535
13534
  static load({
13536
13535
  id,
13537
- elements: { added, removed, updated }
13536
+ elements: { added, removed, updated },
13537
+ appState: { delta: appStateDelta }
13538
13538
  }) {
13539
13539
  const elements = ElementsDelta.create(added, removed, updated);
13540
- 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;
13541
13553
  }
13542
13554
  /**
13543
13555
  * Inverse store delta, creates new instance of `StoreDelta`.
@@ -13548,9 +13560,7 @@ var StoreDelta = class {
13548
13560
  /**
13549
13561
  * Apply the delta to the passed elements and appState, does not modify the snapshot.
13550
13562
  */
13551
- static applyTo(delta, elements, appState, options = {
13552
- excludedProperties: /* @__PURE__ */ new Set()
13553
- }) {
13563
+ static applyTo(delta, elements, appState, options) {
13554
13564
  const [nextElements, elementsContainVisibleChange] = delta.elements.applyTo(
13555
13565
  elements,
13556
13566
  StoreSnapshot.empty().elements,
@@ -13576,6 +13586,9 @@ var StoreDelta = class {
13576
13586
  }
13577
13587
  );
13578
13588
  }
13589
+ static empty() {
13590
+ return _StoreDelta.create(ElementsDelta.empty(), AppStateDelta.empty());
13591
+ }
13579
13592
  isEmpty() {
13580
13593
  return this.elements.isEmpty() && this.appState.isEmpty();
13581
13594
  }
@@ -13816,8 +13829,7 @@ var getDefaultObservedAppState = () => {
13816
13829
  viewBackgroundColor: COLOR_PALETTE2.white,
13817
13830
  selectedElementIds: {},
13818
13831
  selectedGroupIds: {},
13819
- selectedLinearElementId: null,
13820
- selectedLinearElementIsEditing: null,
13832
+ selectedLinearElement: null,
13821
13833
  croppingElementId: null,
13822
13834
  activeLockedId: null,
13823
13835
  lockedMultiSelections: {}
@@ -13833,8 +13845,10 @@ var getObservedAppState = (appState) => {
13833
13845
  croppingElementId: appState.croppingElementId,
13834
13846
  activeLockedId: appState.activeLockedId,
13835
13847
  lockedMultiSelections: appState.lockedMultiSelections,
13836
- selectedLinearElementId: appState.selectedLinearElement?.elementId ?? appState.selectedLinearElementId ?? null,
13837
- selectedLinearElementIsEditing: appState.selectedLinearElement?.isEditing ?? appState.selectedLinearElementIsEditing ?? null
13848
+ selectedLinearElement: appState.selectedLinearElement ? {
13849
+ elementId: appState.selectedLinearElement.elementId,
13850
+ isEditing: !!appState.selectedLinearElement.isEditing
13851
+ } : null
13838
13852
  };
13839
13853
  Reflect.defineProperty(observedAppState, hiddenObservedAppStateProp, {
13840
13854
  value: true,
@@ -14398,9 +14412,9 @@ var Scene = class {
14398
14412
  getFramesIncludingDeleted() {
14399
14413
  return this.frames;
14400
14414
  }
14401
- constructor(elements = null) {
14415
+ constructor(elements = null, options) {
14402
14416
  if (elements) {
14403
- this.replaceAllElements(elements);
14417
+ this.replaceAllElements(elements, options);
14404
14418
  }
14405
14419
  }
14406
14420
  getSelectedElements(opts) {
@@ -14465,10 +14479,12 @@ var Scene = class {
14465
14479
  }
14466
14480
  return didChange;
14467
14481
  }
14468
- replaceAllElements(nextElements) {
14482
+ replaceAllElements(nextElements, options) {
14469
14483
  const _nextElements = toArray(nextElements);
14470
14484
  const nextFrameLikes = [];
14471
- validateIndicesThrottled(_nextElements);
14485
+ if (!options?.skipValidation) {
14486
+ validateIndicesThrottled(_nextElements);
14487
+ }
14472
14488
  this.elements = syncInvalidIndices2(_nextElements);
14473
14489
  this.elementsMap.clear();
14474
14490
  this.elements.forEach((element) => {
@@ -14641,16 +14657,16 @@ var Delta = class _Delta {
14641
14657
  /**
14642
14658
  * Merges two deltas into a new one.
14643
14659
  */
14644
- static merge(delta1, delta2) {
14660
+ static merge(delta1, delta2, delta3 = _Delta.empty()) {
14645
14661
  return _Delta.create(
14646
- { ...delta1.deleted, ...delta2.deleted },
14647
- { ...delta1.inserted, ...delta2.inserted }
14662
+ { ...delta1.deleted, ...delta2.deleted, ...delta3.deleted },
14663
+ { ...delta1.inserted, ...delta2.inserted, ...delta3.inserted }
14648
14664
  );
14649
14665
  }
14650
14666
  /**
14651
14667
  * Merges deleted and inserted object partials.
14652
14668
  */
14653
- static mergeObjects(prev, added, removed) {
14669
+ static mergeObjects(prev, added, removed = {}) {
14654
14670
  const cloned = { ...prev };
14655
14671
  for (const key of Object.keys(removed)) {
14656
14672
  delete cloned[key];
@@ -14871,6 +14887,9 @@ var AppStateDelta = class _AppStateDelta {
14871
14887
  constructor(delta) {
14872
14888
  this.delta = delta;
14873
14889
  }
14890
+ static create(delta) {
14891
+ return new _AppStateDelta(delta);
14892
+ }
14874
14893
  static calculate(prevAppState, nextAppState) {
14875
14894
  const delta = Delta.calculate(
14876
14895
  prevAppState,
@@ -14893,65 +14912,97 @@ var AppStateDelta = class _AppStateDelta {
14893
14912
  return new _AppStateDelta(inversedDelta);
14894
14913
  }
14895
14914
  squash(delta) {
14896
- this.delta = Delta.merge(this.delta, delta.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
+ );
14897
14961
  return this;
14898
14962
  }
14899
14963
  applyTo(appState, nextElements) {
14900
14964
  try {
14901
14965
  const {
14902
- selectedElementIds: removedSelectedElementIds = {},
14903
- selectedGroupIds: removedSelectedGroupIds = {}
14966
+ selectedElementIds: deletedSelectedElementIds = {},
14967
+ selectedGroupIds: deletedSelectedGroupIds = {},
14968
+ lockedMultiSelections: deletedLockedMultiSelections = {}
14904
14969
  } = this.delta.deleted;
14905
14970
  const {
14906
- selectedElementIds: addedSelectedElementIds = {},
14907
- selectedGroupIds: addedSelectedGroupIds = {},
14908
- selectedLinearElementId,
14909
- selectedLinearElementIsEditing,
14971
+ selectedElementIds: insertedSelectedElementIds = {},
14972
+ selectedGroupIds: insertedSelectedGroupIds = {},
14973
+ lockedMultiSelections: insertedLockedMultiSelections = {},
14974
+ selectedLinearElement: insertedSelectedLinearElement,
14910
14975
  ...directlyApplicablePartial
14911
14976
  } = this.delta.inserted;
14912
14977
  const mergedSelectedElementIds = Delta.mergeObjects(
14913
14978
  appState.selectedElementIds,
14914
- addedSelectedElementIds,
14915
- removedSelectedElementIds
14979
+ insertedSelectedElementIds,
14980
+ deletedSelectedElementIds
14916
14981
  );
14917
14982
  const mergedSelectedGroupIds = Delta.mergeObjects(
14918
14983
  appState.selectedGroupIds,
14919
- addedSelectedGroupIds,
14920
- removedSelectedGroupIds
14984
+ insertedSelectedGroupIds,
14985
+ deletedSelectedGroupIds
14921
14986
  );
14922
- let selectedLinearElement = appState.selectedLinearElement;
14923
- if (selectedLinearElementId === null) {
14924
- selectedLinearElement = null;
14925
- } else if (selectedLinearElementId && nextElements.has(selectedLinearElementId)) {
14926
- selectedLinearElement = new LinearElementEditor(
14927
- nextElements.get(
14928
- selectedLinearElementId
14929
- ),
14930
- nextElements,
14931
- selectedLinearElementIsEditing === true
14932
- // Can be unknown which is defaulted to false
14933
- );
14934
- }
14935
- if (
14936
- // Value being 'null' is equivaluent to unknown in this case because it only gets set
14937
- // to null when 'selectedLinearElementId' is set to null
14938
- selectedLinearElementIsEditing != null
14939
- ) {
14940
- invariant8(
14941
- selectedLinearElement,
14942
- `selectedLinearElement is null when selectedLinearElementIsEditing is set to ${selectedLinearElementIsEditing}`
14943
- );
14944
- selectedLinearElement = {
14945
- ...selectedLinearElement,
14946
- isEditing: selectedLinearElementIsEditing
14947
- };
14948
- }
14987
+ const mergedLockedMultiSelections = Delta.mergeObjects(
14988
+ appState.lockedMultiSelections,
14989
+ insertedLockedMultiSelections,
14990
+ deletedLockedMultiSelections
14991
+ );
14992
+ const selectedLinearElement = insertedSelectedLinearElement && nextElements.has(insertedSelectedLinearElement.elementId) ? new LinearElementEditor(
14993
+ nextElements.get(
14994
+ insertedSelectedLinearElement.elementId
14995
+ ),
14996
+ nextElements,
14997
+ insertedSelectedLinearElement.isEditing
14998
+ ) : null;
14949
14999
  const nextAppState = {
14950
15000
  ...appState,
14951
15001
  ...directlyApplicablePartial,
14952
15002
  selectedElementIds: mergedSelectedElementIds,
14953
15003
  selectedGroupIds: mergedSelectedGroupIds,
14954
- selectedLinearElement
15004
+ lockedMultiSelections: mergedLockedMultiSelections,
15005
+ selectedLinearElement: typeof insertedSelectedLinearElement !== "undefined" ? selectedLinearElement : appState.selectedLinearElement
14955
15006
  };
14956
15007
  const constainsVisibleChanges = this.filterInvisibleChanges(
14957
15008
  appState,
@@ -15041,63 +15092,44 @@ var AppStateDelta = class _AppStateDelta {
15041
15092
  nextAppState[key] = null;
15042
15093
  }
15043
15094
  break;
15044
- case "selectedLinearElementId": {
15045
- const appStateKey = _AppStateDelta.convertToAppStateKey(key);
15046
- const linearElement = nextAppState[appStateKey];
15047
- if (!linearElement) {
15095
+ case "selectedLinearElement":
15096
+ const nextLinearElement = nextAppState[key];
15097
+ if (!nextLinearElement) {
15048
15098
  visibleDifferenceFlag.value = true;
15049
15099
  } else {
15050
- const element = nextElements.get(linearElement.elementId);
15100
+ const element = nextElements.get(nextLinearElement.elementId);
15051
15101
  if (element && !element.isDeleted) {
15052
15102
  visibleDifferenceFlag.value = true;
15053
15103
  } else {
15054
- nextAppState[appStateKey] = null;
15104
+ nextAppState[key] = null;
15055
15105
  }
15056
15106
  }
15057
15107
  break;
15058
- }
15059
- case "selectedLinearElementIsEditing": {
15060
- const prevIsEditing = prevAppState.selectedLinearElement?.isEditing ?? false;
15061
- const nextIsEditing = nextAppState.selectedLinearElement?.isEditing ?? false;
15062
- if (prevIsEditing !== nextIsEditing) {
15063
- visibleDifferenceFlag.value = true;
15064
- }
15065
- break;
15066
- }
15067
- case "lockedMultiSelections": {
15108
+ case "lockedMultiSelections":
15068
15109
  const prevLockedUnits = prevAppState[key] || {};
15069
15110
  const nextLockedUnits = nextAppState[key] || {};
15070
15111
  if (!isShallowEqual2(prevLockedUnits, nextLockedUnits)) {
15071
15112
  visibleDifferenceFlag.value = true;
15072
15113
  }
15073
15114
  break;
15074
- }
15075
- case "activeLockedId": {
15115
+ case "activeLockedId":
15076
15116
  const prevHitLockedId = prevAppState[key] || null;
15077
15117
  const nextHitLockedId = nextAppState[key] || null;
15078
15118
  if (prevHitLockedId !== nextHitLockedId) {
15079
15119
  visibleDifferenceFlag.value = true;
15080
15120
  }
15081
15121
  break;
15082
- }
15083
- default: {
15122
+ default:
15084
15123
  assertNever4(
15085
15124
  key,
15086
15125
  `Unknown ObservedElementsAppState's key "${key}"`,
15087
15126
  true
15088
15127
  );
15089
- }
15090
15128
  }
15091
15129
  }
15092
15130
  }
15093
15131
  return visibleDifferenceFlag.value;
15094
15132
  }
15095
- static convertToAppStateKey(key) {
15096
- switch (key) {
15097
- case "selectedLinearElementId":
15098
- return "selectedLinearElement";
15099
- }
15100
- }
15101
15133
  static filterSelectedElements(selectedElementIds, elements, visibleDifferenceFlag) {
15102
15134
  const ids = Object.keys(selectedElementIds);
15103
15135
  if (!ids.length) {
@@ -15136,8 +15168,7 @@ var AppStateDelta = class _AppStateDelta {
15136
15168
  editingGroupId,
15137
15169
  selectedGroupIds,
15138
15170
  selectedElementIds,
15139
- selectedLinearElementId,
15140
- selectedLinearElementIsEditing,
15171
+ selectedLinearElement,
15141
15172
  croppingElementId,
15142
15173
  lockedMultiSelections,
15143
15174
  activeLockedId,
@@ -15174,12 +15205,6 @@ var AppStateDelta = class _AppStateDelta {
15174
15205
  "lockedMultiSelections",
15175
15206
  (prevValue) => prevValue ?? {}
15176
15207
  );
15177
- Delta.diffObjects(
15178
- deleted,
15179
- inserted,
15180
- "activeLockedId",
15181
- (prevValue) => prevValue ?? null
15182
- );
15183
15208
  } catch (e) {
15184
15209
  console.error(`Couldn't postprocess appstate change deltas.`);
15185
15210
  if (isTestEnv8() || isDevEnv7()) {
@@ -15262,9 +15287,13 @@ var ElementsDelta = class _ElementsDelta {
15262
15287
  Number.isInteger(deleted.version) && Number.isInteger(inserted.version) && // versions should be positive, zero included
15263
15288
  deleted.version >= 0 && inserted.version >= 0 && // versions should never be the same
15264
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
+ };
15265
15294
  static validate(elementsDelta, type, satifiesSpecialInvariants) {
15266
15295
  for (const [id, delta] of Object.entries(elementsDelta[type])) {
15267
- if (!this.satisfiesCommmonInvariants(delta) || !satifiesSpecialInvariants(delta)) {
15296
+ if (!this.satisfiesCommmonInvariants(delta) || !this.satisfiesUniqueInvariants(elementsDelta, id) || !satifiesSpecialInvariants(delta)) {
15268
15297
  console.error(
15269
15298
  `Broken invariant for "${type}" delta, element "${id}", delta:`,
15270
15299
  delta
@@ -15291,7 +15320,7 @@ var ElementsDelta = class _ElementsDelta {
15291
15320
  for (const prevElement of prevElements.values()) {
15292
15321
  const nextElement = nextElements.get(prevElement.id);
15293
15322
  if (!nextElement) {
15294
- const deleted = { ...prevElement, isDeleted: false };
15323
+ const deleted = { ...prevElement };
15295
15324
  const inserted = {
15296
15325
  isDeleted: true,
15297
15326
  version: prevElement.version + 1,
@@ -15302,7 +15331,9 @@ var ElementsDelta = class _ElementsDelta {
15302
15331
  inserted,
15303
15332
  _ElementsDelta.stripIrrelevantProps
15304
15333
  );
15305
- removed[prevElement.id] = delta;
15334
+ if (!prevElement.isDeleted) {
15335
+ removed[prevElement.id] = delta;
15336
+ }
15306
15337
  }
15307
15338
  }
15308
15339
  for (const nextElement of nextElements.values()) {
@@ -15314,15 +15345,16 @@ var ElementsDelta = class _ElementsDelta {
15314
15345
  versionNonce: randomInteger4()
15315
15346
  };
15316
15347
  const inserted = {
15317
- ...nextElement,
15318
- isDeleted: false
15348
+ ...nextElement
15319
15349
  };
15320
15350
  const delta = Delta.create(
15321
15351
  deleted,
15322
15352
  inserted,
15323
15353
  _ElementsDelta.stripIrrelevantProps
15324
15354
  );
15325
- added[nextElement.id] = delta;
15355
+ if (!nextElement.isDeleted) {
15356
+ added[nextElement.id] = delta;
15357
+ }
15326
15358
  continue;
15327
15359
  }
15328
15360
  if (prevElement.versionNonce !== nextElement.versionNonce) {
@@ -15343,7 +15375,11 @@ var ElementsDelta = class _ElementsDelta {
15343
15375
  }
15344
15376
  continue;
15345
15377
  }
15346
- if (!Delta.isEmpty(delta)) {
15378
+ const strippedDeleted = _ElementsDelta.stripVersionProps(delta.deleted);
15379
+ const strippedInserted = _ElementsDelta.stripVersionProps(
15380
+ delta.inserted
15381
+ );
15382
+ if (Delta.isInnerDifferent(strippedDeleted, strippedInserted, true)) {
15347
15383
  updated[nextElement.id] = delta;
15348
15384
  }
15349
15385
  }
@@ -15421,7 +15457,13 @@ var ElementsDelta = class _ElementsDelta {
15421
15457
  } else {
15422
15458
  latestDelta = delta;
15423
15459
  }
15424
- if (Delta.isInnerDifferent(latestDelta.deleted, latestDelta.inserted)) {
15460
+ const strippedDeleted = _ElementsDelta.stripVersionProps(
15461
+ latestDelta.deleted
15462
+ );
15463
+ const strippedInserted = _ElementsDelta.stripVersionProps(
15464
+ latestDelta.inserted
15465
+ );
15466
+ if (Delta.isInnerDifferent(strippedDeleted, strippedInserted)) {
15425
15467
  modifiedDeltas[id] = latestDelta;
15426
15468
  }
15427
15469
  }
@@ -15435,26 +15477,30 @@ var ElementsDelta = class _ElementsDelta {
15435
15477
  // redistribute the deltas as `isDeleted` could have been updated
15436
15478
  });
15437
15479
  }
15438
- applyTo(elements, snapshot = StoreSnapshot.empty().elements, options = {
15439
- excludedProperties: /* @__PURE__ */ new Set()
15440
- }) {
15480
+ applyTo(elements, snapshot = StoreSnapshot.empty().elements, options) {
15441
15481
  let nextElements = new Map(elements);
15442
15482
  let changedElements;
15443
15483
  const flags = {
15444
15484
  containsVisibleDifference: false,
15445
- containsZindexDifference: false
15485
+ containsZindexDifference: false,
15486
+ applyDirection: void 0
15446
15487
  };
15447
15488
  try {
15448
15489
  const applyDeltas = _ElementsDelta.createApplier(
15490
+ elements,
15449
15491
  nextElements,
15450
15492
  snapshot,
15451
- options,
15452
- flags
15493
+ flags,
15494
+ options
15453
15495
  );
15454
15496
  const addedElements = applyDeltas(this.added);
15455
15497
  const removedElements = applyDeltas(this.removed);
15456
15498
  const updatedElements = applyDeltas(this.updated);
15457
- const affectedElements = this.resolveConflicts(elements, nextElements);
15499
+ const affectedElements = this.resolveConflicts(
15500
+ elements,
15501
+ nextElements,
15502
+ flags.applyDirection
15503
+ );
15458
15504
  changedElements = new Map([
15459
15505
  ...addedElements,
15460
15506
  ...removedElements,
@@ -15474,9 +15520,7 @@ var ElementsDelta = class _ElementsDelta {
15474
15520
  changedElements,
15475
15521
  flags
15476
15522
  );
15477
- const tempScene = new Scene(nextElements);
15478
- _ElementsDelta.redrawTextBoundingBoxes(tempScene, changedElements);
15479
- _ElementsDelta.redrawBoundArrows(tempScene, changedElements);
15523
+ _ElementsDelta.redrawElements(nextElements, changedElements);
15480
15524
  } catch (e) {
15481
15525
  console.error(
15482
15526
  `Couldn't mutate elements after applying elements change`,
@@ -15490,34 +15534,81 @@ var ElementsDelta = class _ElementsDelta {
15490
15534
  }
15491
15535
  }
15492
15536
  squash(delta) {
15537
+ if (delta.isEmpty()) {
15538
+ return this;
15539
+ }
15493
15540
  const { added, removed, updated } = delta;
15541
+ const mergeBoundElements = (prevDelta, nextDelta) => {
15542
+ const mergedDeletedBoundElements = Delta.mergeArrays(
15543
+ prevDelta.deleted.boundElements ?? [],
15544
+ nextDelta.deleted.boundElements ?? [],
15545
+ void 0,
15546
+ (x) => x.id
15547
+ ) ?? [];
15548
+ const mergedInsertedBoundElements = Delta.mergeArrays(
15549
+ prevDelta.inserted.boundElements ?? [],
15550
+ nextDelta.inserted.boundElements ?? [],
15551
+ void 0,
15552
+ (x) => x.id
15553
+ ) ?? [];
15554
+ if (!mergedDeletedBoundElements.length && !mergedInsertedBoundElements.length) {
15555
+ return;
15556
+ }
15557
+ return Delta.create(
15558
+ {
15559
+ boundElements: mergedDeletedBoundElements
15560
+ },
15561
+ {
15562
+ boundElements: mergedInsertedBoundElements
15563
+ }
15564
+ );
15565
+ };
15494
15566
  for (const [id, nextDelta] of Object.entries(added)) {
15495
- const prevDelta = this.added[id];
15567
+ const prevDelta = this.added[id] ?? this.removed[id] ?? this.updated[id];
15496
15568
  if (!prevDelta) {
15497
15569
  this.added[id] = nextDelta;
15498
15570
  } else {
15499
- this.added[id] = Delta.merge(prevDelta, nextDelta);
15571
+ const mergedDelta = mergeBoundElements(prevDelta, nextDelta);
15572
+ delete this.removed[id];
15573
+ delete this.updated[id];
15574
+ this.added[id] = Delta.merge(prevDelta, nextDelta, mergedDelta);
15500
15575
  }
15501
15576
  }
15502
15577
  for (const [id, nextDelta] of Object.entries(removed)) {
15503
- const prevDelta = this.removed[id];
15578
+ const prevDelta = this.added[id] ?? this.removed[id] ?? this.updated[id];
15504
15579
  if (!prevDelta) {
15505
15580
  this.removed[id] = nextDelta;
15506
15581
  } else {
15507
- this.removed[id] = Delta.merge(prevDelta, nextDelta);
15582
+ const mergedDelta = mergeBoundElements(prevDelta, nextDelta);
15583
+ delete this.added[id];
15584
+ delete this.updated[id];
15585
+ this.removed[id] = Delta.merge(prevDelta, nextDelta, mergedDelta);
15508
15586
  }
15509
15587
  }
15510
15588
  for (const [id, nextDelta] of Object.entries(updated)) {
15511
- const prevDelta = this.updated[id];
15589
+ const prevDelta = this.added[id] ?? this.removed[id] ?? this.updated[id];
15512
15590
  if (!prevDelta) {
15513
15591
  this.updated[id] = nextDelta;
15514
15592
  } else {
15515
- this.updated[id] = Delta.merge(prevDelta, nextDelta);
15593
+ const mergedDelta = mergeBoundElements(prevDelta, nextDelta);
15594
+ const updatedDelta = Delta.merge(prevDelta, nextDelta, mergedDelta);
15595
+ if (prevDelta === this.added[id]) {
15596
+ this.added[id] = updatedDelta;
15597
+ } else if (prevDelta === this.removed[id]) {
15598
+ this.removed[id] = updatedDelta;
15599
+ } else {
15600
+ this.updated[id] = updatedDelta;
15601
+ }
15516
15602
  }
15517
15603
  }
15604
+ if (isTestEnv8() || isDevEnv7()) {
15605
+ _ElementsDelta.validate(this, "added", _ElementsDelta.satisfiesAddition);
15606
+ _ElementsDelta.validate(this, "removed", _ElementsDelta.satisfiesRemoval);
15607
+ _ElementsDelta.validate(this, "updated", _ElementsDelta.satisfiesUpdate);
15608
+ }
15518
15609
  return this;
15519
15610
  }
15520
- static createApplier = (nextElements, snapshot, options, flags) => (deltas) => {
15611
+ static createApplier = (prevElements, nextElements, snapshot, flags, options) => (deltas) => {
15521
15612
  const getElement = _ElementsDelta.createGetter(
15522
15613
  nextElements,
15523
15614
  snapshot,
@@ -15526,14 +15617,20 @@ var ElementsDelta = class _ElementsDelta {
15526
15617
  return Object.entries(deltas).reduce((acc, [id, delta]) => {
15527
15618
  const element = getElement(id, delta.inserted);
15528
15619
  if (element) {
15529
- const newElement2 = _ElementsDelta.applyDelta(
15620
+ const nextElement = _ElementsDelta.applyDelta(
15530
15621
  element,
15531
15622
  delta,
15532
- options,
15533
- flags
15623
+ flags,
15624
+ options
15534
15625
  );
15535
- nextElements.set(newElement2.id, newElement2);
15536
- acc.set(newElement2.id, newElement2);
15626
+ nextElements.set(nextElement.id, nextElement);
15627
+ acc.set(nextElement.id, nextElement);
15628
+ if (!flags.applyDirection) {
15629
+ const prevElement = prevElements.get(id);
15630
+ if (prevElement) {
15631
+ flags.applyDirection = prevElement.version > nextElement.version ? "backward" : "forward";
15632
+ }
15633
+ }
15537
15634
  }
15538
15635
  return acc;
15539
15636
  }, /* @__PURE__ */ new Map());
@@ -15558,13 +15655,13 @@ var ElementsDelta = class _ElementsDelta {
15558
15655
  }
15559
15656
  return element;
15560
15657
  };
15561
- static applyDelta(element, delta, options, flags) {
15658
+ static applyDelta(element, delta, flags, options) {
15562
15659
  const directlyApplicablePartial = {};
15563
15660
  for (const key of Object.keys(delta.inserted)) {
15564
15661
  if (key === "boundElements") {
15565
15662
  continue;
15566
15663
  }
15567
- if (options.excludedProperties.has(key)) {
15664
+ if (options?.excludedProperties?.has(key)) {
15568
15665
  continue;
15569
15666
  }
15570
15667
  const value = delta.inserted[key];
@@ -15592,7 +15689,7 @@ var ElementsDelta = class _ElementsDelta {
15592
15689
  if (!flags.containsZindexDifference) {
15593
15690
  flags.containsZindexDifference = delta.deleted.index !== delta.inserted.index;
15594
15691
  }
15595
- return newElementWith(element, directlyApplicablePartial);
15692
+ return newElementWith(element, directlyApplicablePartial, true);
15596
15693
  }
15597
15694
  /**
15598
15695
  * Check for visible changes regardless of whether they were removed, added or updated.
@@ -15617,25 +15714,32 @@ var ElementsDelta = class _ElementsDelta {
15617
15714
  *
15618
15715
  * @returns all elements affected by the conflict resolution
15619
15716
  */
15620
- resolveConflicts(prevElements, nextElements) {
15717
+ resolveConflicts(prevElements, nextElements, applyDirection = "forward") {
15621
15718
  const nextAffectedElements = /* @__PURE__ */ new Map();
15622
15719
  const updater = (element, updates) => {
15623
15720
  const nextElement = nextElements.get(element.id);
15624
15721
  if (!nextElement) {
15625
15722
  return;
15626
15723
  }
15724
+ const prevElement = prevElements.get(element.id);
15725
+ const nextVersion = applyDirection === "forward" ? nextElement.version + 1 : nextElement.version - 1;
15726
+ const elementUpdates = updates;
15627
15727
  let affectedElement;
15628
- if (prevElements.get(element.id) === nextElement) {
15728
+ if (prevElement === nextElement) {
15629
15729
  affectedElement = newElementWith(
15630
15730
  nextElement,
15631
- updates
15731
+ {
15732
+ ...elementUpdates,
15733
+ version: nextVersion
15734
+ },
15735
+ true
15632
15736
  );
15633
15737
  } else {
15634
- affectedElement = mutateElement(
15635
- nextElement,
15636
- nextElements,
15637
- updates
15638
- );
15738
+ affectedElement = mutateElement(nextElement, nextElements, {
15739
+ ...elementUpdates,
15740
+ // don't modify the version further, if it's already different
15741
+ version: prevElement?.version !== nextElement.version ? nextElement.version : nextVersion
15742
+ });
15639
15743
  }
15640
15744
  nextAffectedElements.set(affectedElement.id, affectedElement);
15641
15745
  nextElements.set(affectedElement.id, affectedElement);
@@ -15698,6 +15802,20 @@ var ElementsDelta = class _ElementsDelta {
15698
15802
  );
15699
15803
  BindableElement.rebindAffected(nextElements, nextElement(), updater);
15700
15804
  }
15805
+ static redrawElements(nextElements, changedElements) {
15806
+ try {
15807
+ const tempScene = new Scene(nextElements, { skipValidation: true });
15808
+ _ElementsDelta.redrawTextBoundingBoxes(tempScene, changedElements);
15809
+ _ElementsDelta.redrawBoundArrows(tempScene, changedElements);
15810
+ } catch (e) {
15811
+ console.error(`Couldn't redraw elements`, e);
15812
+ if (isTestEnv8() || isDevEnv7()) {
15813
+ throw e;
15814
+ }
15815
+ } finally {
15816
+ return nextElements;
15817
+ }
15818
+ }
15701
15819
  static redrawTextBoundingBoxes(scene, changed) {
15702
15820
  const elements = scene.getNonDeletedElementsMap();
15703
15821
  const boxesToRedraw = /* @__PURE__ */ new Map();
@@ -15786,6 +15904,10 @@ var ElementsDelta = class _ElementsDelta {
15786
15904
  const { id, updated, ...strippedPartial } = partial;
15787
15905
  return strippedPartial;
15788
15906
  }
15907
+ static stripVersionProps(partial) {
15908
+ const { version, versionNonce, ...strippedPartial } = partial;
15909
+ return strippedPartial;
15910
+ }
15789
15911
  };
15790
15912
 
15791
15913
  // src/distribute.ts
@@ -16789,7 +16911,7 @@ var embeddableURLValidator = (url, validateEmbeddable) => {
16789
16911
 
16790
16912
  // src/flowchart.ts
16791
16913
  init_define_import_meta_env();
16792
- import { KEYS as KEYS3, invariant as invariant9, toBrandedType as toBrandedType2 } from "@excalidraw/common";
16914
+ import { KEYS as KEYS3, invariant as invariant8, toBrandedType as toBrandedType2 } from "@excalidraw/common";
16793
16915
  import { pointFrom as pointFrom13 } from "@excalidraw/math";
16794
16916
  var VERTICAL_OFFSET = 100;
16795
16917
  var HORIZONTAL_OFFSET = 100;
@@ -16819,7 +16941,7 @@ var getNodeRelatives = (type, node, elementsMap, direction) => {
16819
16941
  if (!relative) {
16820
16942
  return acc;
16821
16943
  }
16822
- invariant9(
16944
+ invariant8(
16823
16945
  isBindableElement(relative),
16824
16946
  "not an ExcalidrawBindableElement"
16825
16947
  );
@@ -16935,7 +17057,7 @@ var addNewNode = (element, appState, direction, scene) => {
16935
17057
  fillStyle: element.fillStyle,
16936
17058
  strokeStyle: element.strokeStyle
16937
17059
  });
16938
- invariant9(
17060
+ invariant8(
16939
17061
  isFlowchartNodeElement(nextNode),
16940
17062
  "not an ExcalidrawFlowchartNodeElement"
16941
17063
  );
@@ -16993,7 +17115,7 @@ var addNewNodes = (startNode, appState, direction, scene, numberOfNodes) => {
16993
17115
  fillStyle: startNode.fillStyle,
16994
17116
  strokeStyle: startNode.strokeStyle
16995
17117
  });
16996
- invariant9(
17118
+ invariant8(
16997
17119
  isFlowchartNodeElement(nextNode),
16998
17120
  "not an ExcalidrawFlowchartNodeElement"
16999
17121
  );
@@ -17219,7 +17341,7 @@ var FlowChartCreator = class {
17219
17341
  }
17220
17342
  if (startNode.frameId) {
17221
17343
  const frame = elementsMap.get(startNode.frameId);
17222
- invariant9(
17344
+ invariant8(
17223
17345
  frame && isFrameElement(frame),
17224
17346
  "not an ExcalidrawFrameElement"
17225
17347
  );