@excalidraw/element 0.18.0-6d870b1c8 → 0.18.0-7876ee524

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
@@ -13533,10 +13533,20 @@ var StoreDelta = class {
13533
13533
  */
13534
13534
  static load({
13535
13535
  id,
13536
- elements: { added, removed, updated }
13536
+ elements: { added, removed, updated },
13537
+ appState: { delta: appStateDelta }
13537
13538
  }) {
13538
13539
  const elements = ElementsDelta.create(added, removed, updated);
13539
- 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 delta into the current instance.
13545
+ */
13546
+ squash(delta) {
13547
+ this.elements.squash(delta.elements);
13548
+ this.appState.squash(delta.appState);
13549
+ return this;
13540
13550
  }
13541
13551
  /**
13542
13552
  * Inverse store delta, creates new instance of `StoreDelta`.
@@ -13547,9 +13557,7 @@ var StoreDelta = class {
13547
13557
  /**
13548
13558
  * Apply the delta to the passed elements and appState, does not modify the snapshot.
13549
13559
  */
13550
- static applyTo(delta, elements, appState, options = {
13551
- excludedProperties: /* @__PURE__ */ new Set()
13552
- }) {
13560
+ static applyTo(delta, elements, appState, options) {
13553
13561
  const [nextElements, elementsContainVisibleChange] = delta.elements.applyTo(
13554
13562
  elements,
13555
13563
  StoreSnapshot.empty().elements,
@@ -14398,9 +14406,9 @@ var Scene = class {
14398
14406
  getFramesIncludingDeleted() {
14399
14407
  return this.frames;
14400
14408
  }
14401
- constructor(elements = null) {
14409
+ constructor(elements = null, options) {
14402
14410
  if (elements) {
14403
- this.replaceAllElements(elements);
14411
+ this.replaceAllElements(elements, options);
14404
14412
  }
14405
14413
  }
14406
14414
  getSelectedElements(opts) {
@@ -14465,10 +14473,12 @@ var Scene = class {
14465
14473
  }
14466
14474
  return didChange;
14467
14475
  }
14468
- replaceAllElements(nextElements) {
14476
+ replaceAllElements(nextElements, options) {
14469
14477
  const _nextElements = toArray(nextElements);
14470
14478
  const nextFrameLikes = [];
14471
- validateIndicesThrottled(_nextElements);
14479
+ if (!options?.skipValidation) {
14480
+ validateIndicesThrottled(_nextElements);
14481
+ }
14472
14482
  this.elements = syncInvalidIndices2(_nextElements);
14473
14483
  this.elementsMap.clear();
14474
14484
  this.elements.forEach((element) => {
@@ -14641,10 +14651,10 @@ var Delta = class _Delta {
14641
14651
  /**
14642
14652
  * Merges two deltas into a new one.
14643
14653
  */
14644
- static merge(delta1, delta2) {
14654
+ static merge(delta1, delta2, delta3) {
14645
14655
  return _Delta.create(
14646
- { ...delta1.deleted, ...delta2.deleted },
14647
- { ...delta1.inserted, ...delta2.inserted }
14656
+ { ...delta1.deleted, ...delta2.deleted, ...delta3?.deleted ?? {} },
14657
+ { ...delta1.inserted, ...delta2.inserted, ...delta3?.inserted ?? {} }
14648
14658
  );
14649
14659
  }
14650
14660
  /**
@@ -14652,7 +14662,7 @@ var Delta = class _Delta {
14652
14662
  */
14653
14663
  static mergeObjects(prev, added, removed) {
14654
14664
  const cloned = { ...prev };
14655
- for (const key of Object.keys(removed)) {
14665
+ for (const key of Object.keys(removed ?? {})) {
14656
14666
  delete cloned[key];
14657
14667
  }
14658
14668
  return { ...cloned, ...added };
@@ -14871,6 +14881,9 @@ var AppStateDelta = class _AppStateDelta {
14871
14881
  constructor(delta) {
14872
14882
  this.delta = delta;
14873
14883
  }
14884
+ static create(delta) {
14885
+ return new _AppStateDelta(delta);
14886
+ }
14874
14887
  static calculate(prevAppState, nextAppState) {
14875
14888
  const delta = Delta.calculate(
14876
14889
  prevAppState,
@@ -14893,7 +14906,33 @@ var AppStateDelta = class _AppStateDelta {
14893
14906
  return new _AppStateDelta(inversedDelta);
14894
14907
  }
14895
14908
  squash(delta) {
14896
- this.delta = Delta.merge(this.delta, delta.delta);
14909
+ const mergedDeletedSelectedElementIds = Delta.mergeObjects(
14910
+ this.delta.deleted.selectedElementIds ?? {},
14911
+ delta.delta.deleted.selectedElementIds ?? {}
14912
+ );
14913
+ const mergedInsertedSelectedElementIds = Delta.mergeObjects(
14914
+ this.delta.inserted.selectedElementIds ?? {},
14915
+ delta.delta.inserted.selectedElementIds ?? {}
14916
+ );
14917
+ const mergedInsertedSelectedGroupIds = Delta.mergeObjects(
14918
+ this.delta.inserted.selectedGroupIds ?? {},
14919
+ delta.delta.inserted.selectedGroupIds ?? {}
14920
+ );
14921
+ const mergedDeletedSelectedGroupIds = Delta.mergeObjects(
14922
+ this.delta.deleted.selectedGroupIds ?? {},
14923
+ delta.delta.deleted.selectedGroupIds ?? {}
14924
+ );
14925
+ const mergedDelta = Delta.create(
14926
+ {
14927
+ selectedElementIds: mergedDeletedSelectedElementIds,
14928
+ selectedGroupIds: mergedDeletedSelectedGroupIds
14929
+ },
14930
+ {
14931
+ selectedElementIds: mergedInsertedSelectedElementIds,
14932
+ selectedGroupIds: mergedInsertedSelectedGroupIds
14933
+ }
14934
+ );
14935
+ this.delta = Delta.merge(this.delta, delta.delta, mergedDelta);
14897
14936
  return this;
14898
14937
  }
14899
14938
  applyTo(appState, nextElements) {
@@ -15221,9 +15260,13 @@ var ElementsDelta = class _ElementsDelta {
15221
15260
  Number.isInteger(deleted.version) && Number.isInteger(inserted.version) && // versions should be positive, zero included
15222
15261
  deleted.version >= 0 && inserted.version >= 0 && // versions should never be the same
15223
15262
  deleted.version !== inserted.version);
15263
+ static satisfiesUniqueInvariants = (elementsDelta, id) => {
15264
+ const { added, removed, updated } = elementsDelta;
15265
+ return [added[id], removed[id], updated[id]].filter(Boolean).length === 1;
15266
+ };
15224
15267
  static validate(elementsDelta, type, satifiesSpecialInvariants) {
15225
15268
  for (const [id, delta] of Object.entries(elementsDelta[type])) {
15226
- if (!this.satisfiesCommmonInvariants(delta) || !satifiesSpecialInvariants(delta)) {
15269
+ if (!this.satisfiesCommmonInvariants(delta) || !this.satisfiesUniqueInvariants(elementsDelta, id) || !satifiesSpecialInvariants(delta)) {
15227
15270
  console.error(
15228
15271
  `Broken invariant for "${type}" delta, element "${id}", delta:`,
15229
15272
  delta
@@ -15407,26 +15450,30 @@ var ElementsDelta = class _ElementsDelta {
15407
15450
  // redistribute the deltas as `isDeleted` could have been updated
15408
15451
  });
15409
15452
  }
15410
- applyTo(elements, snapshot = StoreSnapshot.empty().elements, options = {
15411
- excludedProperties: /* @__PURE__ */ new Set()
15412
- }) {
15453
+ applyTo(elements, snapshot = StoreSnapshot.empty().elements, options) {
15413
15454
  let nextElements = new Map(elements);
15414
15455
  let changedElements;
15415
15456
  const flags = {
15416
15457
  containsVisibleDifference: false,
15417
- containsZindexDifference: false
15458
+ containsZindexDifference: false,
15459
+ applyDirection: void 0
15418
15460
  };
15419
15461
  try {
15420
15462
  const applyDeltas = _ElementsDelta.createApplier(
15463
+ elements,
15421
15464
  nextElements,
15422
15465
  snapshot,
15423
- options,
15424
- flags
15466
+ flags,
15467
+ options
15425
15468
  );
15426
15469
  const addedElements = applyDeltas(this.added);
15427
15470
  const removedElements = applyDeltas(this.removed);
15428
15471
  const updatedElements = applyDeltas(this.updated);
15429
- const affectedElements = this.resolveConflicts(elements, nextElements);
15472
+ const affectedElements = this.resolveConflicts(
15473
+ elements,
15474
+ nextElements,
15475
+ flags.applyDirection
15476
+ );
15430
15477
  changedElements = new Map([
15431
15478
  ...addedElements,
15432
15479
  ...removedElements,
@@ -15446,9 +15493,7 @@ var ElementsDelta = class _ElementsDelta {
15446
15493
  changedElements,
15447
15494
  flags
15448
15495
  );
15449
- const tempScene = new Scene(nextElements);
15450
- _ElementsDelta.redrawTextBoundingBoxes(tempScene, changedElements);
15451
- _ElementsDelta.redrawBoundArrows(tempScene, changedElements);
15496
+ _ElementsDelta.redrawElements(nextElements, changedElements);
15452
15497
  } catch (e) {
15453
15498
  console.error(
15454
15499
  `Couldn't mutate elements after applying elements change`,
@@ -15463,33 +15508,70 @@ var ElementsDelta = class _ElementsDelta {
15463
15508
  }
15464
15509
  squash(delta) {
15465
15510
  const { added, removed, updated } = delta;
15511
+ function mergeBoundElements(prevDelta, nextDelta) {
15512
+ const mergedDeletedBoundElements = Delta.mergeArrays(
15513
+ prevDelta.deleted.boundElements ?? [],
15514
+ nextDelta.deleted.boundElements ?? [],
15515
+ void 0,
15516
+ (x) => x.id
15517
+ ) ?? [];
15518
+ const mergedInsertedBoundElements = Delta.mergeArrays(
15519
+ prevDelta.inserted.boundElements ?? [],
15520
+ nextDelta.inserted.boundElements ?? [],
15521
+ void 0,
15522
+ (x) => x.id
15523
+ ) ?? [];
15524
+ return Delta.create(
15525
+ {
15526
+ boundElements: mergedDeletedBoundElements
15527
+ },
15528
+ {
15529
+ boundElements: mergedInsertedBoundElements
15530
+ }
15531
+ );
15532
+ }
15466
15533
  for (const [id, nextDelta] of Object.entries(added)) {
15467
- const prevDelta = this.added[id];
15534
+ const prevDelta = this.added[id] ?? this.removed[id] ?? this.updated[id];
15468
15535
  if (!prevDelta) {
15469
15536
  this.added[id] = nextDelta;
15470
15537
  } else {
15471
- this.added[id] = Delta.merge(prevDelta, nextDelta);
15538
+ const mergedDelta = mergeBoundElements(prevDelta, nextDelta);
15539
+ this.added[id] = Delta.merge(prevDelta, nextDelta, mergedDelta);
15472
15540
  }
15473
15541
  }
15474
15542
  for (const [id, nextDelta] of Object.entries(removed)) {
15475
- const prevDelta = this.removed[id];
15543
+ const prevDelta = this.added[id] ?? this.removed[id] ?? this.updated[id];
15476
15544
  if (!prevDelta) {
15477
15545
  this.removed[id] = nextDelta;
15478
15546
  } else {
15479
- this.removed[id] = Delta.merge(prevDelta, nextDelta);
15547
+ const mergedDelta = mergeBoundElements(prevDelta, nextDelta);
15548
+ this.removed[id] = Delta.merge(prevDelta, nextDelta, mergedDelta);
15480
15549
  }
15481
15550
  }
15482
15551
  for (const [id, nextDelta] of Object.entries(updated)) {
15483
- const prevDelta = this.updated[id];
15552
+ const prevDelta = this.added[id] ?? this.removed[id] ?? this.updated[id];
15484
15553
  if (!prevDelta) {
15485
15554
  this.updated[id] = nextDelta;
15486
15555
  } else {
15487
- this.updated[id] = Delta.merge(prevDelta, nextDelta);
15556
+ const mergedDelta = mergeBoundElements(prevDelta, nextDelta);
15557
+ this.updated[id] = Delta.merge(prevDelta, nextDelta, mergedDelta);
15558
+ if (prevDelta === this.added[id]) {
15559
+ this.added[id] = nextDelta;
15560
+ } else if (prevDelta === this.removed[id]) {
15561
+ this.removed[id] = nextDelta;
15562
+ } else {
15563
+ this.updated[id] = nextDelta;
15564
+ }
15488
15565
  }
15489
15566
  }
15567
+ if (isTestEnv8() || isDevEnv7()) {
15568
+ _ElementsDelta.validate(this, "added", _ElementsDelta.satisfiesAddition);
15569
+ _ElementsDelta.validate(this, "removed", _ElementsDelta.satisfiesRemoval);
15570
+ _ElementsDelta.validate(this, "updated", _ElementsDelta.satisfiesUpdate);
15571
+ }
15490
15572
  return this;
15491
15573
  }
15492
- static createApplier = (nextElements, snapshot, options, flags) => (deltas) => {
15574
+ static createApplier = (prevElements, nextElements, snapshot, flags, options) => (deltas) => {
15493
15575
  const getElement = _ElementsDelta.createGetter(
15494
15576
  nextElements,
15495
15577
  snapshot,
@@ -15498,14 +15580,20 @@ var ElementsDelta = class _ElementsDelta {
15498
15580
  return Object.entries(deltas).reduce((acc, [id, delta]) => {
15499
15581
  const element = getElement(id, delta.inserted);
15500
15582
  if (element) {
15501
- const newElement2 = _ElementsDelta.applyDelta(
15583
+ const nextElement = _ElementsDelta.applyDelta(
15502
15584
  element,
15503
15585
  delta,
15504
- options,
15505
- flags
15586
+ flags,
15587
+ options
15506
15588
  );
15507
- nextElements.set(newElement2.id, newElement2);
15508
- acc.set(newElement2.id, newElement2);
15589
+ nextElements.set(nextElement.id, nextElement);
15590
+ acc.set(nextElement.id, nextElement);
15591
+ if (!flags.applyDirection) {
15592
+ const prevElement = prevElements.get(id);
15593
+ if (prevElement) {
15594
+ flags.applyDirection = prevElement.version > nextElement.version ? "backward" : "forward";
15595
+ }
15596
+ }
15509
15597
  }
15510
15598
  return acc;
15511
15599
  }, /* @__PURE__ */ new Map());
@@ -15530,13 +15618,13 @@ var ElementsDelta = class _ElementsDelta {
15530
15618
  }
15531
15619
  return element;
15532
15620
  };
15533
- static applyDelta(element, delta, options, flags) {
15621
+ static applyDelta(element, delta, flags, options) {
15534
15622
  const directlyApplicablePartial = {};
15535
15623
  for (const key of Object.keys(delta.inserted)) {
15536
15624
  if (key === "boundElements") {
15537
15625
  continue;
15538
15626
  }
15539
- if (options.excludedProperties.has(key)) {
15627
+ if (options?.excludedProperties?.has(key)) {
15540
15628
  continue;
15541
15629
  }
15542
15630
  const value = delta.inserted[key];
@@ -15564,7 +15652,7 @@ var ElementsDelta = class _ElementsDelta {
15564
15652
  if (!flags.containsZindexDifference) {
15565
15653
  flags.containsZindexDifference = delta.deleted.index !== delta.inserted.index;
15566
15654
  }
15567
- return newElementWith(element, directlyApplicablePartial);
15655
+ return newElementWith(element, directlyApplicablePartial, true);
15568
15656
  }
15569
15657
  /**
15570
15658
  * Check for visible changes regardless of whether they were removed, added or updated.
@@ -15589,25 +15677,32 @@ var ElementsDelta = class _ElementsDelta {
15589
15677
  *
15590
15678
  * @returns all elements affected by the conflict resolution
15591
15679
  */
15592
- resolveConflicts(prevElements, nextElements) {
15680
+ resolveConflicts(prevElements, nextElements, applyDirection = "forward") {
15593
15681
  const nextAffectedElements = /* @__PURE__ */ new Map();
15594
15682
  const updater = (element, updates) => {
15595
15683
  const nextElement = nextElements.get(element.id);
15596
15684
  if (!nextElement) {
15597
15685
  return;
15598
15686
  }
15687
+ const prevElement = prevElements.get(element.id);
15688
+ const nextVersion = applyDirection === "forward" ? nextElement.version + 1 : nextElement.version - 1;
15689
+ const elementUpdates = updates;
15599
15690
  let affectedElement;
15600
- if (prevElements.get(element.id) === nextElement) {
15691
+ if (prevElement === nextElement) {
15601
15692
  affectedElement = newElementWith(
15602
15693
  nextElement,
15603
- updates
15694
+ {
15695
+ ...elementUpdates,
15696
+ version: nextVersion
15697
+ },
15698
+ true
15604
15699
  );
15605
15700
  } else {
15606
- affectedElement = mutateElement(
15607
- nextElement,
15608
- nextElements,
15609
- updates
15610
- );
15701
+ affectedElement = mutateElement(nextElement, nextElements, {
15702
+ ...elementUpdates,
15703
+ // don't modify the version further, if it's already different
15704
+ version: prevElement?.version !== nextElement.version ? nextElement.version : nextVersion
15705
+ });
15611
15706
  }
15612
15707
  nextAffectedElements.set(affectedElement.id, affectedElement);
15613
15708
  nextElements.set(affectedElement.id, affectedElement);
@@ -15670,6 +15765,20 @@ var ElementsDelta = class _ElementsDelta {
15670
15765
  );
15671
15766
  BindableElement.rebindAffected(nextElements, nextElement(), updater);
15672
15767
  }
15768
+ static redrawElements(nextElements, changedElements) {
15769
+ try {
15770
+ const tempScene = new Scene(nextElements, { skipValidation: true });
15771
+ _ElementsDelta.redrawTextBoundingBoxes(tempScene, changedElements);
15772
+ _ElementsDelta.redrawBoundArrows(tempScene, changedElements);
15773
+ } catch (e) {
15774
+ console.error(`Couldn't redraw elements`, e);
15775
+ if (isTestEnv8() || isDevEnv7()) {
15776
+ throw e;
15777
+ }
15778
+ } finally {
15779
+ return nextElements;
15780
+ }
15781
+ }
15673
15782
  static redrawTextBoundingBoxes(scene, changed) {
15674
15783
  const elements = scene.getNonDeletedElementsMap();
15675
15784
  const boxesToRedraw = /* @__PURE__ */ new Map();