+
{props.icon || props.label}
{props.keyBindingLabel && (
diff --git a/packages/excalidraw/components/ToolIcon.scss b/packages/excalidraw/components/ToolIcon.scss
index 59e45455cb..dfba270b5b 100644
--- a/packages/excalidraw/components/ToolIcon.scss
+++ b/packages/excalidraw/components/ToolIcon.scss
@@ -77,8 +77,7 @@
}
.ToolIcon_type_button,
- .Modal .ToolIcon_type_button,
- .ToolIcon_type_button {
+ .Modal .ToolIcon_type_button {
padding: 0;
border: none;
margin: 0;
@@ -101,6 +100,22 @@
background-color: var(--button-gray-3);
}
+ &:disabled {
+ cursor: default;
+
+ &:active,
+ &:focus-visible,
+ &:hover {
+ background-color: initial;
+ border: none;
+ box-shadow: none;
+ }
+
+ svg {
+ color: var(--color-disabled);
+ }
+ }
+
&--show {
visibility: visible;
}
diff --git a/packages/excalidraw/constants.ts b/packages/excalidraw/constants.ts
index 010d2ea81c..57ccb2eb35 100644
--- a/packages/excalidraw/constants.ts
+++ b/packages/excalidraw/constants.ts
@@ -210,6 +210,7 @@ export const VERSION_TIMEOUT = 30000;
export const SCROLL_TIMEOUT = 100;
export const ZOOM_STEP = 0.1;
export const MIN_ZOOM = 0.1;
+export const MAX_ZOOM = 30.0;
export const HYPERLINK_TOOLTIP_DELAY = 300;
// Report a user inactive after IDLE_THRESHOLD milliseconds
diff --git a/packages/excalidraw/css/theme.scss b/packages/excalidraw/css/theme.scss
index 4bcf717549..ffbeda4efd 100644
--- a/packages/excalidraw/css/theme.scss
+++ b/packages/excalidraw/css/theme.scss
@@ -98,6 +98,8 @@
--color-gray-90: #1e1e1e;
--color-gray-100: #121212;
+ --color-disabled: var(--color-gray-40);
+
--color-warning: #fceeca;
--color-warning-dark: #f5c354;
--color-warning-darker: #f3ab2c;
@@ -208,6 +210,8 @@
--color-primary-light-darker: #43415e;
--color-primary-hover: #bbb8ff;
+ --color-disabled: var(--color-gray-70);
+
--color-text-warning: var(--color-gray-80);
--color-danger: #ffa8a5;
diff --git a/packages/excalidraw/css/variables.module.scss b/packages/excalidraw/css/variables.module.scss
index 71097ba3e2..cacce21e2c 100644
--- a/packages/excalidraw/css/variables.module.scss
+++ b/packages/excalidraw/css/variables.module.scss
@@ -50,6 +50,15 @@
color: var(--color-on-primary-container);
}
}
+
+ &[aria-disabled="true"] {
+ background: initial;
+ border: none;
+
+ svg {
+ color: var(--color-disabled);
+ }
+ }
}
}
diff --git a/packages/excalidraw/data/reconcile.ts b/packages/excalidraw/data/reconcile.ts
index 95d6e4669c..221dd04607 100644
--- a/packages/excalidraw/data/reconcile.ts
+++ b/packages/excalidraw/data/reconcile.ts
@@ -20,7 +20,7 @@ const shouldDiscardRemoteElement = (
// local element is being edited
(local.id === localAppState.editingElement?.id ||
local.id === localAppState.resizingElement?.id ||
- local.id === localAppState.draggingElement?.id ||
+ local.id === localAppState.draggingElement?.id || // TODO: Is this still valid? As draggingElement is selection element, which is never part of the elements array
// local element is newer
local.version > remote.version ||
// resolve conflicting edits deterministically by taking the one with
diff --git a/packages/excalidraw/data/restore.ts b/packages/excalidraw/data/restore.ts
index d8cadeac8e..b288cdf693 100644
--- a/packages/excalidraw/data/restore.ts
+++ b/packages/excalidraw/data/restore.ts
@@ -294,7 +294,7 @@ const restoreElement = (
};
/**
- * Repairs contaienr element's boundElements array by removing duplicates and
+ * Repairs container element's boundElements array by removing duplicates and
* fixing containerId of bound elements if not present. Also removes any
* bound elements that do not exist in the elements array.
*
diff --git a/packages/excalidraw/element/binding.ts b/packages/excalidraw/element/binding.ts
index 97f3ad25ab..ba1258f379 100644
--- a/packages/excalidraw/element/binding.ts
+++ b/packages/excalidraw/element/binding.ts
@@ -9,7 +9,6 @@ import {
ExcalidrawElement,
ExcalidrawRectangleElement,
ExcalidrawDiamondElement,
- ExcalidrawTextElement,
ExcalidrawEllipseElement,
ExcalidrawFreeDrawElement,
ExcalidrawImageElement,
@@ -21,6 +20,8 @@ import {
NonDeletedExcalidrawElement,
ElementsMap,
NonDeletedSceneElementsMap,
+ ExcalidrawTextElement,
+ ExcalidrawArrowElement,
} from "./types";
import { getElementAbsoluteCoords } from "./bounds";
@@ -28,11 +29,14 @@ import { AppClassProperties, AppState, Point } from "../types";
import { isPointOnShape } from "../../utils/collision";
import { getElementAtPosition } from "../scene";
import {
+ isArrowElement,
isBindableElement,
isBindingElement,
+ isBoundToContainer,
isLinearElement,
+ isTextElement,
} from "./typeChecks";
-import { mutateElement } from "./mutateElement";
+import { ElementUpdate, mutateElement } from "./mutateElement";
import Scene from "../scene/Scene";
import { LinearElementEditor } from "./linearElementEditor";
import { arrayToMap, tupleToCoors } from "../utils";
@@ -365,71 +369,71 @@ const calculateFocusAndGap = (
export const updateBoundElements = (
changedElement: NonDeletedExcalidrawElement,
elementsMap: ElementsMap,
-
options?: {
simultaneouslyUpdated?: readonly ExcalidrawElement[];
newSize?: { width: number; height: number };
},
) => {
- const boundLinearElements = (changedElement.boundElements ?? []).filter(
- (el) => el.type === "arrow",
- );
- if (boundLinearElements.length === 0) {
- return;
- }
const { newSize, simultaneouslyUpdated } = options ?? {};
const simultaneouslyUpdatedElementIds = getSimultaneouslyUpdatedElementIds(
simultaneouslyUpdated,
);
- const scene = Scene.getScene(changedElement)!;
- getNonDeletedElements(
- scene,
- boundLinearElements.map((el) => el.id),
- ).forEach((element) => {
- if (!isLinearElement(element)) {
+
+ if (!isBindableElement(changedElement)) {
+ return;
+ }
+
+ boundElementsVisitor(elementsMap, changedElement, (element) => {
+ if (!isLinearElement(element) || element.isDeleted) {
return;
}
- const bindableElement = changedElement as ExcalidrawBindableElement;
// In case the boundElements are stale
- if (!doesNeedUpdate(element, bindableElement)) {
+ if (!doesNeedUpdate(element, changedElement)) {
return;
}
- const startBinding = maybeCalculateNewGapWhenScaling(
- bindableElement,
- element.startBinding,
- newSize,
- );
- const endBinding = maybeCalculateNewGapWhenScaling(
- bindableElement,
- element.endBinding,
- newSize,
- );
+ const bindings = {
+ startBinding: maybeCalculateNewGapWhenScaling(
+ changedElement,
+ element.startBinding,
+ newSize,
+ ),
+ endBinding: maybeCalculateNewGapWhenScaling(
+ changedElement,
+ element.endBinding,
+ newSize,
+ ),
+ };
+
// `linearElement` is being moved/scaled already, just update the binding
if (simultaneouslyUpdatedElementIds.has(element.id)) {
- mutateElement(element, { startBinding, endBinding });
+ mutateElement(element, bindings);
return;
}
- updateBoundPoint(
- element,
- "start",
- startBinding,
- changedElement as ExcalidrawBindableElement,
+
+ bindableElementsVisitor(
elementsMap,
- );
- updateBoundPoint(
element,
- "end",
- endBinding,
- changedElement as ExcalidrawBindableElement,
- elementsMap,
+ (bindableElement, bindingProp) => {
+ if (
+ bindableElement &&
+ isBindableElement(bindableElement) &&
+ (bindingProp === "startBinding" || bindingProp === "endBinding")
+ ) {
+ updateBoundPoint(
+ element,
+ bindingProp,
+ bindings[bindingProp],
+ bindableElement,
+ elementsMap,
+ );
+ }
+ },
);
- const boundText = getBoundTextElement(
- element,
- scene.getNonDeletedElementsMap(),
- );
- if (boundText) {
- handleBindTextResize(element, scene.getNonDeletedElementsMap(), false);
+
+ const boundText = getBoundTextElement(element, elementsMap);
+ if (boundText && !boundText.isDeleted) {
+ handleBindTextResize(element, elementsMap, false);
}
});
};
@@ -452,26 +456,21 @@ const getSimultaneouslyUpdatedElementIds = (
const updateBoundPoint = (
linearElement: NonDeleted,
- startOrEnd: "start" | "end",
+ startOrEnd: "startBinding" | "endBinding",
binding: PointBinding | null | undefined,
- changedElement: ExcalidrawBindableElement,
+ bindableElement: ExcalidrawBindableElement,
elementsMap: ElementsMap,
): void => {
if (
binding == null ||
// We only need to update the other end if this is a 2 point line element
- (binding.elementId !== changedElement.id && linearElement.points.length > 2)
+ (binding.elementId !== bindableElement.id &&
+ linearElement.points.length > 2)
) {
return;
}
- const bindingElement = Scene.getScene(linearElement)!.getElement(
- binding.elementId,
- ) as ExcalidrawBindableElement | null;
- if (bindingElement == null) {
- // We're not cleaning up after deleted elements atm., so handle this case
- return;
- }
- const direction = startOrEnd === "start" ? -1 : 1;
+
+ const direction = startOrEnd === "startBinding" ? -1 : 1;
const edgePointIndex = direction === -1 ? 0 : linearElement.points.length - 1;
const adjacentPointIndex = edgePointIndex - direction;
const adjacentPoint = LinearElementEditor.getPointAtIndexGlobalCoordinates(
@@ -480,7 +479,7 @@ const updateBoundPoint = (
elementsMap,
);
const focusPointAbsolute = determineFocusPoint(
- bindingElement,
+ bindableElement,
binding.focus,
adjacentPoint,
elementsMap,
@@ -492,7 +491,7 @@ const updateBoundPoint = (
newEdgePoint = focusPointAbsolute;
} else {
const intersections = intersectElementWithLine(
- bindingElement,
+ bindableElement,
adjacentPoint,
focusPointAbsolute,
binding.gap,
@@ -519,7 +518,7 @@ const updateBoundPoint = (
),
},
],
- { [startOrEnd === "start" ? "startBinding" : "endBinding"]: binding },
+ { [startOrEnd]: binding },
);
};
@@ -773,70 +772,37 @@ export const fixBindingsAfterDeletion = (
sceneElements: readonly ExcalidrawElement[],
deletedElements: readonly ExcalidrawElement[],
): void => {
- const deletedElementIds = new Set(
- deletedElements.map((element) => element.id),
- );
- // non-deleted which bindings need to be updated
- const affectedElements: Set = new Set();
- deletedElements.forEach((deletedElement) => {
- if (isBindableElement(deletedElement)) {
- deletedElement.boundElements?.forEach((element) => {
- if (!deletedElementIds.has(element.id)) {
- affectedElements.add(element.id);
- }
- });
- } else if (isBindingElement(deletedElement)) {
- if (deletedElement.startBinding) {
- affectedElements.add(deletedElement.startBinding.elementId);
- }
- if (deletedElement.endBinding) {
- affectedElements.add(deletedElement.endBinding.elementId);
- }
- }
- });
- sceneElements
- .filter(({ id }) => affectedElements.has(id))
- .forEach((element) => {
- if (isBindableElement(element)) {
- mutateElement(element, {
- boundElements: newBoundElementsAfterDeletion(
- element.boundElements,
- deletedElementIds,
- ),
- });
- } else if (isBindingElement(element)) {
- mutateElement(element, {
- startBinding: newBindingAfterDeletion(
- element.startBinding,
- deletedElementIds,
- ),
- endBinding: newBindingAfterDeletion(
- element.endBinding,
- deletedElementIds,
- ),
- });
- }
- });
-};
+ const elements = arrayToMap(sceneElements);
-const newBindingAfterDeletion = (
- binding: PointBinding | null,
- deletedElementIds: Set,
-): PointBinding | null => {
- if (binding == null || deletedElementIds.has(binding.elementId)) {
- return null;
+ for (const element of deletedElements) {
+ BoundElement.unbindAffected(elements, element, mutateElement);
+ BindableElement.unbindAffected(elements, element, mutateElement);
}
- return binding;
};
-const newBoundElementsAfterDeletion = (
+const newBoundElements = (
boundElements: ExcalidrawElement["boundElements"],
- deletedElementIds: Set,
+ idsToRemove: Set,
+ elementsToAdd: Array = [],
) => {
if (!boundElements) {
return null;
}
- return boundElements.filter((ele) => !deletedElementIds.has(ele.id));
+
+ const nextBoundElements = boundElements.filter(
+ (boundElement) => !idsToRemove.has(boundElement.id),
+ );
+
+ nextBoundElements.push(
+ ...elementsToAdd.map(
+ (x) =>
+ ({ id: x.id, type: x.type } as
+ | ExcalidrawArrowElement
+ | ExcalidrawTextElement),
+ ),
+ );
+
+ return nextBoundElements;
};
export const bindingBorderTest = (
@@ -1382,3 +1348,306 @@ export const findFocusPointForRectangulars = (
});
return tangentPoint!;
};
+export const bindingProperties: Set = new Set([
+ "boundElements",
+ "frameId",
+ "containerId",
+ "startBinding",
+ "endBinding",
+]);
+
+export type BindableProp = "boundElements";
+
+export type BindingProp =
+ | "frameId"
+ | "containerId"
+ | "startBinding"
+ | "endBinding";
+
+type BoundElementsVisitingFunc = (
+ boundElement: ExcalidrawElement | undefined,
+ bindingProp: BindableProp,
+ bindingId: string,
+) => void;
+
+type BindableElementVisitingFunc = (
+ bindableElement: ExcalidrawElement | undefined,
+ bindingProp: BindingProp,
+ bindingId: string,
+) => void;
+
+/**
+ * Tries to visit each bound element (does not have to be found).
+ */
+const boundElementsVisitor = (
+ elements: ElementsMap,
+ element: ExcalidrawElement,
+ visit: BoundElementsVisitingFunc,
+) => {
+ if (isBindableElement(element)) {
+ // create new instance so that possible mutations won't play a role in visiting order
+ const boundElements = element.boundElements?.slice() ?? [];
+
+ // last added text should be the one we keep (~previous are duplicates)
+ boundElements.forEach(({ id }) => {
+ visit(elements.get(id), "boundElements", id);
+ });
+ }
+};
+
+/**
+ * Tries to visit each bindable element (does not have to be found).
+ */
+const bindableElementsVisitor = (
+ elements: ElementsMap,
+ element: ExcalidrawElement,
+ visit: BindableElementVisitingFunc,
+) => {
+ if (element.frameId) {
+ const id = element.frameId;
+ visit(elements.get(id), "frameId", id);
+ }
+
+ if (isBoundToContainer(element)) {
+ const id = element.containerId;
+ visit(elements.get(id), "containerId", id);
+ }
+
+ if (isArrowElement(element)) {
+ if (element.startBinding) {
+ const id = element.startBinding.elementId;
+ visit(elements.get(id), "startBinding", id);
+ }
+
+ if (element.endBinding) {
+ const id = element.endBinding.elementId;
+ visit(elements.get(id), "endBinding", id);
+ }
+ }
+};
+
+/**
+ * Bound element containing bindings to `frameId`, `containerId`, `startBinding` or `endBinding`.
+ */
+export class BoundElement {
+ /**
+ * Unbind the affected non deleted bindable elements (removing element from `boundElements`).
+ * - iterates non deleted bindable elements (`containerId` | `startBinding.elementId` | `endBinding.elementId`) of the current element
+ * - prepares updates to unbind each bindable element's `boundElements` from the current element
+ */
+ public static unbindAffected(
+ elements: ElementsMap,
+ boundElement: ExcalidrawElement | undefined,
+ updateElementWith: (
+ affected: ExcalidrawElement,
+ updates: ElementUpdate,
+ ) => void,
+ ) {
+ if (!boundElement) {
+ return;
+ }
+
+ bindableElementsVisitor(elements, boundElement, (bindableElement) => {
+ // bindable element is deleted, this is fine
+ if (!bindableElement || bindableElement.isDeleted) {
+ return;
+ }
+
+ boundElementsVisitor(
+ elements,
+ bindableElement,
+ (_, __, boundElementId) => {
+ if (boundElementId === boundElement.id) {
+ updateElementWith(bindableElement, {
+ boundElements: newBoundElements(
+ bindableElement.boundElements,
+ new Set([boundElementId]),
+ ),
+ });
+ }
+ },
+ );
+ });
+ }
+
+ /**
+ * Rebind the next affected non deleted bindable elements (adding element to `boundElements`).
+ * - iterates non deleted bindable elements (`containerId` | `startBinding.elementId` | `endBinding.elementId`) of the current element
+ * - prepares updates to rebind each bindable element's `boundElements` to the current element
+ *
+ * NOTE: rebind expects that affected elements were previously unbound with `BoundElement.unbindAffected`
+ */
+ public static rebindAffected = (
+ elements: ElementsMap,
+ boundElement: ExcalidrawElement | undefined,
+ updateElementWith: (
+ affected: ExcalidrawElement,
+ updates: ElementUpdate,
+ ) => void,
+ ) => {
+ // don't try to rebind element that is deleted
+ if (!boundElement || boundElement.isDeleted) {
+ return;
+ }
+
+ bindableElementsVisitor(
+ elements,
+ boundElement,
+ (bindableElement, bindingProp) => {
+ // unbind from bindable elements, as bindings from non deleted elements into deleted elements are incorrect
+ if (!bindableElement || bindableElement.isDeleted) {
+ updateElementWith(boundElement, { [bindingProp]: null });
+ return;
+ }
+
+ // frame bindings are unidirectional, there is nothing to rebind
+ if (bindingProp === "frameId") {
+ return;
+ }
+
+ if (
+ bindableElement.boundElements?.find((x) => x.id === boundElement.id)
+ ) {
+ return;
+ }
+
+ if (isArrowElement(boundElement)) {
+ // rebind if not found!
+ updateElementWith(bindableElement, {
+ boundElements: newBoundElements(
+ bindableElement.boundElements,
+ new Set(),
+ new Array(boundElement),
+ ),
+ });
+ }
+
+ if (isTextElement(boundElement)) {
+ if (!bindableElement.boundElements?.find((x) => x.type === "text")) {
+ // rebind only if there is no other text bound already
+ updateElementWith(bindableElement, {
+ boundElements: newBoundElements(
+ bindableElement.boundElements,
+ new Set(),
+ new Array(boundElement),
+ ),
+ });
+ } else {
+ // unbind otherwise
+ updateElementWith(boundElement, { [bindingProp]: null });
+ }
+ }
+ },
+ );
+ };
+}
+
+/**
+ * Bindable element containing bindings to `boundElements`.
+ */
+export class BindableElement {
+ /**
+ * Unbind the affected non deleted bound elements (resetting `containerId`, `startBinding`, `endBinding` to `null`).
+ * - iterates through non deleted `boundElements` of the current element
+ * - prepares updates to unbind each bound element from the current element
+ */
+ public static unbindAffected(
+ elements: ElementsMap,
+ bindableElement: ExcalidrawElement | undefined,
+ updateElementWith: (
+ affected: ExcalidrawElement,
+ updates: ElementUpdate,
+ ) => void,
+ ) {
+ if (!bindableElement) {
+ return;
+ }
+
+ boundElementsVisitor(elements, bindableElement, (boundElement) => {
+ // bound element is deleted, this is fine
+ if (!boundElement || boundElement.isDeleted) {
+ return;
+ }
+
+ bindableElementsVisitor(
+ elements,
+ boundElement,
+ (_, bindingProp, bindableElementId) => {
+ // making sure there is an element to be unbound
+ if (bindableElementId === bindableElement.id) {
+ updateElementWith(boundElement, { [bindingProp]: null });
+ }
+ },
+ );
+ });
+ }
+
+ /**
+ * Rebind the affected non deleted bound elements (for now setting only `containerId`, as we cannot rebind arrows atm).
+ * - iterates through non deleted `boundElements` of the current element
+ * - prepares updates to rebind each bound element to the current element or unbind it from `boundElements` in case of conflicts
+ *
+ * NOTE: rebind expects that affected elements were previously unbound with `BindaleElement.unbindAffected`
+ */
+ public static rebindAffected = (
+ elements: ElementsMap,
+ bindableElement: ExcalidrawElement | undefined,
+ updateElementWith: (
+ affected: ExcalidrawElement,
+ updates: ElementUpdate,
+ ) => void,
+ ) => {
+ // don't try to rebind element that is deleted (i.e. updated as deleted)
+ if (!bindableElement || bindableElement.isDeleted) {
+ return;
+ }
+
+ boundElementsVisitor(
+ elements,
+ bindableElement,
+ (boundElement, _, boundElementId) => {
+ // unbind from bindable elements, as bindings from non deleted elements into deleted elements are incorrect
+ if (!boundElement || boundElement.isDeleted) {
+ updateElementWith(bindableElement, {
+ boundElements: newBoundElements(
+ bindableElement.boundElements,
+ new Set([boundElementId]),
+ ),
+ });
+ return;
+ }
+
+ if (isTextElement(boundElement)) {
+ const boundElements = bindableElement.boundElements?.slice() ?? [];
+ // check if this is the last element in the array, if not, there is an previously bound text which should be unbound
+ if (
+ boundElements.reverse().find((x) => x.type === "text")?.id ===
+ boundElement.id
+ ) {
+ if (boundElement.containerId !== bindableElement.id) {
+ // rebind if not bound already!
+ updateElementWith(boundElement, {
+ containerId: bindableElement.id,
+ } as ElementUpdate);
+ }
+ } else {
+ if (boundElement.containerId !== null) {
+ // unbind if not unbound already
+ updateElementWith(boundElement, {
+ containerId: null,
+ } as ElementUpdate);
+ }
+
+ // unbind from boundElements as the element got bound to some other element in the meantime
+ updateElementWith(bindableElement, {
+ boundElements: newBoundElements(
+ bindableElement.boundElements,
+ new Set([boundElement.id]),
+ ),
+ });
+ }
+ }
+ },
+ );
+ };
+}
diff --git a/packages/excalidraw/element/embeddable.ts b/packages/excalidraw/element/embeddable.ts
index d82c75e903..df9128165f 100644
--- a/packages/excalidraw/element/embeddable.ts
+++ b/packages/excalidraw/element/embeddable.ts
@@ -13,6 +13,7 @@ import {
} from "./types";
import { sanitizeHTMLAttribute } from "../data/url";
import { MarkRequired } from "../utility-types";
+import { StoreAction } from "../store";
type IframeDataWithSandbox = MarkRequired;
@@ -314,7 +315,7 @@ export const actionSetEmbeddableAsActiveTool = register({
type: "embeddable",
}),
},
- commitToHistory: false,
+ storeAction: StoreAction.NONE,
};
},
});
diff --git a/packages/excalidraw/element/linearElementEditor.ts b/packages/excalidraw/element/linearElementEditor.ts
index 29fa65c35f..7f64cbd7e0 100644
--- a/packages/excalidraw/element/linearElementEditor.ts
+++ b/packages/excalidraw/element/linearElementEditor.ts
@@ -36,7 +36,6 @@ import {
AppClassProperties,
} from "../types";
import { mutateElement } from "./mutateElement";
-import History from "../history";
import {
bindOrUnbindLinearElement,
@@ -50,6 +49,7 @@ import { getBoundTextElement, handleBindTextResize } from "./textElement";
import { DRAGGING_THRESHOLD } from "../constants";
import { Mutable } from "../utility-types";
import { ShapeCache } from "../scene/ShapeCache";
+import { IStore } from "../store";
const editorMidPointsCache: {
version: number | null;
@@ -642,7 +642,7 @@ export class LinearElementEditor {
static handlePointerDown(
event: React.PointerEvent,
appState: AppState,
- history: History,
+ store: IStore,
scenePointer: { x: number; y: number },
linearElementEditor: LinearElementEditor,
app: AppClassProperties,
@@ -700,7 +700,7 @@ export class LinearElementEditor {
});
ret.didAddPoint = true;
}
- history.resumeRecording();
+ store.shouldCaptureIncrement();
ret.linearElementEditor = {
...linearElementEditor,
pointerDownState: {
diff --git a/packages/excalidraw/element/mutateElement.ts b/packages/excalidraw/element/mutateElement.ts
index d4dbd8cd25..a44f5e74a1 100644
--- a/packages/excalidraw/element/mutateElement.ts
+++ b/packages/excalidraw/element/mutateElement.ts
@@ -7,9 +7,9 @@ import { getUpdatedTimestamp } from "../utils";
import { Mutable } from "../utility-types";
import { ShapeCache } from "../scene/ShapeCache";
-type ElementUpdate = Omit<
+export type ElementUpdate = Omit<
Partial,
- "id" | "version" | "versionNonce"
+ "id" | "version" | "versionNonce" | "updated"
>;
// This function tracks updates of text elements for the purposes for collaboration.
@@ -79,6 +79,7 @@ export const mutateElement = >(
didChange = true;
}
}
+
if (!didChange) {
return element;
}
diff --git a/packages/excalidraw/element/sizeHelpers.ts b/packages/excalidraw/element/sizeHelpers.ts
index e30ea98772..187f84d181 100644
--- a/packages/excalidraw/element/sizeHelpers.ts
+++ b/packages/excalidraw/element/sizeHelpers.ts
@@ -6,6 +6,9 @@ import { AppState, Zoom } from "../types";
import { getElementBounds } from "./bounds";
import { viewportCoordsToSceneCoords } from "../utils";
+// TODO: remove invisible elements consistently actions, so that invisible elements are not recorded by the store, exported, broadcasted or persisted
+// - perhaps could be as part of a standalone 'cleanup' action, in addition to 'finalize'
+// - could also be part of `_clearElements`
export const isInvisiblySmallElement = (
element: ExcalidrawElement,
): boolean => {
diff --git a/packages/excalidraw/element/textElement.ts b/packages/excalidraw/element/textElement.ts
index 6f45561f81..b7b6cf65a2 100644
--- a/packages/excalidraw/element/textElement.ts
+++ b/packages/excalidraw/element/textElement.ts
@@ -48,6 +48,7 @@ export const redrawTextBoundingBox = (
textElement: ExcalidrawTextElement,
container: ExcalidrawElement | null,
elementsMap: ElementsMap,
+ informMutation: boolean = true,
) => {
let maxWidth = undefined;
const boundTextUpdates = {
@@ -56,6 +57,7 @@ export const redrawTextBoundingBox = (
text: textElement.text,
width: textElement.width,
height: textElement.height,
+ angle: container?.angle ?? textElement.angle,
};
boundTextUpdates.text = textElement.text;
@@ -89,7 +91,7 @@ export const redrawTextBoundingBox = (
metrics.height,
container.type,
);
- mutateElement(container, { height: nextHeight });
+ mutateElement(container, { height: nextHeight }, informMutation);
updateOriginalContainerCache(container.id, nextHeight);
}
if (metrics.width > maxContainerWidth) {
@@ -97,7 +99,7 @@ export const redrawTextBoundingBox = (
metrics.width,
container.type,
);
- mutateElement(container, { width: nextWidth });
+ mutateElement(container, { width: nextWidth }, informMutation);
}
const updatedTextElement = {
...textElement,
@@ -112,7 +114,7 @@ export const redrawTextBoundingBox = (
boundTextUpdates.y = y;
}
- mutateElement(textElement, boundTextUpdates);
+ mutateElement(textElement, boundTextUpdates, informMutation);
};
export const bindTextToShapeAfterDuplication = (
diff --git a/packages/excalidraw/element/typeChecks.ts b/packages/excalidraw/element/typeChecks.ts
index 7193e251b3..a84798c93b 100644
--- a/packages/excalidraw/element/typeChecks.ts
+++ b/packages/excalidraw/element/typeChecks.ts
@@ -20,6 +20,7 @@ import {
ExcalidrawIframeElement,
ExcalidrawIframeLikeElement,
ExcalidrawMagicFrameElement,
+ ExcalidrawArrowElement,
} from "./types";
export const isInitializedImageElement = (
@@ -101,7 +102,7 @@ export const isLinearElement = (
export const isArrowElement = (
element?: ExcalidrawElement | null,
-): element is ExcalidrawLinearElement => {
+): element is ExcalidrawArrowElement => {
return element != null && element.type === "arrow";
};
diff --git a/packages/excalidraw/element/types.ts b/packages/excalidraw/element/types.ts
index 2ee9a12b09..262747a3f5 100644
--- a/packages/excalidraw/element/types.ts
+++ b/packages/excalidraw/element/types.ts
@@ -26,6 +26,11 @@ type VerticalAlignKeys = keyof typeof VERTICAL_ALIGN;
export type VerticalAlign = typeof VERTICAL_ALIGN[VerticalAlignKeys];
export type FractionalIndex = string & { _brand: "franctionalIndex" };
+export type BoundElement = Readonly<{
+ id: ExcalidrawLinearElement["id"];
+ type: "arrow" | "text";
+}>;
+
type _ExcalidrawElementBase = Readonly<{
id: string;
x: number;
@@ -62,12 +67,7 @@ type _ExcalidrawElementBase = Readonly<{
groupIds: readonly GroupId[];
frameId: string | null;
/** other elements that are bound to this element */
- boundElements:
- | readonly Readonly<{
- id: ExcalidrawLinearElement["id"];
- type: "arrow" | "text";
- }>[]
- | null;
+ boundElements: readonly BoundElement[] | null;
/** epoch (ms) timestamp of last element update */
updated: number;
link: string | null;
diff --git a/packages/excalidraw/groups.ts b/packages/excalidraw/groups.ts
index f8c0eddb93..ed3fad62b4 100644
--- a/packages/excalidraw/groups.ts
+++ b/packages/excalidraw/groups.ts
@@ -355,6 +355,24 @@ export const getMaximumGroups = (
return Array.from(groups.values());
};
+export const getNonDeletedGroupIds = (elements: ElementsMap) => {
+ const nonDeletedGroupIds = new Set();
+
+ for (const [, element] of elements) {
+ // defensive check
+ if (element.isDeleted) {
+ continue;
+ }
+
+ // defensive fallback
+ for (const groupId of element.groupIds ?? []) {
+ nonDeletedGroupIds.add(groupId);
+ }
+ }
+
+ return nonDeletedGroupIds;
+};
+
export const elementsAreInSameGroup = (elements: ExcalidrawElement[]) => {
const allGroups = elements.flatMap((element) => element.groupIds);
const groupCount = new Map();
diff --git a/packages/excalidraw/history.ts b/packages/excalidraw/history.ts
index d102a7ecc9..cf9ed70851 100644
--- a/packages/excalidraw/history.ts
+++ b/packages/excalidraw/history.ts
@@ -1,265 +1,210 @@
+import { AppStateChange, ElementsChange } from "./change";
+import { SceneElementsMap } from "./element/types";
+import { Emitter } from "./emitter";
+import { Snapshot } from "./store";
import { AppState } from "./types";
-import { ExcalidrawElement } from "./element/types";
-import { isLinearElement } from "./element/typeChecks";
-import { deepCopyElement } from "./element/newElement";
-import { Mutable } from "./utility-types";
-export interface HistoryEntry {
- appState: ReturnType;
- elements: ExcalidrawElement[];
+type HistoryStack = HistoryEntry[];
+
+export class HistoryChangedEvent {
+ constructor(
+ public readonly isUndoStackEmpty: boolean = true,
+ public readonly isRedoStackEmpty: boolean = true,
+ ) {}
}
-interface DehydratedExcalidrawElement {
- id: string;
- versionNonce: number;
-}
+export class History {
+ public readonly onHistoryChangedEmitter = new Emitter<
+ [HistoryChangedEvent]
+ >();
-interface DehydratedHistoryEntry {
- appState: string;
- elements: DehydratedExcalidrawElement[];
-}
+ private readonly undoStack: HistoryStack = [];
+ private readonly redoStack: HistoryStack = [];
-const clearAppStatePropertiesForHistory = (appState: AppState) => {
- return {
- selectedElementIds: appState.selectedElementIds,
- selectedGroupIds: appState.selectedGroupIds,
- viewBackgroundColor: appState.viewBackgroundColor,
- editingLinearElement: appState.editingLinearElement,
- editingGroupId: appState.editingGroupId,
- name: appState.name,
- };
-};
-
-class History {
- private elementCache = new Map>();
- private recording: boolean = true;
- private stateHistory: DehydratedHistoryEntry[] = [];
- private redoStack: DehydratedHistoryEntry[] = [];
- private lastEntry: HistoryEntry | null = null;
-
- private hydrateHistoryEntry({
- appState,
- elements,
- }: DehydratedHistoryEntry): HistoryEntry {
- return {
- appState: JSON.parse(appState),
- elements: elements.map((dehydratedExcalidrawElement) => {
- const element = this.elementCache
- .get(dehydratedExcalidrawElement.id)
- ?.get(dehydratedExcalidrawElement.versionNonce);
- if (!element) {
- throw new Error(
- `Element not found: ${dehydratedExcalidrawElement.id}:${dehydratedExcalidrawElement.versionNonce}`,
- );
- }
- return element;
- }),
- };
+ public get isUndoStackEmpty() {
+ return this.undoStack.length === 0;
}
- private dehydrateHistoryEntry({
- appState,
- elements,
- }: HistoryEntry): DehydratedHistoryEntry {
- return {
- appState: JSON.stringify(appState),
- elements: elements.map((element: ExcalidrawElement) => {
- if (!this.elementCache.has(element.id)) {
- this.elementCache.set(element.id, new Map());
- }
- const versions = this.elementCache.get(element.id)!;
- if (!versions.has(element.versionNonce)) {
- versions.set(element.versionNonce, deepCopyElement(element));
- }
- return {
- id: element.id,
- versionNonce: element.versionNonce,
- };
- }),
- };
+ public get isRedoStackEmpty() {
+ return this.redoStack.length === 0;
}
- getSnapshotForTest() {
- return {
- recording: this.recording,
- stateHistory: this.stateHistory.map((dehydratedHistoryEntry) =>
- this.hydrateHistoryEntry(dehydratedHistoryEntry),
- ),
- redoStack: this.redoStack.map((dehydratedHistoryEntry) =>
- this.hydrateHistoryEntry(dehydratedHistoryEntry),
- ),
- };
- }
-
- clear() {
- this.stateHistory.length = 0;
+ public clear() {
+ this.undoStack.length = 0;
this.redoStack.length = 0;
- this.lastEntry = null;
- this.elementCache.clear();
- }
-
- private generateEntry = (
- appState: AppState,
- elements: readonly ExcalidrawElement[],
- ): DehydratedHistoryEntry =>
- this.dehydrateHistoryEntry({
- appState: clearAppStatePropertiesForHistory(appState),
- elements: elements.reduce((elements, element) => {
- if (
- isLinearElement(element) &&
- appState.multiElement &&
- appState.multiElement.id === element.id
- ) {
- // don't store multi-point arrow if still has only one point
- if (
- appState.multiElement &&
- appState.multiElement.id === element.id &&
- element.points.length < 2
- ) {
- return elements;
- }
-
- elements.push({
- ...element,
- // don't store last point if not committed
- points:
- element.lastCommittedPoint !==
- element.points[element.points.length - 1]
- ? element.points.slice(0, -1)
- : element.points,
- });
- } else {
- elements.push(element);
- }
- return elements;
- }, [] as Mutable),
- });
-
- shouldCreateEntry(nextEntry: HistoryEntry): boolean {
- const { lastEntry } = this;
-
- if (!lastEntry) {
- return true;
- }
-
- if (nextEntry.elements.length !== lastEntry.elements.length) {
- return true;
- }
-
- // loop from right to left as changes are likelier to happen on new elements
- for (let i = nextEntry.elements.length - 1; i > -1; i--) {
- const prev = nextEntry.elements[i];
- const next = lastEntry.elements[i];
- if (
- !prev ||
- !next ||
- prev.id !== next.id ||
- prev.versionNonce !== next.versionNonce
- ) {
- return true;
- }
- }
-
- // note: this is safe because entry's appState is guaranteed no excess props
- let key: keyof typeof nextEntry.appState;
- for (key in nextEntry.appState) {
- if (key === "editingLinearElement") {
- if (
- nextEntry.appState[key]?.elementId ===
- lastEntry.appState[key]?.elementId
- ) {
- continue;
- }
- }
- if (key === "selectedElementIds" || key === "selectedGroupIds") {
- continue;
- }
- if (nextEntry.appState[key] !== lastEntry.appState[key]) {
- return true;
- }
- }
-
- return false;
- }
-
- pushEntry(appState: AppState, elements: readonly ExcalidrawElement[]) {
- const newEntryDehydrated = this.generateEntry(appState, elements);
- const newEntry: HistoryEntry = this.hydrateHistoryEntry(newEntryDehydrated);
-
- if (newEntry) {
- if (!this.shouldCreateEntry(newEntry)) {
- return;
- }
-
- this.stateHistory.push(newEntryDehydrated);
- this.lastEntry = newEntry;
- // As a new entry was pushed, we invalidate the redo stack
- this.clearRedoStack();
- }
- }
-
- clearRedoStack() {
- this.redoStack.splice(0, this.redoStack.length);
- }
-
- redoOnce(): HistoryEntry | null {
- if (this.redoStack.length === 0) {
- return null;
- }
-
- const entryToRestore = this.redoStack.pop();
-
- if (entryToRestore !== undefined) {
- this.stateHistory.push(entryToRestore);
- return this.hydrateHistoryEntry(entryToRestore);
- }
-
- return null;
- }
-
- undoOnce(): HistoryEntry | null {
- if (this.stateHistory.length === 1) {
- return null;
- }
-
- const currentEntry = this.stateHistory.pop();
-
- const entryToRestore = this.stateHistory[this.stateHistory.length - 1];
-
- if (currentEntry !== undefined) {
- this.redoStack.push(currentEntry);
- return this.hydrateHistoryEntry(entryToRestore);
- }
-
- return null;
}
/**
- * Updates history's `lastEntry` to latest app state. This is necessary
- * when doing undo/redo which itself doesn't commit to history, but updates
- * app state in a way that would break `shouldCreateEntry` which relies on
- * `lastEntry` to reflect last comittable history state.
- * We can't update `lastEntry` from within history when calling undo/redo
- * because the action potentially mutates appState/elements before storing
- * it.
+ * Record a local change which will go into the history
*/
- setCurrentState(appState: AppState, elements: readonly ExcalidrawElement[]) {
- this.lastEntry = this.hydrateHistoryEntry(
- this.generateEntry(appState, elements),
+ public record(
+ elementsChange: ElementsChange,
+ appStateChange: AppStateChange,
+ ) {
+ const entry = HistoryEntry.create(appStateChange, elementsChange);
+
+ if (!entry.isEmpty()) {
+ // we have the latest changes, no need to `applyLatest`, which is done within `History.push`
+ this.undoStack.push(entry.inverse());
+
+ if (!entry.elementsChange.isEmpty()) {
+ // don't reset redo stack on local appState changes,
+ // as a simple click (unselect) could lead to losing all the redo entries
+ // only reset on non empty elements changes!
+ this.redoStack.length = 0;
+ }
+
+ this.onHistoryChangedEmitter.trigger(
+ new HistoryChangedEvent(this.isUndoStackEmpty, this.isRedoStackEmpty),
+ );
+ }
+ }
+
+ public undo(
+ elements: SceneElementsMap,
+ appState: AppState,
+ snapshot: Readonly,
+ ) {
+ return this.perform(
+ elements,
+ appState,
+ snapshot,
+ () => History.pop(this.undoStack),
+ (entry: HistoryEntry) => History.push(this.redoStack, entry, elements),
);
}
- // Suspicious that this is called so many places. Seems error-prone.
- resumeRecording() {
- this.recording = true;
+ public redo(
+ elements: SceneElementsMap,
+ appState: AppState,
+ snapshot: Readonly,
+ ) {
+ return this.perform(
+ elements,
+ appState,
+ snapshot,
+ () => History.pop(this.redoStack),
+ (entry: HistoryEntry) => History.push(this.undoStack, entry, elements),
+ );
}
- record(state: AppState, elements: readonly ExcalidrawElement[]) {
- if (this.recording) {
- this.pushEntry(state, elements);
- this.recording = false;
+ private perform(
+ elements: SceneElementsMap,
+ appState: AppState,
+ snapshot: Readonly,
+ pop: () => HistoryEntry | null,
+ push: (entry: HistoryEntry) => void,
+ ): [SceneElementsMap, AppState] | void {
+ try {
+ let historyEntry = pop();
+
+ if (historyEntry === null) {
+ return;
+ }
+
+ let nextElements = elements;
+ let nextAppState = appState;
+ let containsVisibleChange = false;
+
+ // iterate through the history entries in case they result in no visible changes
+ while (historyEntry) {
+ try {
+ [nextElements, nextAppState, containsVisibleChange] =
+ historyEntry.applyTo(nextElements, nextAppState, snapshot);
+ } finally {
+ // make sure to always push / pop, even if the increment is corrupted
+ push(historyEntry);
+ }
+
+ if (containsVisibleChange) {
+ break;
+ }
+
+ historyEntry = pop();
+ }
+
+ return [nextElements, nextAppState];
+ } finally {
+ // trigger the history change event before returning completely
+ // also trigger it just once, no need doing so on each entry
+ this.onHistoryChangedEmitter.trigger(
+ new HistoryChangedEvent(this.isUndoStackEmpty, this.isRedoStackEmpty),
+ );
}
}
+
+ private static pop(stack: HistoryStack): HistoryEntry | null {
+ if (!stack.length) {
+ return null;
+ }
+
+ const entry = stack.pop();
+
+ if (entry !== undefined) {
+ return entry;
+ }
+
+ return null;
+ }
+
+ private static push(
+ stack: HistoryStack,
+ entry: HistoryEntry,
+ prevElements: SceneElementsMap,
+ ) {
+ const updatedEntry = entry.inverse().applyLatestChanges(prevElements);
+ return stack.push(updatedEntry);
+ }
}
-export default History;
+export class HistoryEntry {
+ private constructor(
+ public readonly appStateChange: AppStateChange,
+ public readonly elementsChange: ElementsChange,
+ ) {}
+
+ public static create(
+ appStateChange: AppStateChange,
+ elementsChange: ElementsChange,
+ ) {
+ return new HistoryEntry(appStateChange, elementsChange);
+ }
+
+ public inverse(): HistoryEntry {
+ return new HistoryEntry(
+ this.appStateChange.inverse(),
+ this.elementsChange.inverse(),
+ );
+ }
+
+ public applyTo(
+ elements: SceneElementsMap,
+ appState: AppState,
+ snapshot: Readonly,
+ ): [SceneElementsMap, AppState, boolean] {
+ const [nextElements, elementsContainVisibleChange] =
+ this.elementsChange.applyTo(elements, snapshot.elements);
+
+ const [nextAppState, appStateContainsVisibleChange] =
+ this.appStateChange.applyTo(appState, nextElements);
+
+ const appliedVisibleChanges =
+ elementsContainVisibleChange || appStateContainsVisibleChange;
+
+ return [nextElements, nextAppState, appliedVisibleChanges];
+ }
+
+ /**
+ * Apply latest (remote) changes to the history entry, creates new instance of `HistoryEntry`.
+ */
+ public applyLatestChanges(elements: SceneElementsMap): HistoryEntry {
+ const updatedElementsChange =
+ this.elementsChange.applyLatestChanges(elements);
+
+ return HistoryEntry.create(this.appStateChange, updatedElementsChange);
+ }
+
+ public isEmpty(): boolean {
+ return this.appStateChange.isEmpty() && this.elementsChange.isEmpty();
+ }
+}
diff --git a/packages/excalidraw/hooks/useEmitter.ts b/packages/excalidraw/hooks/useEmitter.ts
new file mode 100644
index 0000000000..fe6e3cfb07
--- /dev/null
+++ b/packages/excalidraw/hooks/useEmitter.ts
@@ -0,0 +1,21 @@
+import { useEffect, useState } from "react";
+import { Emitter } from "../emitter";
+
+export const useEmitter = (
+ emitter: Emitter<[TEvent]>,
+ initialState: TEvent,
+) => {
+ const [event, setEvent] = useState(initialState);
+
+ useEffect(() => {
+ const unsubscribe = emitter.on((event) => {
+ setEvent(event);
+ });
+
+ return () => {
+ unsubscribe();
+ };
+ }, [emitter]);
+
+ return event;
+};
diff --git a/packages/excalidraw/scene/Scene.ts b/packages/excalidraw/scene/Scene.ts
index 6be7d87048..98d9fda28a 100644
--- a/packages/excalidraw/scene/Scene.ts
+++ b/packages/excalidraw/scene/Scene.ts
@@ -140,10 +140,6 @@ class Scene {
};
private versionNonce: number | undefined;
- getElementsMapIncludingDeleted() {
- return this.elementsMap;
- }
-
getNonDeletedElementsMap() {
return this.nonDeletedElementsMap;
}
@@ -152,6 +148,10 @@ class Scene {
return this.elements;
}
+ getElementsMapIncludingDeleted() {
+ return this.elementsMap;
+ }
+
getNonDeletedElements() {
return this.nonDeletedElements;
}
diff --git a/packages/excalidraw/store.ts b/packages/excalidraw/store.ts
new file mode 100644
index 0000000000..23065ffa83
--- /dev/null
+++ b/packages/excalidraw/store.ts
@@ -0,0 +1,332 @@
+import { getDefaultAppState } from "./appState";
+import { AppStateChange, ElementsChange } from "./change";
+import { newElementWith } from "./element/mutateElement";
+import { deepCopyElement } from "./element/newElement";
+import { OrderedExcalidrawElement } from "./element/types";
+import { Emitter } from "./emitter";
+import { AppState, ObservedAppState } from "./types";
+import { isShallowEqual } from "./utils";
+
+export const getObservedAppState = (appState: AppState): ObservedAppState => {
+ return {
+ name: appState.name,
+ editingGroupId: appState.editingGroupId,
+ viewBackgroundColor: appState.viewBackgroundColor,
+ selectedElementIds: appState.selectedElementIds,
+ selectedGroupIds: appState.selectedGroupIds,
+ editingLinearElementId: appState.editingLinearElement?.elementId || null,
+ selectedLinearElementId: appState.selectedLinearElement?.elementId || null,
+ };
+};
+
+export const StoreAction = {
+ NONE: "NONE",
+ UPDATE: "UPDATE",
+ CAPTURE: "CAPTURE",
+} as const;
+
+/**
+ * Store which captures the observed changes and emits them as `StoreIncrementEvent` events.
+ *
+ * @experimental this interface is experimental and subject to change.
+ */
+export interface IStore {
+ onStoreIncrementEmitter: Emitter<[StoreIncrementEvent]>;
+ get snapshot(): Snapshot;
+ set snapshot(snapshot: Snapshot);
+
+ /**
+ * Use to schedule update of the snapshot, useful on updates for which we don't need to calculate increments (i.e. remote updates).
+ */
+ shouldUpdateSnapshot(): void;
+
+ /**
+ * Use to schedule calculation of a store increment on a next component update.
+ */
+ shouldCaptureIncrement(): void;
+
+ /**
+ * Capture changes to the `elements` and `appState` by calculating changes (based on a snapshot) and emitting resulting changes as a store increment.
+ *
+ * @emits StoreIncrementEvent
+ */
+ capture(
+ elements: Map,
+ appState: AppState,
+ ): void;
+
+ /**
+ * Clears the store instance.
+ */
+ clear(): void;
+
+ /**
+ * Filters out yet uncomitted elements from `nextElements`, which are part of in-progress local async actions (ephemerals) and thus were not yet commited to the snapshot.
+ *
+ * This is necessary in updates in which we receive reconciled elements, already containing elements which were not yet captured by the local store (i.e. collab).
+ *
+ * Once we will be exchanging just store increments for all ephemerals, this could be deprecated.
+ */
+ ignoreUncomittedElements(
+ prevElements: Map,
+ nextElements: Map,
+ ): Map;
+}
+
+/**
+ * Represent an increment to the Store.
+ */
+class StoreIncrementEvent {
+ constructor(
+ public readonly elementsChange: ElementsChange,
+ public readonly appStateChange: AppStateChange,
+ ) {}
+}
+
+export class Store implements IStore {
+ public readonly onStoreIncrementEmitter = new Emitter<
+ [StoreIncrementEvent]
+ >();
+
+ private calculatingIncrement: boolean = false;
+ private updatingSnapshot: boolean = false;
+
+ private _snapshot = Snapshot.empty();
+
+ public get snapshot() {
+ return this._snapshot;
+ }
+
+ public set snapshot(snapshot: Snapshot) {
+ this._snapshot = snapshot;
+ }
+
+ public shouldUpdateSnapshot = () => {
+ this.updatingSnapshot = true;
+ };
+
+ // Suspicious that this is called so many places. Seems error-prone.
+ public shouldCaptureIncrement = () => {
+ this.calculatingIncrement = true;
+ };
+
+ public capture = (
+ elements: Map,
+ appState: AppState,
+ ): void => {
+ // Quick exit for irrelevant changes
+ if (!this.calculatingIncrement && !this.updatingSnapshot) {
+ return;
+ }
+
+ try {
+ const nextSnapshot = this._snapshot.clone(elements, appState);
+
+ // Optimisation, don't continue if nothing has changed
+ if (this._snapshot !== nextSnapshot) {
+ // Calculate and record the changes based on the previous and next snapshot
+ if (this.calculatingIncrement) {
+ const elementsChange = nextSnapshot.meta.didElementsChange
+ ? ElementsChange.calculate(
+ this._snapshot.elements,
+ nextSnapshot.elements,
+ )
+ : ElementsChange.empty();
+
+ const appStateChange = nextSnapshot.meta.didAppStateChange
+ ? AppStateChange.calculate(
+ this._snapshot.appState,
+ nextSnapshot.appState,
+ )
+ : AppStateChange.empty();
+
+ if (!elementsChange.isEmpty() || !appStateChange.isEmpty()) {
+ // Notify listeners with the increment
+ this.onStoreIncrementEmitter.trigger(
+ new StoreIncrementEvent(elementsChange, appStateChange),
+ );
+ }
+ }
+
+ // Update the snapshot
+ this._snapshot = nextSnapshot;
+ }
+ } finally {
+ // Reset props
+ this.updatingSnapshot = false;
+ this.calculatingIncrement = false;
+ }
+ };
+
+ public ignoreUncomittedElements = (
+ prevElements: Map,
+ nextElements: Map,
+ ) => {
+ for (const [id, prevElement] of prevElements.entries()) {
+ const nextElement = nextElements.get(id);
+
+ if (!nextElement) {
+ // Nothing to care about here, elements were forcefully deleted
+ continue;
+ }
+
+ const elementSnapshot = this._snapshot.elements.get(id);
+
+ // Checks for in progress async user action
+ if (!elementSnapshot) {
+ // Detected yet uncomitted local element
+ nextElements.delete(id);
+ } else if (elementSnapshot.version < prevElement.version) {
+ // Element was already commited, but the snapshot version is lower than current current local version
+ nextElements.set(id, elementSnapshot);
+ }
+ }
+
+ return nextElements;
+ };
+
+ public clear = (): void => {
+ this._snapshot = Snapshot.empty();
+ };
+}
+
+export class Snapshot {
+ private constructor(
+ public readonly elements: Map,
+ public readonly appState: ObservedAppState,
+ public readonly meta: {
+ didElementsChange: boolean;
+ didAppStateChange: boolean;
+ isEmpty?: boolean;
+ } = {
+ didElementsChange: false,
+ didAppStateChange: false,
+ isEmpty: false,
+ },
+ ) {}
+
+ public static empty() {
+ return new Snapshot(
+ new Map(),
+ getObservedAppState(getDefaultAppState() as AppState),
+ { didElementsChange: false, didAppStateChange: false, isEmpty: true },
+ );
+ }
+
+ public isEmpty() {
+ return this.meta.isEmpty;
+ }
+
+ /**
+ * Efficiently clone the existing snapshot.
+ *
+ * @returns same instance if there are no changes detected, new instance otherwise.
+ */
+ public clone(
+ elements: Map,
+ appState: AppState,
+ ) {
+ const didElementsChange = this.detectChangedElements(elements);
+
+ // Not watching over everything from app state, just the relevant props
+ const nextAppStateSnapshot = getObservedAppState(appState);
+ const didAppStateChange = this.detectChangedAppState(nextAppStateSnapshot);
+
+ // Nothing has changed, so there is no point of continuing further
+ if (!didElementsChange && !didAppStateChange) {
+ return this;
+ }
+
+ // Clone only if there was really a change
+ let nextElementsSnapshot = this.elements;
+ if (didElementsChange) {
+ nextElementsSnapshot = this.createElementsSnapshot(elements);
+ }
+
+ const snapshot = new Snapshot(nextElementsSnapshot, nextAppStateSnapshot, {
+ didElementsChange,
+ didAppStateChange,
+ });
+
+ return snapshot;
+ }
+
+ /**
+ * Detect if there any changed elements.
+ *
+ * NOTE: we shouldn't use `sceneVersionNonce` instead, as we need to call this before the scene updates.
+ */
+ private detectChangedElements(
+ nextElements: Map,
+ ) {
+ if (this.elements === nextElements) {
+ return false;
+ }
+
+ if (this.elements.size !== nextElements.size) {
+ return true;
+ }
+
+ // loop from right to left as changes are likelier to happen on new elements
+ const keys = Array.from(nextElements.keys());
+
+ for (let i = keys.length - 1; i >= 0; i--) {
+ const prev = this.elements.get(keys[i]);
+ const next = nextElements.get(keys[i]);
+ if (
+ !prev ||
+ !next ||
+ prev.id !== next.id ||
+ prev.versionNonce !== next.versionNonce
+ ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private detectChangedAppState(observedAppState: ObservedAppState) {
+ return !isShallowEqual(this.appState, observedAppState, {
+ selectedElementIds: isShallowEqual,
+ selectedGroupIds: isShallowEqual,
+ });
+ }
+
+ /**
+ * Perform structural clone, cloning only elements that changed.
+ */
+ private createElementsSnapshot(
+ nextElements: Map,
+ ) {
+ const clonedElements = new Map();
+
+ for (const [id, prevElement] of this.elements.entries()) {
+ // Clone previous elements, never delete, in case nextElements would be just a subset of previous elements
+ // i.e. during collab, persist or whenenever isDeleted elements get cleared
+ if (!nextElements.get(id)) {
+ // When we cannot find the prev element in the next elements, we mark it as deleted
+ clonedElements.set(
+ id,
+ newElementWith(prevElement, { isDeleted: true }),
+ );
+ } else {
+ clonedElements.set(id, prevElement);
+ }
+ }
+
+ for (const [id, nextElement] of nextElements.entries()) {
+ const prevElement = clonedElements.get(id);
+
+ // At this point our elements are reconcilled already, meaning the next element is always newer
+ if (
+ !prevElement || // element was added
+ (prevElement && prevElement.versionNonce !== nextElement.versionNonce) // element was updated
+ ) {
+ clonedElements.set(id, deepCopyElement(nextElement));
+ }
+ }
+
+ return clonedElements;
+ }
+}
diff --git a/packages/excalidraw/tests/__snapshots__/contextmenu.test.tsx.snap b/packages/excalidraw/tests/__snapshots__/contextmenu.test.tsx.snap
index 579ce84d27..fe869ab1fc 100644
--- a/packages/excalidraw/tests/__snapshots__/contextmenu.test.tsx.snap
+++ b/packages/excalidraw/tests/__snapshots__/contextmenu.test.tsx.snap
@@ -971,22 +971,15 @@ exports[`contextMenu element > right-clicking on a group should select whole gro
`;
exports[`contextMenu element > right-clicking on a group should select whole group > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [],
- },
- ],
+ "undoStack": [],
}
`;
@@ -1134,65 +1127,65 @@ exports[`contextMenu element > selecting 'Add to library' in context menu adds e
`;
exports[`contextMenu element > selecting 'Add to library' in context menu adds element to library > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [],
- },
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
},
- "seed": 449462985,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 1150084233,
- "width": 20,
- "x": -10,
- "y": 0,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 20,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 20,
+ "x": -10,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
],
}
@@ -1374,217 +1367,148 @@ exports[`contextMenu element > selecting 'Bring forward' in context menu brings
`;
exports[`contextMenu element > selecting 'Bring forward' in context menu brings element forward > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 20,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 20,
+ "x": -10,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
},
- "elements": [],
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
},
- "seed": 449462985,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 1150084233,
- "width": 20,
- "x": -10,
- "y": 0,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id1" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 20,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 20,
+ "x": 20,
+ "y": 30,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id0" => Delta {
+ "deleted": {
+ "index": "a2",
+ },
+ "inserted": {
+ "index": "a0",
+ },
},
- "seed": 449462985,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 1150084233,
- "width": 20,
- "x": -10,
- "y": 0,
},
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1014066025,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 1604849351,
- "width": 20,
- "x": 20,
- "y": 30,
- },
- ],
- },
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1014066025,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 1604849351,
- "width": 20,
- "x": 20,
- "y": 30,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id0",
- "index": "a2",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 449462985,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 23633383,
- "width": 20,
- "x": -10,
- "y": 0,
- },
- ],
},
],
}
@@ -1766,217 +1690,148 @@ exports[`contextMenu element > selecting 'Bring to front' in context menu brings
`;
exports[`contextMenu element > selecting 'Bring to front' in context menu brings element to front > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 20,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 20,
+ "x": -10,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
},
- "elements": [],
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
},
- "seed": 449462985,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 1150084233,
- "width": 20,
- "x": -10,
- "y": 0,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id1" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 20,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 20,
+ "x": 20,
+ "y": 30,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id0" => Delta {
+ "deleted": {
+ "index": "a2",
+ },
+ "inserted": {
+ "index": "a0",
+ },
},
- "seed": 449462985,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 1150084233,
- "width": 20,
- "x": -10,
- "y": 0,
},
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1014066025,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 1604849351,
- "width": 20,
- "x": 20,
- "y": 30,
- },
- ],
- },
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1014066025,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 1604849351,
- "width": 20,
- "x": 20,
- "y": 30,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id0",
- "index": "a2",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 449462985,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 23633383,
- "width": 20,
- "x": -10,
- "y": 0,
- },
- ],
},
],
}
@@ -2126,65 +1981,65 @@ exports[`contextMenu element > selecting 'Copy styles' in context menu copies st
`;
exports[`contextMenu element > selecting 'Copy styles' in context menu copies styles > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [],
- },
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
},
- "seed": 449462985,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 1150084233,
- "width": 20,
- "x": -10,
- "y": 0,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 20,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 20,
+ "x": -10,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
],
}
@@ -2330,108 +2185,93 @@ exports[`contextMenu element > selecting 'Delete' in context menu deletes elemen
`;
exports[`contextMenu element > selecting 'Delete' in context menu deletes element > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [],
- },
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 20,
- "x": -10,
- "y": 0,
- },
- ],
- },
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id0",
- "index": "a0",
- "isDeleted": true,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "inserted": {
+ "selectedElementIds": {},
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 1150084233,
- "width": 20,
- "x": -10,
- "y": 0,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 20,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 20,
+ "x": -10,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {},
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {
+ "id0" => Delta {
+ "deleted": {
+ "isDeleted": true,
+ },
+ "inserted": {
+ "isDeleted": false,
+ },
+ },
+ },
+ "removed": Map {},
+ "updated": Map {},
+ },
},
],
}
@@ -2613,141 +2453,118 @@ exports[`contextMenu element > selecting 'Duplicate' in context menu duplicates
`;
exports[`contextMenu element > selecting 'Duplicate' in context menu duplicates element > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 20,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 20,
+ "x": -10,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
},
- "elements": [],
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0_copy": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0_copy" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 20,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 20,
+ "x": 0,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 20,
- "x": -10,
- "y": 0,
},
- ],
- },
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0_copy": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
+ "updated": Map {},
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 20,
- "x": -10,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id0_copy",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 1116226695,
- "width": 20,
- "x": 0,
- "y": 10,
- },
- ],
},
],
}
@@ -2938,224 +2755,177 @@ exports[`contextMenu element > selecting 'Group selection' in context menu group
`;
exports[`contextMenu element > selecting 'Group selection' in context menu groups selected elements > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 20,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 20,
+ "x": -10,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
},
- "elements": [],
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 20,
- "x": -10,
- "y": 0,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id1" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 20,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 20,
+ "x": 20,
+ "y": 30,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 20,
- "x": -10,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 20,
- "x": 20,
- "y": 30,
- },
- ],
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedGroupIds": {
+ "id3": true,
+ },
+ },
+ "inserted": {
+ "selectedGroupIds": {},
+ },
},
- "selectedGroupIds": {
- "id3": true,
- },
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id3",
- ],
- "height": 20,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id0" => Delta {
+ "deleted": {
+ "groupIds": [
+ "id3",
+ ],
+ },
+ "inserted": {
+ "groupIds": [],
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 1505387817,
- "width": 20,
- "x": -10,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id3",
- ],
- "height": 20,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "id1" => Delta {
+ "deleted": {
+ "groupIds": [
+ "id3",
+ ],
+ },
+ "inserted": {
+ "groupIds": [],
+ },
},
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 23633383,
- "width": 20,
- "x": 20,
- "y": 30,
},
- ],
+ },
},
],
}
@@ -3339,673 +3109,290 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s
`;
exports[`contextMenu element > selecting 'Paste styles' in context menu pastes styles > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 20,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 20,
+ "x": -10,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
},
- "elements": [],
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 20,
- "x": -10,
- "y": 0,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id1" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 20,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 20,
+ "x": 20,
+ "y": 30,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id1" => Delta {
+ "deleted": {
+ "strokeColor": "#e03131",
+ },
+ "inserted": {
+ "strokeColor": "#1e1e1e",
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 20,
- "x": -10,
- "y": 0,
},
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 20,
- "x": 20,
- "y": 30,
- },
- ],
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id1" => Delta {
+ "deleted": {
+ "backgroundColor": "#a5d8ff",
+ },
+ "inserted": {
+ "backgroundColor": "transparent",
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 20,
- "x": -10,
- "y": 0,
},
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#e03131",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 1604849351,
- "width": 20,
- "x": 20,
- "y": 30,
- },
- ],
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id1" => Delta {
+ "deleted": {
+ "fillStyle": "cross-hatch",
+ },
+ "inserted": {
+ "fillStyle": "solid",
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 20,
- "x": -10,
- "y": 0,
},
- {
- "angle": 0,
- "backgroundColor": "#a5d8ff",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#e03131",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 5,
- "versionNonce": 23633383,
- "width": 20,
- "x": 20,
- "y": 30,
- },
- ],
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id1" => Delta {
+ "deleted": {
+ "strokeStyle": "dotted",
+ },
+ "inserted": {
+ "strokeStyle": "solid",
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 20,
- "x": -10,
- "y": 0,
},
- {
- "angle": 0,
- "backgroundColor": "#a5d8ff",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "cross-hatch",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#e03131",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 6,
- "versionNonce": 915032327,
- "width": 20,
- "x": 20,
- "y": 30,
- },
- ],
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id1" => Delta {
+ "deleted": {
+ "roughness": 2,
+ },
+ "inserted": {
+ "roughness": 1,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 20,
- "x": -10,
- "y": 0,
},
- {
- "angle": 0,
- "backgroundColor": "#a5d8ff",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "cross-hatch",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#e03131",
- "strokeStyle": "dotted",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 7,
- "versionNonce": 747212839,
- "width": 20,
- "x": 20,
- "y": 30,
- },
- ],
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id1" => Delta {
+ "deleted": {
+ "opacity": 60,
+ },
+ "inserted": {
+ "opacity": 100,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 20,
- "x": -10,
- "y": 0,
},
- {
- "angle": 0,
- "backgroundColor": "#a5d8ff",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "cross-hatch",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 2,
- "roundness": {
- "type": 3,
- },
- "seed": 760410951,
- "strokeColor": "#e03131",
- "strokeStyle": "dotted",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 8,
- "versionNonce": 1006504105,
- "width": 20,
- "x": 20,
- "y": 30,
- },
- ],
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id0" => Delta {
+ "deleted": {
+ "backgroundColor": "#a5d8ff",
+ "fillStyle": "cross-hatch",
+ "opacity": 60,
+ "roughness": 2,
+ "strokeColor": "#e03131",
+ "strokeStyle": "dotted",
+ },
+ "inserted": {
+ "backgroundColor": "transparent",
+ "fillStyle": "solid",
+ "opacity": 100,
+ "roughness": 1,
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 20,
- "x": -10,
- "y": 0,
},
- {
- "angle": 0,
- "backgroundColor": "#a5d8ff",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "cross-hatch",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 60,
- "roughness": 2,
- "roundness": {
- "type": 3,
- },
- "seed": 760410951,
- "strokeColor": "#e03131",
- "strokeStyle": "dotted",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 9,
- "versionNonce": 1315507081,
- "width": 20,
- "x": 20,
- "y": 30,
- },
- ],
- },
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "#a5d8ff",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "cross-hatch",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 60,
- "roughness": 2,
- "roundness": {
- "type": 3,
- },
- "seed": 1278240551,
- "strokeColor": "#e03131",
- "strokeStyle": "dotted",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 640725609,
- "width": 20,
- "x": -10,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "#a5d8ff",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "cross-hatch",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 60,
- "roughness": 2,
- "roundness": {
- "type": 3,
- },
- "seed": 760410951,
- "strokeColor": "#e03131",
- "strokeStyle": "dotted",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 9,
- "versionNonce": 1315507081,
- "width": 20,
- "x": 20,
- "y": 30,
- },
- ],
},
],
}
@@ -4187,217 +3574,140 @@ exports[`contextMenu element > selecting 'Send backward' in context menu sends e
`;
exports[`contextMenu element > selecting 'Send backward' in context menu sends element backward > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 20,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 20,
+ "x": -10,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
},
- "elements": [],
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
},
- "seed": 449462985,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 1150084233,
- "width": 20,
- "x": -10,
- "y": 0,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id1" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 20,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 20,
+ "x": 20,
+ "y": 30,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id1" => Delta {
+ "deleted": {
+ "index": "Zz",
+ },
+ "inserted": {
+ "index": "a1",
+ },
},
- "seed": 449462985,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 1150084233,
- "width": 20,
- "x": -10,
- "y": 0,
},
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1014066025,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 1604849351,
- "width": 20,
- "x": 20,
- "y": 30,
- },
- ],
- },
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id1",
- "index": "Zz",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1014066025,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 23633383,
- "width": 20,
- "x": 20,
- "y": 30,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 449462985,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 1150084233,
- "width": 20,
- "x": -10,
- "y": 0,
- },
- ],
},
],
}
@@ -4579,217 +3889,140 @@ exports[`contextMenu element > selecting 'Send to back' in context menu sends el
`;
exports[`contextMenu element > selecting 'Send to back' in context menu sends element to back > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 20,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 20,
+ "x": -10,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
},
- "elements": [],
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 20,
- "x": -10,
- "y": 0,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id1" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 20,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 20,
+ "x": 20,
+ "y": 30,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id1" => Delta {
+ "deleted": {
+ "index": "Zz",
+ },
+ "inserted": {
+ "index": "a1",
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 20,
- "x": -10,
- "y": 0,
},
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 20,
- "x": 20,
- "y": 30,
- },
- ],
- },
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id1",
- "index": "Zz",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 1604849351,
- "width": 20,
- "x": 20,
- "y": 30,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 20,
- "x": -10,
- "y": 0,
- },
- ],
},
],
}
@@ -4974,301 +4207,217 @@ exports[`contextMenu element > selecting 'Ungroup selection' in context menu ung
`;
exports[`contextMenu element > selecting 'Ungroup selection' in context menu ungroups selected group > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 20,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 20,
+ "x": -10,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
},
- "elements": [],
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
},
- "seed": 449462985,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 1150084233,
- "width": 20,
- "x": -10,
- "y": 0,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id1" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 20,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 20,
+ "x": 20,
+ "y": 30,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 449462985,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 1150084233,
- "width": 20,
- "x": -10,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 238820263,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 1505387817,
- "width": 20,
- "x": 20,
- "y": 30,
- },
- ],
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedGroupIds": {
+ "id3": true,
+ },
+ },
+ "inserted": {
+ "selectedGroupIds": {},
+ },
},
- "selectedGroupIds": {
- "id3": true,
- },
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id3",
- ],
- "height": 20,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id0" => Delta {
+ "deleted": {
+ "groupIds": [
+ "id3",
+ ],
+ },
+ "inserted": {
+ "groupIds": [],
+ },
},
- "seed": 449462985,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 915032327,
- "width": 20,
- "x": -10,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id3",
- ],
- "height": 20,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "id1" => Delta {
+ "deleted": {
+ "groupIds": [
+ "id3",
+ ],
+ },
+ "inserted": {
+ "groupIds": [],
+ },
},
- "seed": 238820263,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 81784553,
- "width": 20,
- "x": 20,
- "y": 30,
},
- ],
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedGroupIds": {},
+ },
+ "inserted": {
+ "selectedGroupIds": {
+ "id3": true,
+ },
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id0" => Delta {
+ "deleted": {
+ "groupIds": [],
+ },
+ "inserted": {
+ "groupIds": [
+ "id3",
+ ],
+ },
},
- "seed": 449462985,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 5,
- "versionNonce": 1723083209,
- "width": 20,
- "x": -10,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "id1" => Delta {
+ "deleted": {
+ "groupIds": [],
+ },
+ "inserted": {
+ "groupIds": [
+ "id3",
+ ],
+ },
},
- "seed": 238820263,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 5,
- "versionNonce": 760410951,
- "width": 20,
- "x": 20,
- "y": 30,
},
- ],
+ },
},
],
}
@@ -6242,141 +5391,158 @@ exports[`contextMenu element > shows 'Group selection' in context menu for multi
`;
exports[`contextMenu element > shows 'Group selection' in context menu for multiple selected elements > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": -10,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
},
- "elements": [],
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
},
- "seed": 449462985,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 1150084233,
- "width": 10,
- "x": -10,
- "y": 0,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id1" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 10,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
},
- "seed": 449462985,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 1150084233,
- "width": 10,
- "x": -10,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "inserted": {
+ "selectedElementIds": {},
},
- "seed": 1014066025,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 1604849351,
- "width": 10,
- "x": 10,
- "y": 0,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
},
],
}
@@ -7356,224 +6522,198 @@ exports[`contextMenu element > shows 'Ungroup selection' in context menu for gro
`;
exports[`contextMenu element > shows 'Ungroup selection' in context menu for group inside selected elements > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": -10,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
},
- "elements": [],
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
},
- "seed": 449462985,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 1150084233,
- "width": 10,
- "x": -10,
- "y": 0,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id1" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 10,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 449462985,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 1150084233,
- "width": 10,
- "x": -10,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 238820263,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 1505387817,
- "width": 10,
- "x": 10,
- "y": 0,
- },
- ],
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
},
- "selectedGroupIds": {
- "id4": true,
- },
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4",
- ],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedGroupIds": {
+ "id4": true,
+ },
},
- "seed": 449462985,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 81784553,
- "width": 10,
- "x": -10,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4",
- ],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "inserted": {
+ "selectedGroupIds": {},
},
- "seed": 238820263,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 747212839,
- "width": 10,
- "x": 10,
- "y": 0,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id0" => Delta {
+ "deleted": {
+ "groupIds": [
+ "id4",
+ ],
+ },
+ "inserted": {
+ "groupIds": [],
+ },
+ },
+ "id1" => Delta {
+ "deleted": {
+ "groupIds": [
+ "id4",
+ ],
+ },
+ "inserted": {
+ "groupIds": [],
+ },
+ },
+ },
+ },
},
],
}
@@ -8228,22 +7368,15 @@ exports[`contextMenu element > shows context menu for canvas > [end of test] app
`;
exports[`contextMenu element > shows context menu for canvas > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [],
- },
- ],
+ "undoStack": [],
}
`;
@@ -10141,87 +9274,80 @@ exports[`contextMenu element > shows context menu for element > [end of test] el
`;
exports[`contextMenu element > shows context menu for element > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [],
- },
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
},
- "seed": 449462985,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 1150084233,
- "width": 20,
- "x": -10,
- "y": 0,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 20,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 20,
+ "x": -10,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
],
}
`;
exports[`contextMenu element > shows context menu for element > [end of test] history 2`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [],
- },
- ],
+ "undoStack": [],
}
`;
diff --git a/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap b/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap
new file mode 100644
index 0000000000..fd33d8c2f1
--- /dev/null
+++ b/packages/excalidraw/tests/__snapshots__/history.test.tsx.snap
@@ -0,0 +1,18005 @@
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
+
+exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind bindings when both are updated through the history and the arrow got bound to a different element in the meantime > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": null,
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {
+ "id155": true,
+ },
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {
+ "id155": true,
+ },
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind bindings when both are updated through the history and the arrow got bound to a different element in the meantime > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": [],
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id153",
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 8,
+ "width": 100,
+ "x": -100,
+ "y": -50,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind bindings when both are updated through the history and the arrow got bound to a different element in the meantime > [end of test] element 1 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": [],
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id154",
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 9,
+ "width": 100,
+ "x": 100,
+ "y": -50,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind bindings when both are updated through the history and the arrow got bound to a different element in the meantime > [end of test] element 2 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "endArrowhead": "arrow",
+ "endBinding": {
+ "elementId": "id157",
+ "focus": 0,
+ "gap": 1,
+ },
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 99.19725525211979,
+ "id": "id155",
+ "index": "a2",
+ "isDeleted": false,
+ "lastCommittedPoint": null,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 98.40367721010284,
+ 99.19725525211979,
+ ],
+ ],
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "startArrowhead": null,
+ "startBinding": null,
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "arrow",
+ "updated": 1,
+ "version": 24,
+ "width": 98.40367721010284,
+ "x": 1.000000000000007,
+ "y": 0,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind bindings when both are updated through the history and the arrow got bound to a different element in the meantime > [end of test] element 3 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": [
+ {
+ "id": "id155",
+ "type": "arrow",
+ },
+ ],
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 50,
+ "id": "id157",
+ "index": "a3",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 6,
+ "width": 50,
+ "x": 100,
+ "y": 100,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind bindings when both are updated through the history and the arrow got bound to a different element in the meantime > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id153" => Delta {
+ "deleted": {
+ "boundElements": [],
+ },
+ "inserted": {
+ "boundElements": [
+ {
+ "id": "id155",
+ "type": "arrow",
+ },
+ ],
+ },
+ },
+ "id154" => Delta {
+ "deleted": {
+ "boundElements": [],
+ },
+ "inserted": {
+ "boundElements": [
+ {
+ "id": "id155",
+ "type": "arrow",
+ },
+ ],
+ },
+ },
+ "id155" => Delta {
+ "deleted": {
+ "endBinding": {
+ "elementId": "id157",
+ "focus": 0,
+ "gap": 1,
+ },
+ "height": 99.19725525211979,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 98.40367721010284,
+ 99.19725525211979,
+ ],
+ ],
+ "startBinding": null,
+ "y": 0,
+ },
+ "inserted": {
+ "endBinding": {
+ "elementId": "id154",
+ "focus": 0.009900990099009901,
+ "gap": 1,
+ },
+ "height": 0.9800000000000002,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 98,
+ -0.9800000000000002,
+ ],
+ ],
+ "startBinding": {
+ "elementId": "id153",
+ "focus": 0.0297029702970297,
+ "gap": 1,
+ },
+ "y": 0.9900000000000004,
+ },
+ },
+ "id157" => Delta {
+ "deleted": {
+ "boundElements": [
+ {
+ "id": "id155",
+ "type": "arrow",
+ },
+ ],
+ },
+ "inserted": {
+ "boundElements": [],
+ },
+ },
+ },
+ },
+ },
+ ],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id153" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": -100,
+ "y": -50,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ "id154" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": 100,
+ "y": -50,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id155": true,
+ },
+ "selectedLinearElementId": "id155",
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ "selectedLinearElementId": null,
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id155" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "endArrowhead": "arrow",
+ "endBinding": null,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 0,
+ "index": "a2",
+ "isDeleted": false,
+ "lastCommittedPoint": null,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 100,
+ 0,
+ ],
+ ],
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "startArrowhead": null,
+ "startBinding": null,
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "arrow",
+ "width": 100,
+ "x": 0,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind bindings when both are updated through the history and the arrow got bound to a different element in the meantime > [end of test] number of elements 1`] = `4`;
+
+exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind bindings when both are updated through the history and the arrow got bound to a different element in the meantime > [end of test] number of renders 1`] = `15`;
+
+exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind bindings when both are updated through the history and there are no conflicting updates in the meantime > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": null,
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {
+ "id151": true,
+ },
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {
+ "id151": true,
+ },
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind bindings when both are updated through the history and there are no conflicting updates in the meantime > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": [],
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id149",
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 9,
+ "width": 100,
+ "x": 150,
+ "y": -50,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind bindings when both are updated through the history and there are no conflicting updates in the meantime > [end of test] element 1 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": [],
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id150",
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 9,
+ "width": 100,
+ "x": 150,
+ "y": -50,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind bindings when both are updated through the history and there are no conflicting updates in the meantime > [end of test] element 2 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "endArrowhead": "arrow",
+ "endBinding": null,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 0,
+ "id": "id151",
+ "index": "a2",
+ "isDeleted": false,
+ "lastCommittedPoint": null,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 100,
+ 0,
+ ],
+ ],
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "startArrowhead": null,
+ "startBinding": null,
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "arrow",
+ "updated": 1,
+ "version": 23,
+ "width": 0,
+ "x": 251,
+ "y": 0,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind bindings when both are updated through the history and there are no conflicting updates in the meantime > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id149" => Delta {
+ "deleted": {
+ "boundElements": [],
+ },
+ "inserted": {
+ "boundElements": [
+ {
+ "id": "id151",
+ "type": "arrow",
+ },
+ ],
+ },
+ },
+ "id150" => Delta {
+ "deleted": {
+ "boundElements": [],
+ },
+ "inserted": {
+ "boundElements": [
+ {
+ "id": "id151",
+ "type": "arrow",
+ },
+ ],
+ },
+ },
+ "id151" => Delta {
+ "deleted": {
+ "endBinding": null,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 100,
+ 0,
+ ],
+ ],
+ "startBinding": null,
+ },
+ "inserted": {
+ "endBinding": {
+ "elementId": "id150",
+ "focus": 0,
+ "gap": 1,
+ },
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 0,
+ 0,
+ ],
+ ],
+ "startBinding": {
+ "elementId": "id149",
+ "focus": 0,
+ "gap": 1,
+ },
+ },
+ },
+ },
+ },
+ },
+ ],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id149" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": -100,
+ "y": -50,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ "id150" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": 100,
+ "y": -50,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id151": true,
+ },
+ "selectedLinearElementId": "id151",
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ "selectedLinearElementId": null,
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id151" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "endArrowhead": "arrow",
+ "endBinding": null,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 0,
+ "index": "a2",
+ "isDeleted": false,
+ "lastCommittedPoint": null,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 100,
+ 0,
+ ],
+ ],
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "startArrowhead": null,
+ "startBinding": null,
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "arrow",
+ "width": 100,
+ "x": 0,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind bindings when both are updated through the history and there are no conflicting updates in the meantime > [end of test] number of elements 1`] = `3`;
+
+exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind bindings when both are updated through the history and there are no conflicting updates in the meantime > [end of test] number of renders 1`] = `16`;
+
+exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind remotely added arrow when it's bindable elements are added through the history > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": {
+ "x": 0,
+ "y": 0,
+ },
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {},
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {},
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind remotely added arrow when it's bindable elements are added through the history > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "endArrowhead": null,
+ "endBinding": {
+ "elementId": "id159",
+ "focus": 0,
+ "gap": 1,
+ },
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 0.03596020595764898,
+ "id": "id160",
+ "index": "Zz",
+ "isDeleted": false,
+ "lastCommittedPoint": null,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 98,
+ -0.03596020595764898,
+ ],
+ ],
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "startArrowhead": null,
+ "startBinding": {
+ "elementId": "id158",
+ "focus": 0,
+ "gap": 1,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "arrow",
+ "updated": 1,
+ "version": 15,
+ "width": 98,
+ "x": 1,
+ "y": 0.05467419069071122,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind remotely added arrow when it's bindable elements are added through the history > [end of test] element 1 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": [
+ {
+ "id": "id160",
+ "type": "arrow",
+ },
+ ],
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id158",
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 7,
+ "width": 100,
+ "x": -100,
+ "y": -50,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind remotely added arrow when it's bindable elements are added through the history > [end of test] element 2 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": [
+ {
+ "id": "id160",
+ "type": "arrow",
+ },
+ ],
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id159",
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 7,
+ "width": 100,
+ "x": 100,
+ "y": -50,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind remotely added arrow when it's bindable elements are added through the history > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id158" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": -100,
+ "y": -50,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ "id159" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": 100,
+ "y": -50,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {
+ "id160" => Delta {
+ "deleted": {
+ "endBinding": {
+ "elementId": "id159",
+ "focus": 0,
+ "gap": 1,
+ },
+ "startBinding": {
+ "elementId": "id158",
+ "focus": 0,
+ "gap": 1,
+ },
+ },
+ "inserted": {
+ "endBinding": null,
+ "startBinding": null,
+ },
+ },
+ },
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind remotely added arrow when it's bindable elements are added through the history > [end of test] number of elements 1`] = `3`;
+
+exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind remotely added arrow when it's bindable elements are added through the history > [end of test] number of renders 1`] = `9`;
+
+exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind remotely added bindable elements when it's arrow is added through the history > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": {
+ "x": 0,
+ "y": 0,
+ },
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {},
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {},
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind remotely added bindable elements when it's arrow is added through the history > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "endArrowhead": null,
+ "endBinding": {
+ "elementId": "id162",
+ "focus": 0,
+ "gap": 1,
+ },
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 0.03596020595764898,
+ "id": "id163",
+ "index": "a0",
+ "isDeleted": false,
+ "lastCommittedPoint": null,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 98,
+ -0.03596020595764898,
+ ],
+ ],
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "startArrowhead": null,
+ "startBinding": {
+ "elementId": "id161",
+ "focus": 0,
+ "gap": 1,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "arrow",
+ "updated": 1,
+ "version": 15,
+ "width": 98,
+ "x": 1,
+ "y": 0.05467419069071122,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind remotely added bindable elements when it's arrow is added through the history > [end of test] element 1 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": [
+ {
+ "id": "id163",
+ "type": "arrow",
+ },
+ ],
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id161",
+ "index": "a0V",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 12,
+ "width": 100,
+ "x": -100,
+ "y": -50,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind remotely added bindable elements when it's arrow is added through the history > [end of test] element 2 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": [
+ {
+ "id": "id163",
+ "type": "arrow",
+ },
+ ],
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id162",
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 11,
+ "width": 100,
+ "x": 100,
+ "y": -50,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind remotely added bindable elements when it's arrow is added through the history > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id163" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "endArrowhead": null,
+ "endBinding": {
+ "elementId": "id162",
+ "focus": 0,
+ "gap": 1,
+ },
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 2.6199110083015196,
+ "index": "a0",
+ "isDeleted": false,
+ "lastCommittedPoint": null,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 98,
+ -2.6199110083015196,
+ ],
+ ],
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "startArrowhead": null,
+ "startBinding": {
+ "elementId": "id161",
+ "focus": 0,
+ "gap": 1,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "arrow",
+ "width": 98,
+ "x": 1,
+ "y": 3.98333408405027,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {
+ "id161" => Delta {
+ "deleted": {
+ "boundElements": [
+ {
+ "id": "id163",
+ "type": "arrow",
+ },
+ ],
+ },
+ "inserted": {
+ "boundElements": [],
+ },
+ },
+ "id162" => Delta {
+ "deleted": {
+ "boundElements": [
+ {
+ "id": "id163",
+ "type": "arrow",
+ },
+ ],
+ },
+ "inserted": {
+ "boundElements": [],
+ },
+ },
+ },
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind remotely added bindable elements when it's arrow is added through the history > [end of test] number of elements 1`] = `3`;
+
+exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should rebind remotely added bindable elements when it's arrow is added through the history > [end of test] number of renders 1`] = `11`;
+
+exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should unbind remotely deleted bindable elements from arrow when the arrow is added through the history > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": {
+ "x": 0,
+ "y": 0,
+ },
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {},
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {},
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should unbind remotely deleted bindable elements from arrow when the arrow is added through the history > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id164",
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 2,
+ "width": 100,
+ "x": -100,
+ "y": -50,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should unbind remotely deleted bindable elements from arrow when the arrow is added through the history > [end of test] element 1 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id165",
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 2,
+ "width": 100,
+ "x": 100,
+ "y": -50,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should unbind remotely deleted bindable elements from arrow when the arrow is added through the history > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id164" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": -100,
+ "y": -50,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ "id165" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": 100,
+ "y": -50,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should unbind remotely deleted bindable elements from arrow when the arrow is added through the history > [end of test] number of elements 1`] = `2`;
+
+exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should unbind remotely deleted bindable elements from arrow when the arrow is added through the history > [end of test] number of renders 1`] = `4`;
+
+exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should update bound element points when rectangle was remotely moved and arrow is added back through the history > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": null,
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {},
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {
+ "id168": true,
+ },
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should update bound element points when rectangle was remotely moved and arrow is added back through the history > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": [
+ {
+ "id": "id168",
+ "type": "arrow",
+ },
+ ],
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id166",
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 7,
+ "width": 100,
+ "x": -100,
+ "y": -50,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should update bound element points when rectangle was remotely moved and arrow is added back through the history > [end of test] element 1 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": [
+ {
+ "id": "id168",
+ "type": "arrow",
+ },
+ ],
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id167",
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 8,
+ "width": 100,
+ "x": 500,
+ "y": -500,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should update bound element points when rectangle was remotely moved and arrow is added back through the history > [end of test] element 2 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "endArrowhead": "arrow",
+ "endBinding": {
+ "elementId": "id167",
+ "focus": 0,
+ "gap": 1,
+ },
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 373.7994222717614,
+ "id": "id168",
+ "index": "a2",
+ "isDeleted": false,
+ "lastCommittedPoint": null,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 498,
+ -373.7994222717614,
+ ],
+ ],
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "startArrowhead": null,
+ "startBinding": {
+ "elementId": "id166",
+ "focus": 0,
+ "gap": 1,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "arrow",
+ "updated": 1,
+ "version": 12,
+ "width": 498,
+ "x": 1,
+ "y": -37.91991400161248,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should update bound element points when rectangle was remotely moved and arrow is added back through the history > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id166" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": -100,
+ "y": -50,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ "id167" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": 100,
+ "y": -50,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id168": true,
+ },
+ "selectedLinearElementId": "id168",
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ "selectedLinearElementId": null,
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id168" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "endArrowhead": "arrow",
+ "endBinding": {
+ "elementId": "id167",
+ "focus": 0,
+ "gap": 1,
+ },
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 0,
+ "index": "a2",
+ "isDeleted": false,
+ "lastCommittedPoint": null,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 100,
+ 0,
+ ],
+ ],
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "startArrowhead": null,
+ "startBinding": {
+ "elementId": "id166",
+ "focus": 0,
+ "gap": 1,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "arrow",
+ "width": 100,
+ "x": 0,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {
+ "id166" => Delta {
+ "deleted": {
+ "boundElements": [
+ {
+ "id": "id168",
+ "type": "arrow",
+ },
+ ],
+ },
+ "inserted": {
+ "boundElements": [],
+ },
+ },
+ "id167" => Delta {
+ "deleted": {
+ "boundElements": [
+ {
+ "id": "id168",
+ "type": "arrow",
+ },
+ ],
+ },
+ "inserted": {
+ "boundElements": [],
+ },
+ },
+ },
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should update bound element points when rectangle was remotely moved and arrow is added back through the history > [end of test] number of elements 1`] = `3`;
+
+exports[`history > multiplayer undo/redo > conflicts in arrows and their bindable elements > should update bound element points when rectangle was remotely moved and arrow is added back through the history > [end of test] number of renders 1`] = `10`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should preserve latest remotely added binding and unbind previous one when the container is added through the history > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": {
+ "x": 0,
+ "y": 0,
+ },
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {},
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {},
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should preserve latest remotely added binding and unbind previous one when the container is added through the history > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": [
+ {
+ "id": "id137",
+ "type": "text",
+ },
+ ],
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id135",
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 7,
+ "width": 100,
+ "x": 10,
+ "y": 10,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should preserve latest remotely added binding and unbind previous one when the container is added through the history > [end of test] element 1 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "containerId": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "fontFamily": 1,
+ "fontSize": 20,
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id136",
+ "index": "a1",
+ "isDeleted": false,
+ "lineHeight": 1.25,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "originalText": "que pasa",
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "text": "que pasa",
+ "textAlign": "left",
+ "type": "text",
+ "updated": 1,
+ "version": 6,
+ "verticalAlign": "top",
+ "width": 100,
+ "x": 15,
+ "y": 15,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should preserve latest remotely added binding and unbind previous one when the container is added through the history > [end of test] element 2 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "containerId": "id135",
+ "customData": undefined,
+ "fillStyle": "solid",
+ "fontFamily": 1,
+ "fontSize": 20,
+ "frameId": null,
+ "groupIds": [],
+ "height": 25,
+ "id": "id137",
+ "index": "a2",
+ "isDeleted": false,
+ "lineHeight": 1.25,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "originalText": "ola",
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "text": "ola",
+ "textAlign": "left",
+ "type": "text",
+ "updated": 1,
+ "version": 11,
+ "verticalAlign": "top",
+ "width": 30,
+ "x": 15,
+ "y": 15,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should preserve latest remotely added binding and unbind previous one when the container is added through the history > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id135" => Delta {
+ "deleted": {
+ "isDeleted": false,
+ },
+ "inserted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": 10,
+ "y": 10,
+ },
+ },
+ "id136" => Delta {
+ "deleted": {
+ "containerId": null,
+ },
+ "inserted": {
+ "containerId": null,
+ },
+ },
+ },
+ },
+ },
+ ],
+ "undoStack": [],
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should preserve latest remotely added binding and unbind previous one when the container is added through the history > [end of test] number of elements 1`] = `3`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should preserve latest remotely added binding and unbind previous one when the container is added through the history > [end of test] number of renders 1`] = `11`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should preserve latest remotely added binding and unbind previous one when the text is added through history > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": {
+ "x": 0,
+ "y": 0,
+ },
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {},
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {},
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should preserve latest remotely added binding and unbind previous one when the text is added through history > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": [
+ {
+ "id": "id140",
+ "type": "text",
+ },
+ ],
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id138",
+ "index": "Zz",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 11,
+ "width": 100,
+ "x": 10,
+ "y": 10,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should preserve latest remotely added binding and unbind previous one when the text is added through history > [end of test] element 1 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "containerId": "id138",
+ "customData": undefined,
+ "fillStyle": "solid",
+ "fontFamily": 1,
+ "fontSize": 20,
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id139",
+ "index": "a0",
+ "isDeleted": true,
+ "lineHeight": 1.25,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "originalText": "que pasa",
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "text": "que pasa",
+ "textAlign": "left",
+ "type": "text",
+ "updated": 1,
+ "version": 9,
+ "verticalAlign": "top",
+ "width": 100,
+ "x": 15,
+ "y": 15,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should preserve latest remotely added binding and unbind previous one when the text is added through history > [end of test] element 2 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "containerId": "id138",
+ "customData": undefined,
+ "fillStyle": "solid",
+ "fontFamily": 1,
+ "fontSize": 20,
+ "frameId": null,
+ "groupIds": [],
+ "height": 25,
+ "id": "id140",
+ "index": "a1",
+ "isDeleted": false,
+ "lineHeight": 1.25,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "originalText": "ola",
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "text": "ola",
+ "textAlign": "left",
+ "type": "text",
+ "updated": 1,
+ "version": 11,
+ "verticalAlign": "top",
+ "width": 30,
+ "x": 15,
+ "y": 15,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should preserve latest remotely added binding and unbind previous one when the text is added through history > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {
+ "id139" => Delta {
+ "deleted": {
+ "containerId": "id138",
+ "isDeleted": true,
+ },
+ "inserted": {
+ "containerId": null,
+ "isDeleted": false,
+ },
+ },
+ },
+ "removed": Map {},
+ "updated": Map {
+ "id138" => Delta {
+ "deleted": {
+ "boundElements": [],
+ },
+ "inserted": {
+ "boundElements": [
+ {
+ "id": "id139",
+ "type": "text",
+ },
+ ],
+ },
+ },
+ },
+ },
+ },
+ ],
+ "undoStack": [],
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should preserve latest remotely added binding and unbind previous one when the text is added through history > [end of test] number of elements 1`] = `3`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should preserve latest remotely added binding and unbind previous one when the text is added through history > [end of test] number of renders 1`] = `11`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should rebind bindings when both are updated through the history and the container got bound to a different text in the meantime > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": {
+ "x": 0,
+ "y": 0,
+ },
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {},
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {},
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should rebind bindings when both are updated through the history and the container got bound to a different text in the meantime > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": [
+ {
+ "id": "id127",
+ "type": "text",
+ },
+ ],
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id125",
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 10,
+ "width": 100,
+ "x": 10,
+ "y": 10,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should rebind bindings when both are updated through the history and the container got bound to a different text in the meantime > [end of test] element 1 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "containerId": "id125",
+ "customData": undefined,
+ "fillStyle": "solid",
+ "fontFamily": 1,
+ "fontSize": 20,
+ "frameId": null,
+ "groupIds": [],
+ "height": 25,
+ "id": "id127",
+ "index": "a0V",
+ "isDeleted": false,
+ "lineHeight": 1.25,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "originalText": "ola",
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "text": "ola",
+ "textAlign": "left",
+ "type": "text",
+ "updated": 1,
+ "version": 7,
+ "verticalAlign": "top",
+ "width": 30,
+ "x": 15,
+ "y": 15,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should rebind bindings when both are updated through the history and the container got bound to a different text in the meantime > [end of test] element 2 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "containerId": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "fontFamily": 1,
+ "fontSize": 20,
+ "frameId": null,
+ "groupIds": [],
+ "height": 25,
+ "id": "id126",
+ "index": "a1",
+ "isDeleted": false,
+ "lineHeight": 1.25,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "originalText": "que pasa",
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "text": "que pasa",
+ "textAlign": "left",
+ "type": "text",
+ "updated": 1,
+ "version": 9,
+ "verticalAlign": "top",
+ "width": 80,
+ "x": 15,
+ "y": 15,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should rebind bindings when both are updated through the history and the container got bound to a different text in the meantime > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id125" => Delta {
+ "deleted": {
+ "boundElements": [
+ {
+ "id": "id127",
+ "type": "text",
+ },
+ ],
+ },
+ "inserted": {
+ "boundElements": [
+ {
+ "id": "id126",
+ "type": "text",
+ },
+ ],
+ },
+ },
+ "id126" => Delta {
+ "deleted": {
+ "containerId": null,
+ },
+ "inserted": {
+ "containerId": "id125",
+ },
+ },
+ "id127" => Delta {
+ "deleted": {
+ "containerId": "id125",
+ },
+ "inserted": {
+ "containerId": null,
+ },
+ },
+ },
+ },
+ },
+ ],
+ "undoStack": [],
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should rebind bindings when both are updated through the history and the container got bound to a different text in the meantime > [end of test] number of elements 1`] = `3`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should rebind bindings when both are updated through the history and the container got bound to a different text in the meantime > [end of test] number of renders 1`] = `11`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should rebind bindings when both are updated through the history and the text got bound to a different container in the meantime > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": {
+ "x": 0,
+ "y": 0,
+ },
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {},
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {},
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should rebind bindings when both are updated through the history and the text got bound to a different container in the meantime > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": [],
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id128",
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 8,
+ "width": 100,
+ "x": 10,
+ "y": 10,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should rebind bindings when both are updated through the history and the text got bound to a different container in the meantime > [end of test] element 1 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": [
+ {
+ "id": "id129",
+ "type": "text",
+ },
+ ],
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 60,
+ "id": "id130",
+ "index": "a0V",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 8,
+ "width": 50,
+ "x": 100,
+ "y": 100,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should rebind bindings when both are updated through the history and the text got bound to a different container in the meantime > [end of test] element 2 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "containerId": "id130",
+ "customData": undefined,
+ "fillStyle": "solid",
+ "fontFamily": 1,
+ "fontSize": 20,
+ "frameId": null,
+ "groupIds": [],
+ "height": 50,
+ "id": "id129",
+ "index": "a1",
+ "isDeleted": false,
+ "lineHeight": 1.25,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "originalText": "que pasa",
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "text": "que
+pasa",
+ "textAlign": "left",
+ "type": "text",
+ "updated": 1,
+ "version": 13,
+ "verticalAlign": "top",
+ "width": 40,
+ "x": 105,
+ "y": 105,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should rebind bindings when both are updated through the history and the text got bound to a different container in the meantime > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id128" => Delta {
+ "deleted": {
+ "boundElements": [],
+ },
+ "inserted": {
+ "boundElements": [
+ {
+ "id": "id129",
+ "type": "text",
+ },
+ ],
+ },
+ },
+ "id129" => Delta {
+ "deleted": {
+ "containerId": "id130",
+ },
+ "inserted": {
+ "containerId": "id128",
+ },
+ },
+ "id130" => Delta {
+ "deleted": {
+ "boundElements": [
+ {
+ "id": "id129",
+ "type": "text",
+ },
+ ],
+ },
+ "inserted": {
+ "boundElements": [],
+ },
+ },
+ },
+ },
+ },
+ ],
+ "undoStack": [],
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should rebind bindings when both are updated through the history and the text got bound to a different container in the meantime > [end of test] number of elements 1`] = `3`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should rebind bindings when both are updated through the history and the text got bound to a different container in the meantime > [end of test] number of renders 1`] = `11`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should rebind bindings when both are updated through the history and there no conflicting updates in the meantime > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": {
+ "x": 0,
+ "y": 0,
+ },
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {},
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {},
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should rebind bindings when both are updated through the history and there no conflicting updates in the meantime > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": [],
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id123",
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 9,
+ "width": 100,
+ "x": 35,
+ "y": 10,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should rebind bindings when both are updated through the history and there no conflicting updates in the meantime > [end of test] element 1 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "containerId": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "fontFamily": 1,
+ "fontSize": 20,
+ "frameId": null,
+ "groupIds": [],
+ "height": 25,
+ "id": "id124",
+ "index": "a1",
+ "isDeleted": false,
+ "lineHeight": 1.25,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "originalText": "que pasa",
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "text": "que pasa",
+ "textAlign": "left",
+ "type": "text",
+ "updated": 1,
+ "version": 10,
+ "verticalAlign": "top",
+ "width": 80,
+ "x": 40,
+ "y": 15,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should rebind bindings when both are updated through the history and there no conflicting updates in the meantime > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id123" => Delta {
+ "deleted": {
+ "boundElements": [],
+ },
+ "inserted": {
+ "boundElements": [
+ {
+ "id": "id124",
+ "type": "text",
+ },
+ ],
+ },
+ },
+ "id124" => Delta {
+ "deleted": {
+ "containerId": null,
+ },
+ "inserted": {
+ "containerId": "id123",
+ },
+ },
+ },
+ },
+ },
+ ],
+ "undoStack": [],
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should rebind bindings when both are updated through the history and there no conflicting updates in the meantime > [end of test] number of elements 1`] = `2`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should rebind bindings when both are updated through the history and there no conflicting updates in the meantime > [end of test] number of renders 1`] = `11`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should rebind remotely added bound text when it's container is added through the history > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": {
+ "x": 0,
+ "y": 0,
+ },
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {},
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {},
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should rebind remotely added bound text when it's container is added through the history > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": [
+ {
+ "id": "id132",
+ "type": "text",
+ },
+ ],
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id131",
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 7,
+ "width": 100,
+ "x": 10,
+ "y": 10,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should rebind remotely added bound text when it's container is added through the history > [end of test] element 1 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "containerId": "id131",
+ "customData": undefined,
+ "fillStyle": "solid",
+ "fontFamily": 1,
+ "fontSize": 20,
+ "frameId": null,
+ "groupIds": [],
+ "height": 25,
+ "id": "id132",
+ "index": "a1",
+ "isDeleted": false,
+ "lineHeight": 1.25,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "originalText": "que pasa",
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "text": "que pasa",
+ "textAlign": "left",
+ "type": "text",
+ "updated": 1,
+ "version": 12,
+ "verticalAlign": "top",
+ "width": 80,
+ "x": 15,
+ "y": 15,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should rebind remotely added bound text when it's container is added through the history > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id131" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": 10,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {
+ "id132" => Delta {
+ "deleted": {
+ "containerId": "id131",
+ },
+ "inserted": {
+ "containerId": null,
+ },
+ },
+ },
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should rebind remotely added bound text when it's container is added through the history > [end of test] number of elements 1`] = `2`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should rebind remotely added bound text when it's container is added through the history > [end of test] number of renders 1`] = `9`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should rebind remotely added container when it's bound text is added through the history > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": {
+ "x": 0,
+ "y": 0,
+ },
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {},
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {},
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should rebind remotely added container when it's bound text is added through the history > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": [
+ {
+ "id": "id134",
+ "type": "text",
+ },
+ ],
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id133",
+ "index": "Zz",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 11,
+ "width": 100,
+ "x": 10,
+ "y": 10,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should rebind remotely added container when it's bound text is added through the history > [end of test] element 1 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "containerId": "id133",
+ "customData": undefined,
+ "fillStyle": "solid",
+ "fontFamily": 1,
+ "fontSize": 20,
+ "frameId": null,
+ "groupIds": [],
+ "height": 25,
+ "id": "id134",
+ "index": "a0",
+ "isDeleted": false,
+ "lineHeight": 1.25,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "originalText": "que pasa",
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "text": "que pasa",
+ "textAlign": "left",
+ "type": "text",
+ "updated": 1,
+ "version": 8,
+ "verticalAlign": "top",
+ "width": 80,
+ "x": 15,
+ "y": 15,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should rebind remotely added container when it's bound text is added through the history > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id134" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "containerId": "id133",
+ "customData": undefined,
+ "fillStyle": "solid",
+ "fontFamily": 1,
+ "fontSize": 20,
+ "frameId": null,
+ "groupIds": [],
+ "height": 25,
+ "index": "a0",
+ "isDeleted": false,
+ "lineHeight": 1.25,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "originalText": "que pasa",
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "text": "que pasa",
+ "textAlign": "left",
+ "type": "text",
+ "verticalAlign": "top",
+ "width": 80,
+ "x": 15,
+ "y": 15,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {
+ "id133" => Delta {
+ "deleted": {
+ "boundElements": [
+ {
+ "id": "id134",
+ "type": "text",
+ },
+ ],
+ },
+ "inserted": {
+ "boundElements": [],
+ },
+ },
+ },
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should rebind remotely added container when it's bound text is added through the history > [end of test] number of elements 1`] = `2`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should rebind remotely added container when it's bound text is added through the history > [end of test] number of renders 1`] = `9`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should redraw bound text to match container dimensions when the bound text is updated through the history > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": {
+ "x": 0,
+ "y": 0,
+ },
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {},
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {},
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should redraw bound text to match container dimensions when the bound text is updated through the history > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": [
+ {
+ "id": "id148",
+ "type": "text",
+ },
+ ],
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id147",
+ "index": "Zz",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 3,
+ "width": 100,
+ "x": 10,
+ "y": 10,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should redraw bound text to match container dimensions when the bound text is updated through the history > [end of test] element 1 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "containerId": "id147",
+ "customData": undefined,
+ "fillStyle": "solid",
+ "fontFamily": 1,
+ "fontSize": 20,
+ "frameId": null,
+ "groupIds": [],
+ "height": 25,
+ "id": "id148",
+ "index": "a0",
+ "isDeleted": false,
+ "lineHeight": 1.25,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "originalText": "que pasa",
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "text": "que pasa",
+ "textAlign": "left",
+ "type": "text",
+ "updated": 1,
+ "version": 7,
+ "verticalAlign": "top",
+ "width": 80,
+ "x": 15,
+ "y": 15,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should redraw bound text to match container dimensions when the bound text is updated through the history > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id148" => Delta {
+ "deleted": {
+ "angle": 0,
+ "x": 15,
+ "y": 15,
+ },
+ "inserted": {
+ "angle": 0,
+ "x": 15,
+ "y": 15,
+ },
+ },
+ },
+ },
+ },
+ ],
+ "undoStack": [],
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should redraw bound text to match container dimensions when the bound text is updated through the history > [end of test] number of elements 1`] = `2`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should redraw bound text to match container dimensions when the bound text is updated through the history > [end of test] number of renders 1`] = `9`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should redraw remotely added bound text when it's container is updated through the history > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": {
+ "x": 0,
+ "y": 0,
+ },
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {},
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {},
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should redraw remotely added bound text when it's container is updated through the history > [end of test] element 0 1`] = `
+{
+ "angle": 90,
+ "backgroundColor": "transparent",
+ "boundElements": [
+ {
+ "id": "id146",
+ "type": "text",
+ },
+ ],
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id145",
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 8,
+ "width": 100,
+ "x": 200,
+ "y": 200,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should redraw remotely added bound text when it's container is updated through the history > [end of test] element 1 1`] = `
+{
+ "angle": 90,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "containerId": "id145",
+ "customData": undefined,
+ "fillStyle": "solid",
+ "fontFamily": 1,
+ "fontSize": 20,
+ "frameId": null,
+ "groupIds": [],
+ "height": 25,
+ "id": "id146",
+ "index": "a1",
+ "isDeleted": false,
+ "lineHeight": 1.25,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "originalText": "que pasa",
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "text": "que pasa",
+ "textAlign": "left",
+ "type": "text",
+ "updated": 1,
+ "version": 6,
+ "verticalAlign": "top",
+ "width": 80,
+ "x": 205,
+ "y": 205,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should redraw remotely added bound text when it's container is updated through the history > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id145" => Delta {
+ "deleted": {
+ "angle": 90,
+ "x": 200,
+ "y": 200,
+ },
+ "inserted": {
+ "angle": 0,
+ "x": 10,
+ "y": 10,
+ },
+ },
+ },
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should redraw remotely added bound text when it's container is updated through the history > [end of test] number of elements 1`] = `2`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should redraw remotely added bound text when it's container is updated through the history > [end of test] number of renders 1`] = `10`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should unbind remotely deleted bound text from container when the container is added through the history > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": {
+ "x": 0,
+ "y": 0,
+ },
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {},
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {},
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should unbind remotely deleted bound text from container when the container is added through the history > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": [],
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id141",
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 8,
+ "width": 100,
+ "x": 10,
+ "y": 10,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should unbind remotely deleted bound text from container when the container is added through the history > [end of test] element 1 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "containerId": "id141",
+ "customData": undefined,
+ "fillStyle": "solid",
+ "fontFamily": 1,
+ "fontSize": 20,
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id142",
+ "index": "a1",
+ "isDeleted": true,
+ "lineHeight": 1.25,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "originalText": "que pasa",
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "text": "que pasa",
+ "textAlign": "left",
+ "type": "text",
+ "updated": 1,
+ "version": 3,
+ "verticalAlign": "top",
+ "width": 100,
+ "x": 15,
+ "y": 15,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should unbind remotely deleted bound text from container when the container is added through the history > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id141" => Delta {
+ "deleted": {
+ "boundElements": [],
+ "isDeleted": false,
+ },
+ "inserted": {
+ "boundElements": [
+ {
+ "id": "id142",
+ "type": "text",
+ },
+ ],
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should unbind remotely deleted bound text from container when the container is added through the history > [end of test] number of elements 1`] = `2`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should unbind remotely deleted bound text from container when the container is added through the history > [end of test] number of renders 1`] = `9`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should unbind remotely deleted container from bound text when the text is added through the history > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": {
+ "x": 0,
+ "y": 0,
+ },
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {},
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {},
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should unbind remotely deleted container from bound text when the text is added through the history > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": [
+ {
+ "id": "id144",
+ "type": "text",
+ },
+ ],
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id143",
+ "index": "Zz",
+ "isDeleted": true,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 3,
+ "width": 100,
+ "x": 10,
+ "y": 10,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should unbind remotely deleted container from bound text when the text is added through the history > [end of test] element 1 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "containerId": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "fontFamily": 1,
+ "fontSize": 20,
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id144",
+ "index": "a0",
+ "isDeleted": false,
+ "lineHeight": 1.25,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "originalText": "que pasa",
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "text": "que pasa",
+ "textAlign": "left",
+ "type": "text",
+ "updated": 1,
+ "version": 8,
+ "verticalAlign": "top",
+ "width": 100,
+ "x": 15,
+ "y": 15,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should unbind remotely deleted container from bound text when the text is added through the history > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id144" => Delta {
+ "deleted": {
+ "containerId": null,
+ "isDeleted": false,
+ },
+ "inserted": {
+ "containerId": "id143",
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should unbind remotely deleted container from bound text when the text is added through the history > [end of test] number of elements 1`] = `2`;
+
+exports[`history > multiplayer undo/redo > conflicts in bound text elements and their containers > should unbind remotely deleted container from bound text when the text is added through the history > [end of test] number of renders 1`] = `9`;
+
+exports[`history > multiplayer undo/redo > conflicts in frames and their children > should not rebind frame child with frame when frame was remotely deleted and frame child is added back through the history > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": {
+ "x": 0,
+ "y": 0,
+ },
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {},
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {},
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in frames and their children > should not rebind frame child with frame when frame was remotely deleted and frame child is added back through the history > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id170",
+ "index": "Zz",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 10,
+ "width": 100,
+ "x": 10,
+ "y": 10,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in frames and their children > should not rebind frame child with frame when frame was remotely deleted and frame child is added back through the history > [end of test] element 1 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 500,
+ "id": "id169",
+ "index": "a0",
+ "isDeleted": true,
+ "link": null,
+ "locked": false,
+ "name": null,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "frame",
+ "updated": 1,
+ "version": 3,
+ "width": 500,
+ "x": 0,
+ "y": 0,
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in frames and their children > should not rebind frame child with frame when frame was remotely deleted and frame child is added back through the history > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id170" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "Zz",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": 10,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id170" => Delta {
+ "deleted": {
+ "frameId": "id169",
+ },
+ "inserted": {
+ "frameId": null,
+ },
+ },
+ },
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > multiplayer undo/redo > conflicts in frames and their children > should not rebind frame child with frame when frame was remotely deleted and frame child is added back through the history > [end of test] number of elements 1`] = `2`;
+
+exports[`history > multiplayer undo/redo > conflicts in frames and their children > should not rebind frame child with frame when frame was remotely deleted and frame child is added back through the history > [end of test] number of renders 1`] = `13`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when editing group contains only remotely deleted elements > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": null,
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {
+ "id100": true,
+ },
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {},
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when editing group contains only remotely deleted elements > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [
+ "A",
+ ],
+ "height": 100,
+ "id": "id99",
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 5,
+ "width": 100,
+ "x": 0,
+ "y": 0,
+}
+`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when editing group contains only remotely deleted elements > [end of test] element 1 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [
+ "A",
+ ],
+ "height": 100,
+ "id": "id100",
+ "index": "a1",
+ "isDeleted": true,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 4,
+ "width": 100,
+ "x": 100,
+ "y": 100,
+}
+`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when editing group contains only remotely deleted elements > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id100": true,
+ "id99": true,
+ },
+ "selectedGroupIds": {
+ "A": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ "selectedGroupIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id99" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [
+ "A",
+ ],
+ "height": 100,
+ "index": "a0",
+ "isDeleted": true,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": 0,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ "id100" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [
+ "A",
+ ],
+ "height": 100,
+ "index": "a1",
+ "isDeleted": true,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": 100,
+ "y": 100,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "editingGroupId": "A",
+ "selectedElementIds": {},
+ "selectedGroupIds": {},
+ },
+ "inserted": {
+ "editingGroupId": null,
+ "selectedElementIds": {
+ "id99": true,
+ },
+ "selectedGroupIds": {
+ "A": true,
+ },
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "editingGroupId": null,
+ "selectedElementIds": {},
+ },
+ "inserted": {
+ "editingGroupId": "A",
+ "selectedElementIds": {
+ "id100": true,
+ },
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when editing group contains only remotely deleted elements > [end of test] number of elements 1`] = `2`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when editing group contains only remotely deleted elements > [end of test] number of renders 1`] = `13`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when element changes relate only to remotely deleted elements > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "#ffc9c9",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": "elementBackground",
+ "openSidebar": null,
+ "originSnapOffset": null,
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {
+ "id87": true,
+ },
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {},
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when element changes relate only to remotely deleted elements > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "id": "id85",
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 3,
+ "width": 10,
+ "x": 10,
+ "y": 0,
+}
+`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when element changes relate only to remotely deleted elements > [end of test] element 1 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "#ffc9c9",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "id": "id86",
+ "index": "a1",
+ "isDeleted": true,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 7,
+ "width": 10,
+ "x": 20,
+ "y": 0,
+}
+`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when element changes relate only to remotely deleted elements > [end of test] element 2 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "#ffc9c9",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "id": "id87",
+ "index": "a2",
+ "isDeleted": true,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 7,
+ "width": 10,
+ "x": 50,
+ "y": 50,
+}
+`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when element changes relate only to remotely deleted elements > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id85": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id85" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 10,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id86": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id85": true,
+ },
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id86" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "#ffc9c9",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a1",
+ "isDeleted": true,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 20,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id86" => Delta {
+ "deleted": {
+ "backgroundColor": "#ffc9c9",
+ },
+ "inserted": {
+ "backgroundColor": "transparent",
+ },
+ },
+ },
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id87": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id86": true,
+ },
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id87" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "#ffc9c9",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a2",
+ "isDeleted": true,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 50,
+ "y": 50,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id87" => Delta {
+ "deleted": {
+ "x": 50,
+ "y": 50,
+ },
+ "inserted": {
+ "x": 30,
+ "y": 30,
+ },
+ },
+ },
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when element changes relate only to remotely deleted elements > [end of test] number of elements 1`] = `3`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when element changes relate only to remotely deleted elements > [end of test] number of renders 1`] = `20`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when selected elements relate only to remotely deleted elements > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": null,
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {
+ "id90": true,
+ },
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {
+ "id90": true,
+ "id91": true,
+ },
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when selected elements relate only to remotely deleted elements > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id89",
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 2,
+ "width": 100,
+ "x": 10,
+ "y": 10,
+}
+`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when selected elements relate only to remotely deleted elements > [end of test] element 1 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id90",
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 4,
+ "width": 100,
+ "x": 20,
+ "y": 20,
+}
+`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when selected elements relate only to remotely deleted elements > [end of test] element 2 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id91",
+ "index": "a2",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 4,
+ "width": 100,
+ "x": 30,
+ "y": 30,
+}
+`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when selected elements relate only to remotely deleted elements > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id89": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id89" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": 10,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ "id90" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": 20,
+ "y": 20,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ "id91" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a2",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": 30,
+ "y": 30,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id90": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id89": true,
+ },
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id91": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when selected elements relate only to remotely deleted elements > [end of test] number of elements 1`] = `3`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when selected elements relate only to remotely deleted elements > [end of test] number of renders 1`] = `15`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when selected groups contain only remotely deleted elements > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": {
+ "x": 0,
+ "y": 0,
+ },
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {},
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {
+ "id95": true,
+ "id96": true,
+ "id97": true,
+ "id98": true,
+ },
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {
+ "A": true,
+ "B": true,
+ },
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when selected groups contain only remotely deleted elements > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [
+ "A",
+ ],
+ "height": 100,
+ "id": "id95",
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 4,
+ "width": 100,
+ "x": 0,
+ "y": 0,
+}
+`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when selected groups contain only remotely deleted elements > [end of test] element 1 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [
+ "A",
+ ],
+ "height": 100,
+ "id": "id96",
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 4,
+ "width": 100,
+ "x": 0,
+ "y": 0,
+}
+`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when selected groups contain only remotely deleted elements > [end of test] element 2 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [
+ "B",
+ ],
+ "height": 100,
+ "id": "id97",
+ "index": "a2",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 2,
+ "width": 100,
+ "x": 0,
+ "y": 0,
+}
+`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when selected groups contain only remotely deleted elements > [end of test] element 3 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [
+ "B",
+ ],
+ "height": 100,
+ "id": "id98",
+ "index": "a3",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 2,
+ "width": 100,
+ "x": 0,
+ "y": 0,
+}
+`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when selected groups contain only remotely deleted elements > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id95": true,
+ "id96": true,
+ },
+ "selectedGroupIds": {
+ "A": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ "selectedGroupIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id97": true,
+ "id98": true,
+ },
+ "selectedGroupIds": {
+ "B": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ "selectedGroupIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when selected groups contain only remotely deleted elements > [end of test] number of elements 1`] = `4`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when selected groups contain only remotely deleted elements > [end of test] number of renders 1`] = `15`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when selected or editing linear element was remotely deleted > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": null,
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {},
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {},
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when selected or editing linear element was remotely deleted > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "endArrowhead": "arrow",
+ "endBinding": null,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "id": "id103",
+ "index": "a0",
+ "isDeleted": true,
+ "lastCommittedPoint": [
+ 10,
+ 10,
+ ],
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 10,
+ 10,
+ ],
+ ],
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "startArrowhead": null,
+ "startBinding": null,
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "arrow",
+ "updated": 1,
+ "version": 8,
+ "width": 10,
+ "x": -10,
+ "y": -10,
+}
+`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when selected or editing linear element was remotely deleted > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id103": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id103" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "endArrowhead": "arrow",
+ "endBinding": null,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": true,
+ "lastCommittedPoint": [
+ 10,
+ 10,
+ ],
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 10,
+ 10,
+ ],
+ ],
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "startArrowhead": null,
+ "startBinding": null,
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "arrow",
+ "width": 10,
+ "x": -10,
+ "y": -10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedLinearElementId": "id103",
+ },
+ "inserted": {
+ "selectedLinearElementId": null,
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "editingLinearElementId": "id103",
+ },
+ "inserted": {
+ "editingLinearElementId": null,
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "editingLinearElementId": null,
+ "selectedLinearElementId": null,
+ },
+ "inserted": {
+ "editingLinearElementId": "id103",
+ "selectedLinearElementId": "id103",
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when selected or editing linear element was remotely deleted > [end of test] number of elements 1`] = `1`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when selected or editing linear element was remotely deleted > [end of test] number of renders 1`] = `11`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when when element change relates to remotely deleted element > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "#ffc9c9",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": "elementBackground",
+ "openSidebar": null,
+ "originSnapOffset": null,
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {},
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {},
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when when element change relates to remotely deleted element > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "#ffec99",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "id": "id84",
+ "index": "a0",
+ "isDeleted": true,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 7,
+ "width": 10,
+ "x": 10,
+ "y": 0,
+}
+`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when when element change relates to remotely deleted element > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id84": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id84" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "#ffec99",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": true,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 10,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id84" => Delta {
+ "deleted": {
+ "backgroundColor": "#ffec99",
+ },
+ "inserted": {
+ "backgroundColor": "transparent",
+ },
+ },
+ },
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when when element change relates to remotely deleted element > [end of test] number of elements 1`] = `1`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when when element change relates to remotely deleted element > [end of test] number of renders 1`] = `10`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when z-index changes do not produce visible change and we synced all indices > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": null,
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {},
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {},
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when z-index changes do not produce visible change and we synced all indices > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id109",
+ "index": "a1",
+ "isDeleted": true,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 8,
+ "width": 100,
+ "x": 20,
+ "y": 20,
+}
+`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when z-index changes do not produce visible change and we synced all indices > [end of test] element 1 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id110",
+ "index": "a3V",
+ "isDeleted": true,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 4,
+ "width": 100,
+ "x": 30,
+ "y": 30,
+}
+`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when z-index changes do not produce visible change and we synced all indices > [end of test] element 2 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id108",
+ "index": "a4",
+ "isDeleted": true,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 4,
+ "width": 100,
+ "x": 10,
+ "y": 10,
+}
+`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when z-index changes do not produce visible change and we synced all indices > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id109" => Delta {
+ "deleted": {
+ "index": "a1",
+ },
+ "inserted": {
+ "index": "a3",
+ },
+ },
+ },
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {},
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id109": true,
+ },
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {
+ "id108" => Delta {
+ "deleted": {
+ "isDeleted": true,
+ },
+ "inserted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a4",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": 10,
+ "y": 10,
+ },
+ },
+ "id109" => Delta {
+ "deleted": {
+ "isDeleted": true,
+ },
+ "inserted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a3",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": 20,
+ "y": 20,
+ },
+ },
+ "id110" => Delta {
+ "deleted": {
+ "isDeleted": true,
+ },
+ "inserted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a3V",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": 30,
+ "y": 30,
+ },
+ },
+ },
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ ],
+ "undoStack": [],
+}
+`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when z-index changes do not produce visible change and we synced all indices > [end of test] number of elements 1`] = `3`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when z-index changes do not produce visible change and we synced all indices > [end of test] number of renders 1`] = `11`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when z-index changes do not produce visible change and we synced changed indices > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": null,
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {},
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {},
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when z-index changes do not produce visible change and we synced changed indices > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id104",
+ "index": "Zx",
+ "isDeleted": true,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 4,
+ "width": 100,
+ "x": 10,
+ "y": 10,
+}
+`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when z-index changes do not produce visible change and we synced changed indices > [end of test] element 1 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id106",
+ "index": "Zy",
+ "isDeleted": true,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 4,
+ "width": 100,
+ "x": 30,
+ "y": 30,
+}
+`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when z-index changes do not produce visible change and we synced changed indices > [end of test] element 2 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id105",
+ "index": "a1",
+ "isDeleted": true,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 7,
+ "width": 100,
+ "x": 20,
+ "y": 20,
+}
+`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when z-index changes do not produce visible change and we synced changed indices > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id105" => Delta {
+ "deleted": {
+ "index": "a1",
+ },
+ "inserted": {
+ "index": "Zz",
+ },
+ },
+ },
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {},
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id105": true,
+ },
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {
+ "id104" => Delta {
+ "deleted": {
+ "isDeleted": true,
+ },
+ "inserted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "Zx",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": 10,
+ "y": 10,
+ },
+ },
+ "id105" => Delta {
+ "deleted": {
+ "isDeleted": true,
+ },
+ "inserted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "Zz",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": 20,
+ "y": 20,
+ },
+ },
+ "id106" => Delta {
+ "deleted": {
+ "isDeleted": true,
+ },
+ "inserted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "Zy",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": 30,
+ "y": 30,
+ },
+ },
+ },
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ ],
+ "undoStack": [],
+}
+`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when z-index changes do not produce visible change and we synced changed indices > [end of test] number of elements 1`] = `3`;
+
+exports[`history > multiplayer undo/redo > should iterate through the history when z-index changes do not produce visible change and we synced changed indices > [end of test] number of renders 1`] = `11`;
+
+exports[`history > multiplayer undo/redo > should not let remote changes to interfere with in progress dragging > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": null,
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {
+ "id117": true,
+ "id118": true,
+ },
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {
+ "id117": true,
+ "id118": true,
+ },
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > multiplayer undo/redo > should not let remote changes to interfere with in progress dragging > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "id": "id117",
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 9,
+ "width": 10,
+ "x": 90,
+ "y": 90,
+}
+`;
+
+exports[`history > multiplayer undo/redo > should not let remote changes to interfere with in progress dragging > [end of test] element 1 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "id": "id118",
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 9,
+ "width": 10,
+ "x": 110,
+ "y": 110,
+}
+`;
+
+exports[`history > multiplayer undo/redo > should not let remote changes to interfere with in progress dragging > [end of test] element 2 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id122",
+ "index": "a2",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#a5d8ff",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 2,
+ "width": 100,
+ "x": 0,
+ "y": 0,
+}
+`;
+
+exports[`history > multiplayer undo/redo > should not let remote changes to interfere with in progress dragging > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id117": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id117" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 10,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id118": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id117": true,
+ },
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id118" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 30,
+ "y": 30,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id117": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id118": true,
+ },
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id118": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id117" => Delta {
+ "deleted": {
+ "x": 90,
+ "y": 90,
+ },
+ "inserted": {
+ "x": 10,
+ "y": 10,
+ },
+ },
+ "id118" => Delta {
+ "deleted": {
+ "x": 110,
+ "y": 110,
+ },
+ "inserted": {
+ "x": 30,
+ "y": 30,
+ },
+ },
+ },
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > multiplayer undo/redo > should not let remote changes to interfere with in progress dragging > [end of test] number of elements 1`] = `3`;
+
+exports[`history > multiplayer undo/redo > should not let remote changes to interfere with in progress dragging > [end of test] number of renders 1`] = `27`;
+
+exports[`history > multiplayer undo/redo > should not let remote changes to interfere with in progress freedraw > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "freedraw",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": null,
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {},
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {},
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > multiplayer undo/redo > should not let remote changes to interfere with in progress freedraw > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 50,
+ "id": "id112",
+ "index": "a0",
+ "isDeleted": false,
+ "lastCommittedPoint": [
+ 50,
+ 50,
+ ],
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 20,
+ 20,
+ ],
+ [
+ 50,
+ 50,
+ ],
+ [
+ 50,
+ 50,
+ ],
+ ],
+ "pressures": [
+ 0,
+ 0,
+ 0,
+ 0,
+ ],
+ "roughness": 1,
+ "roundness": null,
+ "simulatePressure": false,
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "freedraw",
+ "updated": 1,
+ "version": 8,
+ "width": 50,
+ "x": 10,
+ "y": 10,
+}
+`;
+
+exports[`history > multiplayer undo/redo > should not let remote changes to interfere with in progress freedraw > [end of test] element 1 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id113",
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#a5d8ff",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 2,
+ "width": 100,
+ "x": 0,
+ "y": 0,
+}
+`;
+
+exports[`history > multiplayer undo/redo > should not let remote changes to interfere with in progress freedraw > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id112" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 50,
+ "index": "a0",
+ "isDeleted": false,
+ "lastCommittedPoint": [
+ 50,
+ 50,
+ ],
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 20,
+ 20,
+ ],
+ [
+ 50,
+ 50,
+ ],
+ [
+ 50,
+ 50,
+ ],
+ ],
+ "pressures": [
+ 0,
+ 0,
+ 0,
+ 0,
+ ],
+ "roughness": 1,
+ "roundness": null,
+ "simulatePressure": false,
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "freedraw",
+ "width": 50,
+ "x": 10,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > multiplayer undo/redo > should not let remote changes to interfere with in progress freedraw > [end of test] number of elements 1`] = `2`;
+
+exports[`history > multiplayer undo/redo > should not let remote changes to interfere with in progress freedraw > [end of test] number of renders 1`] = `10`;
+
+exports[`history > multiplayer undo/redo > should not let remote changes to interfere with in progress resizing > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": null,
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {},
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {
+ "id114": true,
+ },
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > multiplayer undo/redo > should not let remote changes to interfere with in progress resizing > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 90,
+ "id": "id114",
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 9,
+ "width": 90,
+ "x": 10,
+ "y": 10,
+}
+`;
+
+exports[`history > multiplayer undo/redo > should not let remote changes to interfere with in progress resizing > [end of test] element 1 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id116",
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#a5d8ff",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 2,
+ "width": 100,
+ "x": 0,
+ "y": 0,
+}
+`;
+
+exports[`history > multiplayer undo/redo > should not let remote changes to interfere with in progress resizing > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id114": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id114" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 10,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id114" => Delta {
+ "deleted": {
+ "height": 90,
+ "width": 90,
+ },
+ "inserted": {
+ "height": 10,
+ "width": 10,
+ },
+ },
+ },
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > multiplayer undo/redo > should not let remote changes to interfere with in progress resizing > [end of test] number of elements 1`] = `2`;
+
+exports[`history > multiplayer undo/redo > should not let remote changes to interfere with in progress resizing > [end of test] number of renders 1`] = `14`;
+
+exports[`history > multiplayer undo/redo > should not override remote changes on different elements > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "#ffc9c9",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": "elementBackground",
+ "openSidebar": null,
+ "originSnapOffset": null,
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {},
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {
+ "id74": true,
+ },
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > multiplayer undo/redo > should not override remote changes on different elements > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "id": "id74",
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 7,
+ "width": 10,
+ "x": 10,
+ "y": 0,
+}
+`;
+
+exports[`history > multiplayer undo/redo > should not override remote changes on different elements > [end of test] element 1 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "#ffc9c9",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id75",
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#a5d8ff",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 2,
+ "width": 100,
+ "x": 0,
+ "y": 0,
+}
+`;
+
+exports[`history > multiplayer undo/redo > should not override remote changes on different elements > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id74" => Delta {
+ "deleted": {
+ "backgroundColor": "transparent",
+ },
+ "inserted": {
+ "backgroundColor": "#ffc9c9",
+ },
+ },
+ },
+ },
+ },
+ ],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id74": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id74" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 10,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > multiplayer undo/redo > should not override remote changes on different elements > [end of test] number of elements 1`] = `2`;
+
+exports[`history > multiplayer undo/redo > should not override remote changes on different elements > [end of test] number of renders 1`] = `11`;
+
+exports[`history > multiplayer undo/redo > should not override remote changes on different properties > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "#ffc9c9",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": "elementBackground",
+ "openSidebar": null,
+ "originSnapOffset": null,
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {},
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {
+ "id76": true,
+ },
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > multiplayer undo/redo > should not override remote changes on different properties > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "#ffc9c9",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "id": "id76",
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#ffec99",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 7,
+ "width": 10,
+ "x": 10,
+ "y": 0,
+}
+`;
+
+exports[`history > multiplayer undo/redo > should not override remote changes on different properties > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id76": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id76" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 10,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id76" => Delta {
+ "deleted": {
+ "backgroundColor": "#ffc9c9",
+ },
+ "inserted": {
+ "backgroundColor": "transparent",
+ },
+ },
+ },
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > multiplayer undo/redo > should not override remote changes on different properties > [end of test] number of elements 1`] = `1`;
+
+exports[`history > multiplayer undo/redo > should not override remote changes on different properties > [end of test] number of renders 1`] = `10`;
+
+exports[`history > multiplayer undo/redo > should override remotely added groups on undo, but restore them on redo > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": {
+ "x": 0,
+ "y": 0,
+ },
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {},
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {},
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > multiplayer undo/redo > should override remotely added groups on undo, but restore them on redo > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [
+ "A",
+ "B",
+ ],
+ "height": 100,
+ "id": "id78",
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 6,
+ "width": 100,
+ "x": 0,
+ "y": 0,
+}
+`;
+
+exports[`history > multiplayer undo/redo > should override remotely added groups on undo, but restore them on redo > [end of test] element 1 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [
+ "A",
+ "B",
+ ],
+ "height": 100,
+ "id": "id79",
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 6,
+ "width": 100,
+ "x": 0,
+ "y": 0,
+}
+`;
+
+exports[`history > multiplayer undo/redo > should override remotely added groups on undo, but restore them on redo > [end of test] element 2 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [
+ "B",
+ ],
+ "height": 100,
+ "id": "id80",
+ "index": "a2",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 2,
+ "width": 100,
+ "x": 0,
+ "y": 0,
+}
+`;
+
+exports[`history > multiplayer undo/redo > should override remotely added groups on undo, but restore them on redo > [end of test] element 3 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [
+ "B",
+ ],
+ "height": 100,
+ "id": "id81",
+ "index": "a3",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 2,
+ "width": 100,
+ "x": 0,
+ "y": 0,
+}
+`;
+
+exports[`history > multiplayer undo/redo > should override remotely added groups on undo, but restore them on redo > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id78" => Delta {
+ "deleted": {
+ "groupIds": [
+ "A",
+ "B",
+ ],
+ },
+ "inserted": {
+ "groupIds": [],
+ },
+ },
+ "id79" => Delta {
+ "deleted": {
+ "groupIds": [
+ "A",
+ "B",
+ ],
+ },
+ "inserted": {
+ "groupIds": [],
+ },
+ },
+ },
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > multiplayer undo/redo > should override remotely added groups on undo, but restore them on redo > [end of test] number of elements 1`] = `4`;
+
+exports[`history > multiplayer undo/redo > should override remotely added groups on undo, but restore them on redo > [end of test] number of renders 1`] = `8`;
+
+exports[`history > multiplayer undo/redo > should override remotely added points on undo, but restore them on redo > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": null,
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {},
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {
+ "id82": true,
+ },
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > multiplayer undo/redo > should override remotely added points on undo, but restore them on redo > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "endArrowhead": "arrow",
+ "endBinding": null,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 20,
+ "id": "id82",
+ "index": "a0",
+ "isDeleted": false,
+ "lastCommittedPoint": [
+ 30,
+ 30,
+ ],
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 5,
+ 5,
+ ],
+ [
+ 10,
+ 10,
+ ],
+ [
+ 15,
+ 15,
+ ],
+ [
+ 20,
+ 20,
+ ],
+ ],
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "startArrowhead": null,
+ "startBinding": null,
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "arrow",
+ "updated": 1,
+ "version": 14,
+ "width": 20,
+ "x": 0,
+ "y": 0,
+}
+`;
+
+exports[`history > multiplayer undo/redo > should override remotely added points on undo, but restore them on redo > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id82": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id82" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "endArrowhead": "arrow",
+ "endBinding": null,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "lastCommittedPoint": [
+ 10,
+ 10,
+ ],
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 10,
+ 10,
+ ],
+ ],
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "startArrowhead": null,
+ "startBinding": null,
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "arrow",
+ "width": 10,
+ "x": 0,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id82" => Delta {
+ "deleted": {
+ "height": 30,
+ "lastCommittedPoint": [
+ 30,
+ 30,
+ ],
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 5,
+ 5,
+ ],
+ [
+ 10,
+ 10,
+ ],
+ [
+ 15,
+ 15,
+ ],
+ [
+ 20,
+ 20,
+ ],
+ ],
+ "width": 30,
+ },
+ "inserted": {
+ "height": 10,
+ "lastCommittedPoint": [
+ 10,
+ 10,
+ ],
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 10,
+ 10,
+ ],
+ ],
+ "width": 10,
+ },
+ },
+ },
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedLinearElementId": "id82",
+ },
+ "inserted": {
+ "selectedLinearElementId": null,
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > multiplayer undo/redo > should override remotely added points on undo, but restore them on redo > [end of test] number of elements 1`] = `1`;
+
+exports[`history > multiplayer undo/redo > should override remotely added points on undo, but restore them on redo > [end of test] number of renders 1`] = `17`;
+
+exports[`history > multiplayer undo/redo > should redistribute deltas when element gets removed locally but is restored remotely > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": null,
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {},
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {},
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > multiplayer undo/redo > should redistribute deltas when element gets removed locally but is restored remotely > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "#ffec99",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "id": "id83",
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 7,
+ "width": 10,
+ "x": 10,
+ "y": 0,
+}
+`;
+
+exports[`history > multiplayer undo/redo > should redistribute deltas when element gets removed locally but is restored remotely > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id83": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id83" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "#ffec99",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 10,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {},
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id83": true,
+ },
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id83" => Delta {
+ "deleted": {
+ "isDeleted": false,
+ },
+ "inserted": {
+ "isDeleted": false,
+ },
+ },
+ },
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > multiplayer undo/redo > should redistribute deltas when element gets removed locally but is restored remotely > [end of test] number of elements 1`] = `1`;
+
+exports[`history > multiplayer undo/redo > should redistribute deltas when element gets removed locally but is restored remotely > [end of test] number of renders 1`] = `12`;
+
+exports[`history > multiplayer undo/redo > should update history entries after remote changes on the same properties > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "#a5d8ff",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": "elementBackground",
+ "openSidebar": null,
+ "originSnapOffset": null,
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {},
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {
+ "id77": true,
+ },
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > multiplayer undo/redo > should update history entries after remote changes on the same properties > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "id": "id77",
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 13,
+ "width": 10,
+ "x": 10,
+ "y": 0,
+}
+`;
+
+exports[`history > multiplayer undo/redo > should update history entries after remote changes on the same properties > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id77" => Delta {
+ "deleted": {
+ "backgroundColor": "#d0bfff",
+ },
+ "inserted": {
+ "backgroundColor": "#ffec99",
+ },
+ },
+ },
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id77" => Delta {
+ "deleted": {
+ "backgroundColor": "transparent",
+ },
+ "inserted": {
+ "backgroundColor": "#d0bfff",
+ },
+ },
+ },
+ },
+ },
+ ],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id77": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id77" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 10,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > multiplayer undo/redo > should update history entries after remote changes on the same properties > [end of test] number of elements 1`] = `1`;
+
+exports[`history > multiplayer undo/redo > should update history entries after remote changes on the same properties > [end of test] number of renders 1`] = `16`;
+
+exports[`history > singleplayer undo/redo > should clear the redo stack on elements change > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": null,
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {},
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {
+ "id14": true,
+ },
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > singleplayer undo/redo > should clear the redo stack on elements change > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "id": "id13",
+ "index": "a0",
+ "isDeleted": true,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 4,
+ "width": 10,
+ "x": 10,
+ "y": 0,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should clear the redo stack on elements change > [end of test] element 1 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "id": "id14",
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 3,
+ "width": 10,
+ "x": 20,
+ "y": 0,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should clear the redo stack on elements change > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id14": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id14" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 20,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > singleplayer undo/redo > should clear the redo stack on elements change > [end of test] number of elements 1`] = `2`;
+
+exports[`history > singleplayer undo/redo > should clear the redo stack on elements change > [end of test] number of renders 1`] = `10`;
+
+exports[`history > singleplayer undo/redo > should create new history entry on scene import via drag&drop > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": {
+ "x": 0,
+ "y": 0,
+ },
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {},
+ "resizingElement": null,
+ "scrollX": -50,
+ "scrollY": -50,
+ "selectedElementIds": {},
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": false,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#000",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > singleplayer undo/redo > should create new history entry on scene import via drag&drop > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": [],
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "A",
+ "index": "a0",
+ "isDeleted": true,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 5,
+ "width": 100,
+ "x": 0,
+ "y": 0,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should create new history entry on scene import via drag&drop > [end of test] element 1 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": [],
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "B",
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 5,
+ "width": 100,
+ "x": 0,
+ "y": 0,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should create new history entry on scene import via drag&drop > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "viewBackgroundColor": "#000",
+ },
+ "inserted": {
+ "viewBackgroundColor": "#FFF",
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {
+ "A" => Delta {
+ "deleted": {
+ "isDeleted": true,
+ },
+ "inserted": {
+ "isDeleted": false,
+ },
+ },
+ },
+ "removed": Map {
+ "B" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": [],
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": 0,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > singleplayer undo/redo > should create new history entry on scene import via drag&drop > [end of test] number of elements 1`] = `2`;
+
+exports[`history > singleplayer undo/redo > should create new history entry on scene import via drag&drop > [end of test] number of renders 1`] = `6`;
+
+exports[`history > singleplayer undo/redo > should end up with no history entry after initializing scene > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": null,
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {},
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {
+ "id19": true,
+ },
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": false,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": true,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > singleplayer undo/redo > should end up with no history entry after initializing scene > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": [],
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "A",
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 2,
+ "width": 100,
+ "x": 0,
+ "y": 0,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should end up with no history entry after initializing scene > [end of test] element 1 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "id": "id19",
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 5,
+ "width": 10,
+ "x": 0,
+ "y": 0,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should end up with no history entry after initializing scene > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id19": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id19" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 0,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > singleplayer undo/redo > should end up with no history entry after initializing scene > [end of test] number of elements 1`] = `2`;
+
+exports[`history > singleplayer undo/redo > should end up with no history entry after initializing scene > [end of test] number of renders 1`] = `8`;
+
+exports[`history > singleplayer undo/redo > should iterate through the history when selection changes do not produce visible change > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": null,
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {
+ "id15": true,
+ },
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {},
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > singleplayer undo/redo > should iterate through the history when selection changes do not produce visible change > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "id": "id15",
+ "index": "a0",
+ "isDeleted": true,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 4,
+ "width": 10,
+ "x": 10,
+ "y": 0,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should iterate through the history when selection changes do not produce visible change > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id15": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id15": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {},
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id15": true,
+ },
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {
+ "id15" => Delta {
+ "deleted": {
+ "isDeleted": true,
+ },
+ "inserted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 10,
+ "y": 0,
+ },
+ },
+ },
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ ],
+ "undoStack": [],
+}
+`;
+
+exports[`history > singleplayer undo/redo > should iterate through the history when selection changes do not produce visible change > [end of test] number of elements 1`] = `1`;
+
+exports[`history > singleplayer undo/redo > should iterate through the history when selection changes do not produce visible change > [end of test] number of renders 1`] = `14`;
+
+exports[`history > singleplayer undo/redo > should not clear the redo stack on standalone appstate change > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": null,
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {},
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {
+ "id8": true,
+ },
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > singleplayer undo/redo > should not clear the redo stack on standalone appstate change > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "id": "id7",
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 3,
+ "width": 10,
+ "x": 10,
+ "y": 0,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should not clear the redo stack on standalone appstate change > [end of test] element 1 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "id": "id8",
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 5,
+ "width": 10,
+ "x": 20,
+ "y": 0,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should not clear the redo stack on standalone appstate change > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id7": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id7" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 10,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {},
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id7": true,
+ },
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id7": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id8": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id7": true,
+ },
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id8" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 20,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > singleplayer undo/redo > should not clear the redo stack on standalone appstate change > [end of test] number of elements 1`] = `2`;
+
+exports[`history > singleplayer undo/redo > should not clear the redo stack on standalone appstate change > [end of test] number of renders 1`] = `14`;
+
+exports[`history > singleplayer undo/redo > should not collapse when applying corrupted history entry > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": {
+ "x": 0,
+ "y": 0,
+ },
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {},
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {},
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > singleplayer undo/redo > should not collapse when applying corrupted history entry > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id0",
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 2,
+ "width": 100,
+ "x": 0,
+ "y": 0,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should not collapse when applying corrupted history entry > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > singleplayer undo/redo > should not collapse when applying corrupted history entry > [end of test] number of elements 1`] = `1`;
+
+exports[`history > singleplayer undo/redo > should not collapse when applying corrupted history entry > [end of test] number of renders 1`] = `4`;
+
+exports[`history > singleplayer undo/redo > should not end up with history entry when there are no appstate changes > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": null,
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {},
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {
+ "id1": true,
+ "id2": true,
+ },
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {
+ "A": true,
+ },
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > singleplayer undo/redo > should not end up with history entry when there are no appstate changes > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [
+ "A",
+ ],
+ "height": 100,
+ "id": "id1",
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 2,
+ "width": 100,
+ "x": 0,
+ "y": 0,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should not end up with history entry when there are no appstate changes > [end of test] element 1 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [
+ "A",
+ ],
+ "height": 100,
+ "id": "id2",
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 2,
+ "width": 100,
+ "x": 0,
+ "y": 0,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should not end up with history entry when there are no appstate changes > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ "id2": true,
+ },
+ "selectedGroupIds": {
+ "A": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ "selectedGroupIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id1" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [
+ "A",
+ ],
+ "height": 100,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": 0,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ "id2" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [
+ "A",
+ ],
+ "height": 100,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": 0,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > singleplayer undo/redo > should not end up with history entry when there are no appstate changes > [end of test] number of elements 1`] = `2`;
+
+exports[`history > singleplayer undo/redo > should not end up with history entry when there are no appstate changes > [end of test] number of renders 1`] = `7`;
+
+exports[`history > singleplayer undo/redo > should not end up with history entry when there are no elements changes > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": {
+ "x": 0,
+ "y": 0,
+ },
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {},
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {},
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > singleplayer undo/redo > should not end up with history entry when there are no elements changes > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id5",
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 2,
+ "width": 100,
+ "x": 0,
+ "y": 0,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should not end up with history entry when there are no elements changes > [end of test] element 1 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id6",
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 2,
+ "width": 100,
+ "x": 0,
+ "y": 0,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should not end up with history entry when there are no elements changes > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id5" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": 0,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ "id6" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": 0,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > singleplayer undo/redo > should not end up with history entry when there are no elements changes > [end of test] number of elements 1`] = `2`;
+
+exports[`history > singleplayer undo/redo > should not end up with history entry when there are no elements changes > [end of test] number of renders 1`] = `5`;
+
+exports[`history > singleplayer undo/redo > should not override appstate changes when redo stack is not cleared > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "#a5d8ff",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": "elementBackground",
+ "openSidebar": null,
+ "originSnapOffset": null,
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {
+ "id11": true,
+ },
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {
+ "id11": true,
+ },
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > singleplayer undo/redo > should not override appstate changes when redo stack is not cleared > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "id": "id11",
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 11,
+ "width": 10,
+ "x": 10,
+ "y": 0,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should not override appstate changes when redo stack is not cleared > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id11" => Delta {
+ "deleted": {
+ "backgroundColor": "#ffc9c9",
+ },
+ "inserted": {
+ "backgroundColor": "#a5d8ff",
+ },
+ },
+ },
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id11" => Delta {
+ "deleted": {
+ "backgroundColor": "transparent",
+ },
+ "inserted": {
+ "backgroundColor": "#ffc9c9",
+ },
+ },
+ },
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id11": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ ],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id11": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id11" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 10,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > singleplayer undo/redo > should not override appstate changes when redo stack is not cleared > [end of test] number of elements 1`] = `1`;
+
+exports[`history > singleplayer undo/redo > should not override appstate changes when redo stack is not cleared > [end of test] number of renders 1`] = `16`;
+
+exports[`history > singleplayer undo/redo > should support appstate name or viewBackgroundColor change > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": {
+ "x": 0,
+ "y": 0,
+ },
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {},
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {},
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#000",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support appstate name or viewBackgroundColor change > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "name": "New name",
+ },
+ "inserted": {
+ "name": "Old name",
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "viewBackgroundColor": "#000",
+ },
+ "inserted": {
+ "viewBackgroundColor": "#FFF",
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support appstate name or viewBackgroundColor change > [end of test] number of elements 1`] = `0`;
+
+exports[`history > singleplayer undo/redo > should support appstate name or viewBackgroundColor change > [end of test] number of renders 1`] = `8`;
+
+exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind arrow from non deleted bindable elements on deletion and rebind on undo > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": null,
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {
+ "id47": true,
+ },
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {
+ "id52": true,
+ },
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind arrow from non deleted bindable elements on deletion and rebind on undo > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": [
+ {
+ "id": "id48",
+ "type": "text",
+ },
+ {
+ "id": "id52",
+ "type": "arrow",
+ },
+ ],
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id47",
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 8,
+ "width": 100,
+ "x": -100,
+ "y": -50,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind arrow from non deleted bindable elements on deletion and rebind on undo > [end of test] element 1 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "containerId": "id47",
+ "customData": undefined,
+ "fillStyle": "solid",
+ "fontFamily": 1,
+ "fontSize": 20,
+ "frameId": null,
+ "groupIds": [],
+ "height": 25,
+ "id": "id48",
+ "index": "a1",
+ "isDeleted": false,
+ "lineHeight": 1.25,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "originalText": "ola",
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "text": "ola",
+ "textAlign": "center",
+ "type": "text",
+ "updated": 1,
+ "version": 6,
+ "verticalAlign": "middle",
+ "width": 30,
+ "x": -65,
+ "y": -12.5,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind arrow from non deleted bindable elements on deletion and rebind on undo > [end of test] element 2 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": [
+ {
+ "id": "id52",
+ "type": "arrow",
+ },
+ ],
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id49",
+ "index": "a2",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 7,
+ "width": 100,
+ "x": 100,
+ "y": -50,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind arrow from non deleted bindable elements on deletion and rebind on undo > [end of test] element 3 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "endArrowhead": "arrow",
+ "endBinding": {
+ "elementId": "id49",
+ "focus": 0,
+ "gap": 1,
+ },
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 0,
+ "id": "id52",
+ "index": "a3",
+ "isDeleted": false,
+ "lastCommittedPoint": null,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 98,
+ 0,
+ ],
+ ],
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "startArrowhead": null,
+ "startBinding": {
+ "elementId": "id47",
+ "focus": 0,
+ "gap": 1,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "arrow",
+ "updated": 1,
+ "version": 12,
+ "width": 98,
+ "x": 1,
+ "y": 0,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind arrow from non deleted bindable elements on deletion and rebind on undo > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id52": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id52" => Delta {
+ "deleted": {
+ "isDeleted": false,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 100,
+ 0,
+ ],
+ ],
+ },
+ "inserted": {
+ "isDeleted": true,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 100,
+ 0,
+ ],
+ ],
+ },
+ },
+ },
+ "updated": Map {
+ "id47" => Delta {
+ "deleted": {
+ "boundElements": [
+ {
+ "id": "id52",
+ "type": "arrow",
+ },
+ ],
+ },
+ "inserted": {
+ "boundElements": [],
+ },
+ },
+ "id49" => Delta {
+ "deleted": {
+ "boundElements": [
+ {
+ "id": "id52",
+ "type": "arrow",
+ },
+ ],
+ },
+ "inserted": {
+ "boundElements": [],
+ },
+ },
+ },
+ },
+ },
+ ],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id47" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": -100,
+ "y": -50,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ "id48" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "containerId": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "fontFamily": 1,
+ "fontSize": 20,
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a1",
+ "isDeleted": false,
+ "lineHeight": 1.25,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "originalText": "ola",
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "text": "ola",
+ "textAlign": "left",
+ "type": "text",
+ "verticalAlign": "top",
+ "width": 100,
+ "x": -200,
+ "y": -200,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ "id49" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a2",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": 100,
+ "y": -50,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id47": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id48": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {},
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id48": true,
+ },
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id47" => Delta {
+ "deleted": {
+ "boundElements": [
+ {
+ "id": "id48",
+ "type": "text",
+ },
+ ],
+ },
+ "inserted": {
+ "boundElements": [],
+ },
+ },
+ "id48" => Delta {
+ "deleted": {
+ "containerId": "id47",
+ "height": 25,
+ "textAlign": "center",
+ "verticalAlign": "middle",
+ "width": 30,
+ "x": -65,
+ "y": -12.5,
+ },
+ "inserted": {
+ "containerId": null,
+ "height": 100,
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "width": 100,
+ "x": -200,
+ "y": -200,
+ },
+ },
+ },
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id52": true,
+ },
+ "selectedLinearElementId": "id52",
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id47": true,
+ },
+ "selectedLinearElementId": null,
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id52" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "endArrowhead": "arrow",
+ "endBinding": {
+ "elementId": "id49",
+ "focus": 0,
+ "gap": 1,
+ },
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 0,
+ "index": "a3",
+ "isDeleted": false,
+ "lastCommittedPoint": null,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 100,
+ 0,
+ ],
+ ],
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "startArrowhead": null,
+ "startBinding": {
+ "elementId": "id47",
+ "focus": 0,
+ "gap": 1,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "arrow",
+ "width": 100,
+ "x": 0,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {
+ "id47" => Delta {
+ "deleted": {
+ "boundElements": [
+ {
+ "id": "id52",
+ "type": "arrow",
+ },
+ ],
+ },
+ "inserted": {
+ "boundElements": [],
+ },
+ },
+ "id49" => Delta {
+ "deleted": {
+ "boundElements": [
+ {
+ "id": "id52",
+ "type": "arrow",
+ },
+ ],
+ },
+ "inserted": {
+ "boundElements": [],
+ },
+ },
+ },
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind arrow from non deleted bindable elements on deletion and rebind on undo > [end of test] number of elements 1`] = `4`;
+
+exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind arrow from non deleted bindable elements on deletion and rebind on undo > [end of test] number of renders 1`] = `13`;
+
+exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind arrow from non deleted bindable elements on undo and rebind on redo > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": null,
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {
+ "id41": true,
+ },
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {
+ "id46": true,
+ },
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind arrow from non deleted bindable elements on undo and rebind on redo > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": [
+ {
+ "id": "id42",
+ "type": "text",
+ },
+ {
+ "id": "id46",
+ "type": "arrow",
+ },
+ ],
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id41",
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 8,
+ "width": 100,
+ "x": -100,
+ "y": -50,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind arrow from non deleted bindable elements on undo and rebind on redo > [end of test] element 1 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "containerId": "id41",
+ "customData": undefined,
+ "fillStyle": "solid",
+ "fontFamily": 1,
+ "fontSize": 20,
+ "frameId": null,
+ "groupIds": [],
+ "height": 25,
+ "id": "id42",
+ "index": "a1",
+ "isDeleted": false,
+ "lineHeight": 1.25,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "originalText": "ola",
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "text": "ola",
+ "textAlign": "center",
+ "type": "text",
+ "updated": 1,
+ "version": 8,
+ "verticalAlign": "middle",
+ "width": 30,
+ "x": -65,
+ "y": -12.5,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind arrow from non deleted bindable elements on undo and rebind on redo > [end of test] element 2 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": [
+ {
+ "id": "id46",
+ "type": "arrow",
+ },
+ ],
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id43",
+ "index": "a2",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 7,
+ "width": 100,
+ "x": 100,
+ "y": -50,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind arrow from non deleted bindable elements on undo and rebind on redo > [end of test] element 3 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "endArrowhead": "arrow",
+ "endBinding": {
+ "elementId": "id43",
+ "focus": 0,
+ "gap": 1,
+ },
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 0,
+ "id": "id46",
+ "index": "a3",
+ "isDeleted": false,
+ "lastCommittedPoint": null,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 98,
+ 0,
+ ],
+ ],
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "startArrowhead": null,
+ "startBinding": {
+ "elementId": "id41",
+ "focus": 0,
+ "gap": 1,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "arrow",
+ "updated": 1,
+ "version": 12,
+ "width": 98,
+ "x": 1,
+ "y": 0,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind arrow from non deleted bindable elements on undo and rebind on redo > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id41" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": -100,
+ "y": -50,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ "id42" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "containerId": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "fontFamily": 1,
+ "fontSize": 20,
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a1",
+ "isDeleted": false,
+ "lineHeight": 1.25,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "originalText": "ola",
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "text": "ola",
+ "textAlign": "left",
+ "type": "text",
+ "verticalAlign": "top",
+ "width": 100,
+ "x": -200,
+ "y": -200,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ "id43" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a2",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": 100,
+ "y": -50,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id41": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id42": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {},
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id42": true,
+ },
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id41" => Delta {
+ "deleted": {
+ "boundElements": [
+ {
+ "id": "id42",
+ "type": "text",
+ },
+ ],
+ },
+ "inserted": {
+ "boundElements": [],
+ },
+ },
+ "id42" => Delta {
+ "deleted": {
+ "containerId": "id41",
+ "height": 25,
+ "textAlign": "center",
+ "verticalAlign": "middle",
+ "width": 30,
+ "x": -65,
+ "y": -12.5,
+ },
+ "inserted": {
+ "containerId": null,
+ "height": 100,
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "width": 100,
+ "x": -200,
+ "y": -200,
+ },
+ },
+ },
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id46": true,
+ },
+ "selectedLinearElementId": "id46",
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id41": true,
+ },
+ "selectedLinearElementId": null,
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id46" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "endArrowhead": "arrow",
+ "endBinding": {
+ "elementId": "id43",
+ "focus": 0,
+ "gap": 1,
+ },
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 0,
+ "index": "a3",
+ "isDeleted": false,
+ "lastCommittedPoint": null,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 100,
+ 0,
+ ],
+ ],
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "startArrowhead": null,
+ "startBinding": {
+ "elementId": "id41",
+ "focus": 0,
+ "gap": 1,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "arrow",
+ "width": 100,
+ "x": 0,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {
+ "id41" => Delta {
+ "deleted": {
+ "boundElements": [
+ {
+ "id": "id46",
+ "type": "arrow",
+ },
+ ],
+ },
+ "inserted": {
+ "boundElements": [],
+ },
+ },
+ "id43" => Delta {
+ "deleted": {
+ "boundElements": [
+ {
+ "id": "id46",
+ "type": "arrow",
+ },
+ ],
+ },
+ "inserted": {
+ "boundElements": [],
+ },
+ },
+ },
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind arrow from non deleted bindable elements on undo and rebind on redo > [end of test] number of elements 1`] = `4`;
+
+exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind arrow from non deleted bindable elements on undo and rebind on redo > [end of test] number of renders 1`] = `13`;
+
+exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind everything from non deleted elements when iterating through the whole undo stack and vice versa rebind everything on redo > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": null,
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {
+ "id53": true,
+ },
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {
+ "id58": true,
+ },
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind everything from non deleted elements when iterating through the whole undo stack and vice versa rebind everything on redo > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": [
+ {
+ "id": "id54",
+ "type": "text",
+ },
+ {
+ "id": "id58",
+ "type": "arrow",
+ },
+ ],
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id53",
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 12,
+ "width": 100,
+ "x": -100,
+ "y": -50,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind everything from non deleted elements when iterating through the whole undo stack and vice versa rebind everything on redo > [end of test] element 1 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "containerId": "id53",
+ "customData": undefined,
+ "fillStyle": "solid",
+ "fontFamily": 1,
+ "fontSize": 20,
+ "frameId": null,
+ "groupIds": [],
+ "height": 25,
+ "id": "id54",
+ "index": "a1",
+ "isDeleted": false,
+ "lineHeight": 1.25,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "originalText": "ola",
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "text": "ola",
+ "textAlign": "center",
+ "type": "text",
+ "updated": 1,
+ "version": 12,
+ "verticalAlign": "middle",
+ "width": 30,
+ "x": -65,
+ "y": -12.5,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind everything from non deleted elements when iterating through the whole undo stack and vice versa rebind everything on redo > [end of test] element 2 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": [
+ {
+ "id": "id58",
+ "type": "arrow",
+ },
+ ],
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id55",
+ "index": "a2",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 9,
+ "width": 100,
+ "x": 100,
+ "y": -50,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind everything from non deleted elements when iterating through the whole undo stack and vice versa rebind everything on redo > [end of test] element 3 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "endArrowhead": "arrow",
+ "endBinding": {
+ "elementId": "id55",
+ "focus": 0,
+ "gap": 1,
+ },
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 0,
+ "id": "id58",
+ "index": "a3",
+ "isDeleted": false,
+ "lastCommittedPoint": null,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 98,
+ 0,
+ ],
+ ],
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "startArrowhead": null,
+ "startBinding": {
+ "elementId": "id53",
+ "focus": 0,
+ "gap": 1,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "arrow",
+ "updated": 1,
+ "version": 12,
+ "width": 98,
+ "x": 1,
+ "y": 0,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind everything from non deleted elements when iterating through the whole undo stack and vice versa rebind everything on redo > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id53" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": -100,
+ "y": -50,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ "id54" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "containerId": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "fontFamily": 1,
+ "fontSize": 20,
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a1",
+ "isDeleted": false,
+ "lineHeight": 1.25,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "originalText": "ola",
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "text": "ola",
+ "textAlign": "left",
+ "type": "text",
+ "verticalAlign": "top",
+ "width": 100,
+ "x": -200,
+ "y": -200,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ "id55" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a2",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": 100,
+ "y": -50,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id53": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id54": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {},
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id54": true,
+ },
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id53" => Delta {
+ "deleted": {
+ "boundElements": [
+ {
+ "id": "id54",
+ "type": "text",
+ },
+ ],
+ },
+ "inserted": {
+ "boundElements": [],
+ },
+ },
+ "id54" => Delta {
+ "deleted": {
+ "containerId": "id53",
+ "height": 25,
+ "textAlign": "center",
+ "verticalAlign": "middle",
+ "width": 30,
+ "x": -65,
+ "y": -12.5,
+ },
+ "inserted": {
+ "containerId": null,
+ "height": 100,
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "width": 100,
+ "x": -200,
+ "y": -200,
+ },
+ },
+ },
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id58": true,
+ },
+ "selectedLinearElementId": "id58",
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id53": true,
+ },
+ "selectedLinearElementId": null,
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id58" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "endArrowhead": "arrow",
+ "endBinding": {
+ "elementId": "id55",
+ "focus": 0,
+ "gap": 1,
+ },
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 0,
+ "index": "a3",
+ "isDeleted": false,
+ "lastCommittedPoint": null,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 100,
+ 0,
+ ],
+ ],
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "startArrowhead": null,
+ "startBinding": {
+ "elementId": "id53",
+ "focus": 0,
+ "gap": 1,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "arrow",
+ "width": 100,
+ "x": 0,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {
+ "id53" => Delta {
+ "deleted": {
+ "boundElements": [
+ {
+ "id": "id58",
+ "type": "arrow",
+ },
+ ],
+ },
+ "inserted": {
+ "boundElements": [],
+ },
+ },
+ "id55" => Delta {
+ "deleted": {
+ "boundElements": [
+ {
+ "id": "id58",
+ "type": "arrow",
+ },
+ ],
+ },
+ "inserted": {
+ "boundElements": [],
+ },
+ },
+ },
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind everything from non deleted elements when iterating through the whole undo stack and vice versa rebind everything on redo > [end of test] number of elements 1`] = `4`;
+
+exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind everything from non deleted elements when iterating through the whole undo stack and vice versa rebind everything on redo > [end of test] number of renders 1`] = `21`;
+
+exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind rectangle from arrow on deletion and rebind on undo > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": null,
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {},
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {
+ "id59": true,
+ },
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind rectangle from arrow on deletion and rebind on undo > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": [
+ {
+ "id": "id64",
+ "type": "arrow",
+ },
+ {
+ "id": "id60",
+ "type": "text",
+ },
+ ],
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id59",
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 8,
+ "width": 100,
+ "x": -100,
+ "y": -50,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind rectangle from arrow on deletion and rebind on undo > [end of test] element 1 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "containerId": "id59",
+ "customData": undefined,
+ "fillStyle": "solid",
+ "fontFamily": 1,
+ "fontSize": 20,
+ "frameId": null,
+ "groupIds": [],
+ "height": 25,
+ "id": "id60",
+ "index": "a1",
+ "isDeleted": false,
+ "lineHeight": 1.25,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "originalText": "ola",
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "text": "ola",
+ "textAlign": "center",
+ "type": "text",
+ "updated": 1,
+ "version": 8,
+ "verticalAlign": "middle",
+ "width": 30,
+ "x": -65,
+ "y": -12.5,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind rectangle from arrow on deletion and rebind on undo > [end of test] element 2 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": [
+ {
+ "id": "id64",
+ "type": "arrow",
+ },
+ ],
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id61",
+ "index": "a2",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 5,
+ "width": 100,
+ "x": 100,
+ "y": -50,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind rectangle from arrow on deletion and rebind on undo > [end of test] element 3 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "endArrowhead": "arrow",
+ "endBinding": {
+ "elementId": "id61",
+ "focus": 0,
+ "gap": 1,
+ },
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 0,
+ "id": "id64",
+ "index": "a3",
+ "isDeleted": false,
+ "lastCommittedPoint": null,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 98,
+ 0,
+ ],
+ ],
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "startArrowhead": null,
+ "startBinding": {
+ "elementId": "id59",
+ "focus": 0,
+ "gap": 1,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "arrow",
+ "updated": 1,
+ "version": 12,
+ "width": 98,
+ "x": 1,
+ "y": 0,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind rectangle from arrow on deletion and rebind on undo > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id59": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id59" => Delta {
+ "deleted": {
+ "isDeleted": false,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ "id60" => Delta {
+ "deleted": {
+ "isDeleted": false,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {
+ "id64" => Delta {
+ "deleted": {
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 100,
+ 0,
+ ],
+ ],
+ "startBinding": {
+ "elementId": "id59",
+ "focus": 0,
+ "gap": 1,
+ },
+ },
+ "inserted": {
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 100,
+ 0,
+ ],
+ ],
+ "startBinding": null,
+ },
+ },
+ },
+ },
+ },
+ ],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id59" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": -100,
+ "y": -50,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ "id60" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "containerId": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "fontFamily": 1,
+ "fontSize": 20,
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a1",
+ "isDeleted": false,
+ "lineHeight": 1.25,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "originalText": "ola",
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "text": "ola",
+ "textAlign": "left",
+ "type": "text",
+ "verticalAlign": "top",
+ "width": 100,
+ "x": -200,
+ "y": -200,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ "id61" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a2",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": 100,
+ "y": -50,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id59": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id60": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {},
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id60": true,
+ },
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id59" => Delta {
+ "deleted": {
+ "boundElements": [
+ {
+ "id": "id60",
+ "type": "text",
+ },
+ ],
+ },
+ "inserted": {
+ "boundElements": [],
+ },
+ },
+ "id60" => Delta {
+ "deleted": {
+ "containerId": "id59",
+ "height": 25,
+ "textAlign": "center",
+ "verticalAlign": "middle",
+ "width": 30,
+ "x": -65,
+ "y": -12.5,
+ },
+ "inserted": {
+ "containerId": null,
+ "height": 100,
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "width": 100,
+ "x": -200,
+ "y": -200,
+ },
+ },
+ },
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id64": true,
+ },
+ "selectedLinearElementId": "id64",
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id59": true,
+ },
+ "selectedLinearElementId": null,
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id64" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "endArrowhead": "arrow",
+ "endBinding": {
+ "elementId": "id61",
+ "focus": 0,
+ "gap": 1,
+ },
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 0,
+ "index": "a3",
+ "isDeleted": false,
+ "lastCommittedPoint": null,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 100,
+ 0,
+ ],
+ ],
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "startArrowhead": null,
+ "startBinding": {
+ "elementId": "id59",
+ "focus": 0,
+ "gap": 1,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "arrow",
+ "width": 100,
+ "x": 0,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {
+ "id59" => Delta {
+ "deleted": {
+ "boundElements": [
+ {
+ "id": "id64",
+ "type": "arrow",
+ },
+ ],
+ },
+ "inserted": {
+ "boundElements": [],
+ },
+ },
+ "id61" => Delta {
+ "deleted": {
+ "boundElements": [
+ {
+ "id": "id64",
+ "type": "arrow",
+ },
+ ],
+ },
+ "inserted": {
+ "boundElements": [],
+ },
+ },
+ },
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id59": true,
+ },
+ "selectedLinearElementId": null,
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id64": true,
+ },
+ "selectedLinearElementId": "id64",
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind rectangle from arrow on deletion and rebind on undo > [end of test] number of elements 1`] = `4`;
+
+exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind rectangle from arrow on deletion and rebind on undo > [end of test] number of renders 1`] = `15`;
+
+exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind rectangles from arrow on deletion and rebind on undo > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": null,
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {
+ "id66": true,
+ },
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {
+ "id66": true,
+ "id68": true,
+ },
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind rectangles from arrow on deletion and rebind on undo > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": [
+ {
+ "id": "id71",
+ "type": "arrow",
+ },
+ {
+ "id": "id67",
+ "type": "text",
+ },
+ ],
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id66",
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 8,
+ "width": 100,
+ "x": -100,
+ "y": -50,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind rectangles from arrow on deletion and rebind on undo > [end of test] element 1 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "containerId": "id66",
+ "customData": undefined,
+ "fillStyle": "solid",
+ "fontFamily": 1,
+ "fontSize": 20,
+ "frameId": null,
+ "groupIds": [],
+ "height": 25,
+ "id": "id67",
+ "index": "a1",
+ "isDeleted": false,
+ "lineHeight": 1.25,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "originalText": "ola",
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "text": "ola",
+ "textAlign": "center",
+ "type": "text",
+ "updated": 1,
+ "version": 8,
+ "verticalAlign": "middle",
+ "width": 30,
+ "x": -65,
+ "y": -12.5,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind rectangles from arrow on deletion and rebind on undo > [end of test] element 2 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": [
+ {
+ "id": "id71",
+ "type": "arrow",
+ },
+ ],
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "id": "id68",
+ "index": "a2",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 5,
+ "width": 100,
+ "x": 100,
+ "y": -50,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind rectangles from arrow on deletion and rebind on undo > [end of test] element 3 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "endArrowhead": "arrow",
+ "endBinding": {
+ "elementId": "id68",
+ "focus": 0,
+ "gap": 1,
+ },
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 0,
+ "id": "id71",
+ "index": "a3",
+ "isDeleted": false,
+ "lastCommittedPoint": null,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 98,
+ 0,
+ ],
+ ],
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "startArrowhead": null,
+ "startBinding": {
+ "elementId": "id66",
+ "focus": 0,
+ "gap": 1,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "arrow",
+ "updated": 1,
+ "version": 13,
+ "width": 98,
+ "x": 1,
+ "y": 0,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind rectangles from arrow on deletion and rebind on undo > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id66": true,
+ "id68": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id66" => Delta {
+ "deleted": {
+ "isDeleted": false,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ "id67" => Delta {
+ "deleted": {
+ "isDeleted": false,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ "id68" => Delta {
+ "deleted": {
+ "isDeleted": false,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {
+ "id71" => Delta {
+ "deleted": {
+ "endBinding": {
+ "elementId": "id68",
+ "focus": 0,
+ "gap": 1,
+ },
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 100,
+ 0,
+ ],
+ ],
+ "startBinding": {
+ "elementId": "id66",
+ "focus": 0,
+ "gap": 1,
+ },
+ },
+ "inserted": {
+ "endBinding": null,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 100,
+ 0,
+ ],
+ ],
+ "startBinding": null,
+ },
+ },
+ },
+ },
+ },
+ ],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id66" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": -100,
+ "y": -50,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ "id67" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "containerId": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "fontFamily": 1,
+ "fontSize": 20,
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a1",
+ "isDeleted": false,
+ "lineHeight": 1.25,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "originalText": "ola",
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "text": "ola",
+ "textAlign": "left",
+ "type": "text",
+ "verticalAlign": "top",
+ "width": 100,
+ "x": -200,
+ "y": -200,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ "id68" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a2",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": 100,
+ "y": -50,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id66": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id67": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {},
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id67": true,
+ },
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id66" => Delta {
+ "deleted": {
+ "boundElements": [
+ {
+ "id": "id67",
+ "type": "text",
+ },
+ ],
+ },
+ "inserted": {
+ "boundElements": [],
+ },
+ },
+ "id67" => Delta {
+ "deleted": {
+ "containerId": "id66",
+ "height": 25,
+ "textAlign": "center",
+ "verticalAlign": "middle",
+ "width": 30,
+ "x": -65,
+ "y": -12.5,
+ },
+ "inserted": {
+ "containerId": null,
+ "height": 100,
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "width": 100,
+ "x": -200,
+ "y": -200,
+ },
+ },
+ },
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id71": true,
+ },
+ "selectedLinearElementId": "id71",
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id66": true,
+ },
+ "selectedLinearElementId": null,
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id71" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "endArrowhead": "arrow",
+ "endBinding": {
+ "elementId": "id68",
+ "focus": 0,
+ "gap": 1,
+ },
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 0,
+ "index": "a3",
+ "isDeleted": false,
+ "lastCommittedPoint": null,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 100,
+ 0,
+ ],
+ ],
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "startArrowhead": null,
+ "startBinding": {
+ "elementId": "id66",
+ "focus": 0,
+ "gap": 1,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "arrow",
+ "width": 100,
+ "x": 0,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {
+ "id66" => Delta {
+ "deleted": {
+ "boundElements": [
+ {
+ "id": "id71",
+ "type": "arrow",
+ },
+ ],
+ },
+ "inserted": {
+ "boundElements": [],
+ },
+ },
+ "id68" => Delta {
+ "deleted": {
+ "boundElements": [
+ {
+ "id": "id71",
+ "type": "arrow",
+ },
+ ],
+ },
+ "inserted": {
+ "boundElements": [],
+ },
+ },
+ },
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id66": true,
+ },
+ "selectedLinearElementId": null,
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id71": true,
+ },
+ "selectedLinearElementId": "id71",
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id68": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind rectangles from arrow on deletion and rebind on undo > [end of test] number of elements 1`] = `4`;
+
+exports[`history > singleplayer undo/redo > should support bidirectional bindings > should unbind rectangles from arrow on deletion and rebind on undo > [end of test] number of renders 1`] = `16`;
+
+exports[`history > singleplayer undo/redo > should support changes in elements' order > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": null,
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {
+ "id36": true,
+ },
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {
+ "id36": true,
+ "id38": true,
+ },
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support changes in elements' order > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "id": "id37",
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 3,
+ "width": 10,
+ "x": 20,
+ "y": 20,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support changes in elements' order > [end of test] element 1 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "id": "id36",
+ "index": "a2",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 6,
+ "width": 10,
+ "x": 10,
+ "y": 0,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support changes in elements' order > [end of test] element 2 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "id": "id38",
+ "index": "a3",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 9,
+ "width": 10,
+ "x": 40,
+ "y": 40,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support changes in elements' order > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id36": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id36" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 10,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id37": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id36": true,
+ },
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id37" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 20,
+ "y": 20,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id38": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id37": true,
+ },
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id38" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a2",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 40,
+ "y": 40,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id38" => Delta {
+ "deleted": {
+ "index": "a0V",
+ },
+ "inserted": {
+ "index": "a2",
+ },
+ },
+ },
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id36": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id38": true,
+ },
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id38": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id36" => Delta {
+ "deleted": {
+ "index": "a2",
+ },
+ "inserted": {
+ "index": "a0",
+ },
+ },
+ "id38" => Delta {
+ "deleted": {
+ "index": "a3",
+ },
+ "inserted": {
+ "index": "a0V",
+ },
+ },
+ },
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support changes in elements' order > [end of test] number of elements 1`] = `3`;
+
+exports[`history > singleplayer undo/redo > should support changes in elements' order > [end of test] number of renders 1`] = `23`;
+
+exports[`history > singleplayer undo/redo > should support duplication of groups, appstate group selection and editing group > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": null,
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {
+ "id33": true,
+ },
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {
+ "id32_copy_copy": true,
+ "id33_copy_copy": true,
+ },
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {
+ "A_copy": true,
+ },
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support duplication of groups, appstate group selection and editing group > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [
+ "A",
+ ],
+ "height": 100,
+ "id": "id32",
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 2,
+ "width": 100,
+ "x": 0,
+ "y": 0,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support duplication of groups, appstate group selection and editing group > [end of test] element 1 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [
+ "A",
+ ],
+ "height": 100,
+ "id": "id33",
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 2,
+ "width": 100,
+ "x": 100,
+ "y": 100,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support duplication of groups, appstate group selection and editing group > [end of test] element 2 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [
+ "A_copy",
+ ],
+ "height": 100,
+ "id": "id32_copy_copy",
+ "index": "a1G",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 3,
+ "width": 100,
+ "x": 10,
+ "y": 10,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support duplication of groups, appstate group selection and editing group > [end of test] element 3 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [
+ "A_copy",
+ ],
+ "height": 100,
+ "id": "id33_copy_copy",
+ "index": "a1V",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 3,
+ "width": 100,
+ "x": 110,
+ "y": 110,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support duplication of groups, appstate group selection and editing group > [end of test] element 4 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [
+ "A_copy",
+ ],
+ "height": 100,
+ "id": "id32_copy",
+ "index": "a2",
+ "isDeleted": true,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 6,
+ "width": 100,
+ "x": 10,
+ "y": 10,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support duplication of groups, appstate group selection and editing group > [end of test] element 5 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [
+ "A_copy",
+ ],
+ "height": 100,
+ "id": "id33_copy",
+ "index": "a3",
+ "isDeleted": true,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 6,
+ "width": 100,
+ "x": 110,
+ "y": 110,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support duplication of groups, appstate group selection and editing group > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id32": true,
+ "id33": true,
+ },
+ "selectedGroupIds": {
+ "A": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ "selectedGroupIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id32" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [
+ "A",
+ ],
+ "height": 100,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": 0,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ "id33" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [
+ "A",
+ ],
+ "height": 100,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": 100,
+ "y": 100,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id32_copy_copy": true,
+ "id33_copy_copy": true,
+ },
+ "selectedGroupIds": {
+ "A_copy": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id32": true,
+ "id33": true,
+ },
+ "selectedGroupIds": {
+ "A": true,
+ },
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id32_copy_copy" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [
+ "A_copy",
+ ],
+ "height": 100,
+ "index": "a1G",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": 10,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ "id33_copy_copy" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [
+ "A_copy",
+ ],
+ "height": 100,
+ "index": "a1V",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": 110,
+ "y": 110,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support duplication of groups, appstate group selection and editing group > [end of test] number of elements 1`] = `6`;
+
+exports[`history > singleplayer undo/redo > should support duplication of groups, appstate group selection and editing group > [end of test] number of renders 1`] = `18`;
+
+exports[`history > singleplayer undo/redo > should support element creation, deletion and appstate element selection change > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": null,
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {
+ "id23": true,
+ },
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {},
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support element creation, deletion and appstate element selection change > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "id": "id22",
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 5,
+ "width": 10,
+ "x": 10,
+ "y": 0,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support element creation, deletion and appstate element selection change > [end of test] element 1 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "id": "id23",
+ "index": "a1",
+ "isDeleted": true,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 8,
+ "width": 10,
+ "x": 20,
+ "y": 20,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support element creation, deletion and appstate element selection change > [end of test] element 2 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "id": "id24",
+ "index": "a2",
+ "isDeleted": true,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "updated": 1,
+ "version": 8,
+ "width": 10,
+ "x": 40,
+ "y": 40,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support element creation, deletion and appstate element selection change > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id22": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id22" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 10,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id23": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id22": true,
+ },
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id23" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 20,
+ "y": 20,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id24": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id23": true,
+ },
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id24" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a2",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 40,
+ "y": 40,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id23": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id24": true,
+ },
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id24": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {},
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id23": true,
+ "id24": true,
+ },
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {
+ "id23" => Delta {
+ "deleted": {
+ "isDeleted": true,
+ },
+ "inserted": {
+ "isDeleted": false,
+ },
+ },
+ "id24" => Delta {
+ "deleted": {
+ "isDeleted": true,
+ },
+ "inserted": {
+ "isDeleted": false,
+ },
+ },
+ },
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support element creation, deletion and appstate element selection change > [end of test] number of elements 1`] = `3`;
+
+exports[`history > singleplayer undo/redo > should support element creation, deletion and appstate element selection change > [end of test] number of renders 1`] = `30`;
+
+exports[`history > singleplayer undo/redo > should support linear element creation and points manipulation through the editor > [end of test] appState 1`] = `
+{
+ "activeEmbeddable": null,
+ "activeTool": {
+ "customType": null,
+ "lastActiveTool": null,
+ "locked": false,
+ "type": "selection",
+ },
+ "collaborators": Map {},
+ "contextMenu": null,
+ "currentChartType": "bar",
+ "currentItemBackgroundColor": "transparent",
+ "currentItemEndArrowhead": "arrow",
+ "currentItemFillStyle": "solid",
+ "currentItemFontFamily": 1,
+ "currentItemFontSize": 20,
+ "currentItemOpacity": 100,
+ "currentItemRoughness": 1,
+ "currentItemRoundness": "round",
+ "currentItemStartArrowhead": null,
+ "currentItemStrokeColor": "#1e1e1e",
+ "currentItemStrokeStyle": "solid",
+ "currentItemStrokeWidth": 2,
+ "currentItemTextAlign": "left",
+ "cursorButton": "up",
+ "defaultSidebarDockedPreference": false,
+ "draggingElement": null,
+ "editingElement": null,
+ "editingFrame": null,
+ "editingGroupId": null,
+ "editingLinearElement": null,
+ "elementsToHighlight": null,
+ "errorMessage": null,
+ "exportBackground": true,
+ "exportEmbedScene": false,
+ "exportScale": 1,
+ "exportWithDarkMode": false,
+ "fileHandle": null,
+ "followedBy": Set {},
+ "frameRendering": {
+ "clip": true,
+ "enabled": true,
+ "name": true,
+ "outline": true,
+ },
+ "frameToHighlight": null,
+ "gridSize": null,
+ "height": 0,
+ "isBindingEnabled": true,
+ "isLoading": false,
+ "isResizing": false,
+ "isRotating": false,
+ "lastPointerDownWith": "mouse",
+ "multiElement": null,
+ "objectsSnapModeEnabled": false,
+ "offsetLeft": 0,
+ "offsetTop": 0,
+ "openDialog": null,
+ "openMenu": null,
+ "openPopup": null,
+ "openSidebar": null,
+ "originSnapOffset": null,
+ "pasteDialog": {
+ "data": null,
+ "shown": false,
+ },
+ "penDetected": false,
+ "penMode": false,
+ "pendingImageElementId": null,
+ "previousSelectedElementIds": {
+ "id27": true,
+ },
+ "resizingElement": null,
+ "scrollX": 0,
+ "scrollY": 0,
+ "selectedElementIds": {
+ "id27": true,
+ },
+ "selectedElementsAreBeingDragged": false,
+ "selectedGroupIds": {},
+ "selectionElement": null,
+ "shouldCacheIgnoreZoom": false,
+ "showHyperlinkPopup": false,
+ "showStats": false,
+ "showWelcomeScreen": true,
+ "snapLines": [],
+ "startBoundElement": null,
+ "suggestedBindings": [],
+ "theme": "light",
+ "toast": null,
+ "userToFollow": null,
+ "viewBackgroundColor": "#ffffff",
+ "viewModeEnabled": false,
+ "width": 0,
+ "zenModeEnabled": false,
+ "zoom": {
+ "value": 1,
+ },
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support linear element creation and points manipulation through the editor > [end of test] element 0 1`] = `
+{
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "endArrowhead": "arrow",
+ "endBinding": null,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 20,
+ "id": "id27",
+ "index": "a0",
+ "isDeleted": false,
+ "lastCommittedPoint": [
+ 20,
+ 0,
+ ],
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 10,
+ 10,
+ ],
+ [
+ 20,
+ 20,
+ ],
+ ],
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "startArrowhead": null,
+ "startBinding": null,
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "arrow",
+ "updated": 1,
+ "version": 15,
+ "width": 20,
+ "x": 0,
+ "y": 0,
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support linear element creation and points manipulation through the editor > [end of test] history 1`] = `
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
+ "redoStack": [],
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id27": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id27" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "endArrowhead": "arrow",
+ "endBinding": null,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "lastCommittedPoint": [
+ 10,
+ 10,
+ ],
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 10,
+ 10,
+ ],
+ ],
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "startArrowhead": null,
+ "startBinding": null,
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "arrow",
+ "width": 10,
+ "x": 0,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id27" => Delta {
+ "deleted": {
+ "lastCommittedPoint": [
+ 20,
+ 0,
+ ],
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 10,
+ 10,
+ ],
+ [
+ 20,
+ 0,
+ ],
+ ],
+ "width": 20,
+ },
+ "inserted": {
+ "lastCommittedPoint": [
+ 10,
+ 10,
+ ],
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 10,
+ 10,
+ ],
+ ],
+ "width": 10,
+ },
+ },
+ },
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedLinearElementId": "id27",
+ },
+ "inserted": {
+ "selectedLinearElementId": null,
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "editingLinearElementId": "id27",
+ },
+ "inserted": {
+ "editingLinearElementId": null,
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id27" => Delta {
+ "deleted": {
+ "height": 20,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 10,
+ 10,
+ ],
+ [
+ 20,
+ 20,
+ ],
+ ],
+ },
+ "inserted": {
+ "height": 10,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 10,
+ 10,
+ ],
+ [
+ 20,
+ 0,
+ ],
+ ],
+ },
+ },
+ },
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "editingLinearElementId": null,
+ "selectedLinearElementId": null,
+ },
+ "inserted": {
+ "editingLinearElementId": "id27",
+ "selectedLinearElementId": "id27",
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ ],
+}
+`;
+
+exports[`history > singleplayer undo/redo > should support linear element creation and points manipulation through the editor > [end of test] number of elements 1`] = `1`;
+
+exports[`history > singleplayer undo/redo > should support linear element creation and points manipulation through the editor > [end of test] number of renders 1`] = `23`;
diff --git a/packages/excalidraw/tests/__snapshots__/move.test.tsx.snap b/packages/excalidraw/tests/__snapshots__/move.test.tsx.snap
index 39ad72b24c..9734378c19 100644
--- a/packages/excalidraw/tests/__snapshots__/move.test.tsx.snap
+++ b/packages/excalidraw/tests/__snapshots__/move.test.tsx.snap
@@ -173,7 +173,7 @@ exports[`move element > rectangles with binding arrow 6`] = `
"type": "rectangle",
"updated": 1,
"version": 7,
- "versionNonce": 745419401,
+ "versionNonce": 1984422985,
"width": 300,
"x": 201,
"y": 2,
@@ -186,7 +186,7 @@ exports[`move element > rectangles with binding arrow 7`] = `
"backgroundColor": "transparent",
"boundElements": null,
"customData": undefined,
- "endArrowhead": null,
+ "endArrowhead": "arrow",
"endBinding": {
"elementId": "id1",
"focus": -0.46666666666666673,
@@ -227,10 +227,10 @@ exports[`move element > rectangles with binding arrow 7`] = `
"strokeColor": "#1e1e1e",
"strokeStyle": "solid",
"strokeWidth": 2,
- "type": "line",
+ "type": "arrow",
"updated": 1,
- "version": 12,
- "versionNonce": 1984422985,
+ "version": 14,
+ "versionNonce": 2066753033,
"width": 81,
"x": 110,
"y": 49.981789081137734,
diff --git a/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap b/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap
index 13ec543817..a1b238c639 100644
--- a/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap
+++ b/packages/excalidraw/tests/__snapshots__/regressionTests.test.tsx.snap
@@ -111,362 +111,288 @@ exports[`given element A and group of elements B and given both are selected whe
`;
exports[`given element A and group of elements B and given both are selected when user clicks on B, on pointer up only elements from B should be selected > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 0,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
},
- "elements": [],
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 0,
- "y": 0,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id1" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 0,
+ "y": 30,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id2": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id2" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a2",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 0,
+ "y": 60,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 0,
- "y": 0,
},
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 10,
- "x": 0,
- "y": 30,
- },
- ],
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id2": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id2": true,
+ },
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 0,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 10,
- "x": 0,
- "y": 30,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id2",
- "index": "a2",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1604849351,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 493213705,
- "width": 10,
- "x": 0,
- "y": 60,
- },
- ],
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- "id2": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id2": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
},
- "selectedGroupIds": {
- "id5": true,
- },
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedGroupIds": {
+ "id5": true,
+ },
},
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 10,
- "x": 0,
- "y": 30,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id5",
- ],
- "height": 10,
- "id": "id0",
- "index": "a1V",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "inserted": {
+ "selectedGroupIds": {},
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 5,
- "versionNonce": 1006504105,
- "width": 10,
- "x": 0,
- "y": 0,
},
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id5",
- ],
- "height": 10,
- "id": "id2",
- "index": "a2",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id0" => Delta {
+ "deleted": {
+ "groupIds": [
+ "id5",
+ ],
+ "index": "a1V",
+ },
+ "inserted": {
+ "groupIds": [],
+ "index": "a0",
+ },
+ },
+ "id2" => Delta {
+ "deleted": {
+ "groupIds": [
+ "id5",
+ ],
+ },
+ "inserted": {
+ "groupIds": [],
+ },
},
- "seed": 1604849351,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 760410951,
- "width": 10,
- "x": 0,
- "y": 60,
},
- ],
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {},
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
},
],
}
@@ -589,362 +515,277 @@ exports[`given element A and group of elements B and given both are selected whe
`;
exports[`given element A and group of elements B and given both are selected when user shift-clicks on B, on pointer up only element A should be selected > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": 0,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
},
- "elements": [],
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 100,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 100,
- "x": 0,
- "y": 0,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id1" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": 110,
+ "y": 110,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id2": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 100,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id2" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a2",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 100,
+ "x": 220,
+ "y": 220,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 100,
- "x": 0,
- "y": 0,
},
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 100,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 100,
- "x": 110,
- "y": 110,
- },
- ],
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id2": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 100,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 100,
- "x": 0,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 100,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 100,
- "x": 110,
- "y": 110,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 100,
- "id": "id2",
- "index": "a2",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1604849351,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 493213705,
- "width": 100,
- "x": 220,
- "y": 220,
- },
- ],
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- "id2": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedGroupIds": {
+ "id4": true,
+ },
+ },
+ "inserted": {
+ "selectedGroupIds": {},
+ },
},
- "selectedGroupIds": {
- "id4": true,
- },
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 100,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id0" => Delta {
+ "deleted": {
+ "groupIds": [
+ "id4",
+ ],
+ "index": "a1V",
+ },
+ "inserted": {
+ "groupIds": [],
+ "index": "a0",
+ },
},
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 100,
- "x": 110,
- "y": 110,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4",
- ],
- "height": 100,
- "id": "id0",
- "index": "a1V",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "id2" => Delta {
+ "deleted": {
+ "groupIds": [
+ "id4",
+ ],
+ },
+ "inserted": {
+ "groupIds": [],
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 5,
- "versionNonce": 760410951,
- "width": 100,
- "x": 0,
- "y": 0,
},
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4",
- ],
- "height": 100,
- "id": "id2",
- "index": "a2",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
},
- "seed": 1604849351,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 1723083209,
- "width": 100,
- "x": 220,
- "y": 220,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {},
+ "selectedGroupIds": {
+ "id0": true,
+ "id1": true,
+ "id2": true,
+ "id4": false,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id0": true,
+ "id2": true,
+ },
+ "selectedGroupIds": {
+ "id4": true,
+ },
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
},
],
}
@@ -1058,764 +899,427 @@ exports[`regression tests > Cmd/Ctrl-click exclusively select element under poin
`;
exports[`regression tests > Cmd/Ctrl-click exclusively select element under pointer > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 0,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
},
- "elements": [],
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 0,
- "y": 0,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id1" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 30,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 0,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 10,
- "x": 30,
- "y": 0,
- },
- ],
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
},
- "selectedGroupIds": {
- "id4": true,
- },
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4",
- ],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 23633383,
- "width": 10,
- "x": 0,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4",
- ],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 493213705,
- "width": 10,
- "x": 30,
- "y": 0,
- },
- ],
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": "id4",
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedGroupIds": {
+ "id4": true,
+ },
+ },
+ "inserted": {
+ "selectedGroupIds": {},
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4",
- ],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id0" => Delta {
+ "deleted": {
+ "groupIds": [
+ "id4",
+ ],
+ },
+ "inserted": {
+ "groupIds": [],
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 23633383,
- "width": 10,
- "x": 0,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4",
- ],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "id1" => Delta {
+ "deleted": {
+ "groupIds": [
+ "id4",
+ ],
+ },
+ "inserted": {
+ "groupIds": [],
+ },
},
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 493213705,
- "width": 10,
- "x": 30,
- "y": 0,
},
- ],
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id7": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "editingGroupId": "id4",
+ "selectedElementIds": {},
+ "selectedGroupIds": {},
+ },
+ "inserted": {
+ "editingGroupId": null,
+ "selectedElementIds": {
+ "id1": true,
+ },
+ "selectedGroupIds": {
+ "id4": true,
+ },
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4",
- ],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 23633383,
- "width": 10,
- "x": 0,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4",
- ],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 493213705,
- "width": 10,
- "x": 30,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id7",
- "index": "a2",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1723083209,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 289600103,
- "width": 10,
- "x": 60,
- "y": 0,
- },
- ],
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- "id1": true,
- "id7": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "editingGroupId": null,
+ "selectedElementIds": {
+ "id7": true,
+ },
+ },
+ "inserted": {
+ "editingGroupId": "id4",
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
},
- "selectedGroupIds": {
- "id10": true,
- },
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4",
- "id10",
- ],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id7" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a2",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 60,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 5,
- "versionNonce": 406373543,
- "width": 10,
- "x": 0,
- "y": 0,
},
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4",
- "id10",
- ],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 5,
- "versionNonce": 941653321,
- "width": 10,
- "x": 30,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id10",
- ],
- "height": 10,
- "id": "id7",
- "index": "a2",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1723083209,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 908564423,
- "width": 10,
- "x": 60,
- "y": 0,
- },
- ],
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": "id4",
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ "id1": true,
+ },
+ "selectedGroupIds": {
+ "id4": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id7": true,
+ },
+ "selectedGroupIds": {},
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4",
- "id10",
- ],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 5,
- "versionNonce": 406373543,
- "width": 10,
- "x": 0,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4",
- "id10",
- ],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 5,
- "versionNonce": 941653321,
- "width": 10,
- "x": 30,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id10",
- ],
- "height": 10,
- "id": "id7",
- "index": "a2",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1723083209,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 908564423,
- "width": 10,
- "x": 60,
- "y": 0,
- },
- ],
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": "id10",
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id7": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id7": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4",
- "id10",
- ],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedGroupIds": {
+ "id10": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 5,
- "versionNonce": 406373543,
- "width": 10,
- "x": 0,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4",
- "id10",
- ],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "inserted": {
+ "selectedGroupIds": {
+ "id4": true,
+ },
},
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 5,
- "versionNonce": 941653321,
- "width": 10,
- "x": 30,
- "y": 0,
},
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id10",
- ],
- "height": 10,
- "id": "id7",
- "index": "a2",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id0" => Delta {
+ "deleted": {
+ "groupIds": [
+ "id4",
+ "id10",
+ ],
+ },
+ "inserted": {
+ "groupIds": [
+ "id4",
+ ],
+ },
+ },
+ "id1" => Delta {
+ "deleted": {
+ "groupIds": [
+ "id4",
+ "id10",
+ ],
+ },
+ "inserted": {
+ "groupIds": [
+ "id4",
+ ],
+ },
+ },
+ "id7" => Delta {
+ "deleted": {
+ "groupIds": [
+ "id10",
+ ],
+ },
+ "inserted": {
+ "groupIds": [],
+ },
},
- "seed": 1723083209,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 908564423,
- "width": 10,
- "x": 60,
- "y": 0,
},
- ],
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "editingGroupId": "id4",
+ "selectedElementIds": {},
+ "selectedGroupIds": {},
+ },
+ "inserted": {
+ "editingGroupId": null,
+ "selectedElementIds": {
+ "id1": true,
+ "id7": true,
+ },
+ "selectedGroupIds": {
+ "id10": true,
+ },
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "editingGroupId": "id10",
+ "selectedElementIds": {
+ "id7": true,
+ },
+ },
+ "inserted": {
+ "editingGroupId": "id4",
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
},
],
}
@@ -1931,110 +1435,86 @@ exports[`regression tests > Drags selected element when hitting only bounding bo
`;
exports[`regression tests > Drags selected element when hitting only bounding box and keeps element selected > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [],
- },
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 2,
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "ellipse",
- "updated": 1,
- "version": 3,
- "versionNonce": 2019559783,
- "width": 10,
- "x": 0,
- "y": 0,
- },
- ],
- },
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 2,
+ "inserted": {
+ "selectedElementIds": {},
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "ellipse",
- "updated": 1,
- "version": 4,
- "versionNonce": 1014066025,
- "width": 10,
- "x": 25,
- "y": 25,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "ellipse",
+ "width": 10,
+ "x": 0,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id0" => Delta {
+ "deleted": {
+ "x": 25,
+ "y": 25,
+ },
+ "inserted": {
+ "x": 0,
+ "y": 0,
+ },
+ },
+ },
+ },
},
],
}
@@ -2153,362 +1633,250 @@ exports[`regression tests > adjusts z order when grouping > [end of test] appSta
`;
exports[`regression tests > adjusts z order when grouping > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 10,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
},
- "elements": [],
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 10,
- "y": 10,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id1" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 30,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id2": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id2" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a2",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 50,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 10,
- "y": 10,
},
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 10,
- "x": 30,
- "y": 10,
- },
- ],
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id2": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id2": true,
+ },
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 10,
- "y": 10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 10,
- "x": 30,
- "y": 10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id2",
- "index": "a2",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1604849351,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 493213705,
- "width": 10,
- "x": 50,
- "y": 10,
- },
- ],
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- "id2": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id2": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
},
- "selectedGroupIds": {
- "id5": true,
- },
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedGroupIds": {
+ "id5": true,
+ },
},
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 10,
- "x": 30,
- "y": 10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id5",
- ],
- "height": 10,
- "id": "id0",
- "index": "a1V",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "inserted": {
+ "selectedGroupIds": {},
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 5,
- "versionNonce": 1006504105,
- "width": 10,
- "x": 10,
- "y": 10,
},
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id5",
- ],
- "height": 10,
- "id": "id2",
- "index": "a2",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id0" => Delta {
+ "deleted": {
+ "groupIds": [
+ "id5",
+ ],
+ "index": "a1V",
+ },
+ "inserted": {
+ "groupIds": [],
+ "index": "a0",
+ },
+ },
+ "id2" => Delta {
+ "deleted": {
+ "groupIds": [
+ "id5",
+ ],
+ },
+ "inserted": {
+ "groupIds": [],
+ },
},
- "seed": 1604849351,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 760410951,
- "width": 10,
- "x": 50,
- "y": 10,
},
- ],
+ },
},
],
}
@@ -2624,141 +1992,120 @@ exports[`regression tests > alt-drag duplicates an element > [end of test] appSt
`;
exports[`regression tests > alt-drag duplicates an element > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 10,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
},
- "elements": [],
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0_copy" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 10,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 10,
- "y": 10,
},
- ],
- },
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
+ "updated": Map {
+ "id0" => Delta {
+ "deleted": {
+ "index": "a1",
+ "x": 20,
+ "y": 20,
+ },
+ "inserted": {
+ "index": "a0",
+ "x": 10,
+ "y": 10,
+ },
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0_copy",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 238820263,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 5,
- "versionNonce": 400692809,
- "width": 10,
- "x": 10,
- "y": 10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 5,
- "versionNonce": 1604849351,
- "width": 10,
- "x": 20,
- "y": 20,
- },
- ],
},
],
}
@@ -2872,65 +2219,62 @@ exports[`regression tests > arrow keys > [end of test] appState 1`] = `
`;
exports[`regression tests > arrow keys > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [],
- },
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 10,
- "y": 10,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 10,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
],
}
@@ -3046,355 +2390,200 @@ exports[`regression tests > can drag element that covers another element, while
`;
exports[`regression tests > can drag element that covers another element, while another elem is selected > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 200,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 200,
+ "x": 100,
+ "y": 100,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
},
- "elements": [],
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 200,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 200,
- "x": 100,
- "y": 100,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id1" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 200,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 200,
+ "x": 100,
+ "y": 100,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id2": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 200,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id2" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 350,
+ "index": "a2",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "ellipse",
+ "width": 350,
+ "x": 300,
+ "y": 300,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 200,
- "x": 100,
- "y": 100,
},
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 200,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 200,
- "x": 100,
- "y": 100,
- },
- ],
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id2": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id2": true,
+ },
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 200,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id1" => Delta {
+ "deleted": {
+ "x": 300,
+ "y": 300,
+ },
+ "inserted": {
+ "x": 100,
+ "y": 100,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 200,
- "x": 100,
- "y": 100,
},
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 200,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 200,
- "x": 100,
- "y": 100,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 350,
- "id": "id2",
- "index": "a2",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 1604849351,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "ellipse",
- "updated": 1,
- "version": 3,
- "versionNonce": 493213705,
- "width": 350,
- "x": 300,
- "y": 300,
- },
- ],
- },
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 200,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 200,
- "x": 100,
- "y": 100,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 200,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 747212839,
- "width": 200,
- "x": 300,
- "y": 300,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 350,
- "id": "id2",
- "index": "a2",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 1604849351,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "ellipse",
- "updated": 1,
- "version": 3,
- "versionNonce": 493213705,
- "width": 350,
- "x": 300,
- "y": 300,
- },
- ],
},
],
}
@@ -3508,200 +2697,128 @@ exports[`regression tests > change the properties of a shape > [end of test] app
`;
exports[`regression tests > change the properties of a shape > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [],
- },
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 10,
- "y": 10,
- },
- ],
- },
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "#ffec99",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "inserted": {
+ "selectedElementIds": {},
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 1150084233,
- "width": 10,
- "x": 10,
- "y": 10,
},
- ],
- },
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "#ffc9c9",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 10,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 5,
- "versionNonce": 1014066025,
- "width": 10,
- "x": 10,
- "y": 10,
},
- ],
- },
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
+ "updated": Map {},
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "#ffc9c9",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1278240551,
- "strokeColor": "#1971c2",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 6,
- "versionNonce": 400692809,
- "width": 10,
- "x": 10,
- "y": 10,
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id0" => Delta {
+ "deleted": {
+ "backgroundColor": "#ffec99",
+ },
+ "inserted": {
+ "backgroundColor": "transparent",
+ },
+ },
+ },
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id0" => Delta {
+ "deleted": {
+ "backgroundColor": "#ffc9c9",
+ },
+ "inserted": {
+ "backgroundColor": "#ffec99",
+ },
+ },
+ },
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id0" => Delta {
+ "deleted": {
+ "strokeColor": "#1971c2",
+ },
+ "inserted": {
+ "strokeColor": "#1e1e1e",
+ },
+ },
+ },
+ },
},
],
}
@@ -3851,110 +2968,89 @@ exports[`regression tests > click on an element and drag it > [dragged] element
`;
exports[`regression tests > click on an element and drag it > [dragged] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [
+ [Function],
+ [Function],
+ ],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [],
- },
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 10,
- "y": 10,
- },
- ],
- },
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "inserted": {
+ "selectedElementIds": {},
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 1116226695,
- "width": 10,
- "x": 20,
- "y": 20,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 10,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id0" => Delta {
+ "deleted": {
+ "x": 20,
+ "y": 20,
+ },
+ "inserted": {
+ "x": 10,
+ "y": 10,
+ },
+ },
+ },
+ },
},
],
}
@@ -4070,155 +3166,110 @@ exports[`regression tests > click on an element and drag it > [end of test] appS
`;
exports[`regression tests > click on an element and drag it > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [],
- },
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 10,
- "y": 10,
- },
- ],
- },
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "inserted": {
+ "selectedElementIds": {},
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 1116226695,
- "width": 10,
- "x": 20,
- "y": 20,
},
- ],
- },
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 10,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 5,
- "versionNonce": 1604849351,
- "width": 10,
- "x": 10,
- "y": 10,
},
- ],
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id0" => Delta {
+ "deleted": {
+ "x": 20,
+ "y": 20,
+ },
+ "inserted": {
+ "x": 10,
+ "y": 10,
+ },
+ },
+ },
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id0" => Delta {
+ "deleted": {
+ "x": 10,
+ "y": 10,
+ },
+ "inserted": {
+ "x": 20,
+ "y": 20,
+ },
+ },
+ },
+ },
},
],
}
@@ -4334,141 +3385,136 @@ exports[`regression tests > click to select a shape > [end of test] appState 1`]
`;
exports[`regression tests > click to select a shape > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 10,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
},
- "elements": [],
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 10,
- "y": 10,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id1" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 30,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 10,
- "y": 10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 10,
- "x": 30,
- "y": 10,
- },
- ],
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
},
],
}
@@ -4585,248 +3631,190 @@ exports[`regression tests > click-drag to select a group > [end of test] appStat
`;
exports[`regression tests > click-drag to select a group > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 10,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
},
- "elements": [],
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 10,
- "y": 10,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id1" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 30,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id2": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id2" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a2",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 50,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 10,
- "y": 10,
},
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 10,
- "x": 30,
- "y": 10,
- },
- ],
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id2": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id2": true,
+ },
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 10,
- "y": 10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 10,
- "x": 30,
- "y": 10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id2",
- "index": "a2",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1604849351,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 493213705,
- "width": 10,
- "x": 50,
- "y": 10,
- },
- ],
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
},
],
}
@@ -4942,386 +3930,294 @@ exports[`regression tests > deleting last but one element in editing group shoul
`;
exports[`regression tests > deleting last but one element in editing group should unselect the group > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 10,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
},
- "elements": [],
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 10,
- "y": 0,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id1" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 50,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 10,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 10,
- "x": 50,
- "y": 0,
- },
- ],
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
},
- "selectedGroupIds": {
- "id4": true,
- },
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4",
- ],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 23633383,
- "width": 10,
- "x": 10,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4",
- ],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 493213705,
- "width": 10,
- "x": 50,
- "y": 0,
- },
- ],
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": "id4",
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedGroupIds": {
+ "id4": true,
+ },
+ },
+ "inserted": {
+ "selectedGroupIds": {},
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4",
- ],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": true,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id0" => Delta {
+ "deleted": {
+ "groupIds": [
+ "id4",
+ ],
+ },
+ "inserted": {
+ "groupIds": [],
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 5,
- "versionNonce": 81784553,
- "width": 10,
- "x": 10,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4",
- ],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "id1" => Delta {
+ "deleted": {
+ "groupIds": [
+ "id4",
+ ],
+ },
+ "inserted": {
+ "groupIds": [],
+ },
},
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 493213705,
- "width": 10,
- "x": 50,
- "y": 0,
},
- ],
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "editingGroupId": "id4",
+ "selectedElementIds": {},
+ "selectedGroupIds": {},
+ },
+ "inserted": {
+ "editingGroupId": null,
+ "selectedElementIds": {
+ "id1": true,
+ },
+ "selectedGroupIds": {
+ "id4": true,
+ },
+ },
},
- "selectedGroupIds": {
- "id4": false,
- },
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4",
- ],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": true,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 5,
- "versionNonce": 81784553,
- "width": 10,
- "x": 10,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4",
- ],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "inserted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
},
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 493213705,
- "width": 10,
- "x": 50,
- "y": 0,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {
+ "id0" => Delta {
+ "deleted": {
+ "isDeleted": true,
+ },
+ "inserted": {
+ "isDeleted": false,
+ },
+ },
+ },
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "editingGroupId": null,
+ "selectedElementIds": {},
+ },
+ "inserted": {
+ "editingGroupId": "id4",
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ "selectedGroupIds": {
+ "id4": false,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ "selectedGroupIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
},
],
}
@@ -5496,141 +4392,134 @@ exports[`regression tests > deselects group of selected elements on pointer down
`;
exports[`regression tests > deselects group of selected elements on pointer down when pointer doesn't hit any element > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 0,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
},
- "elements": [],
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 0,
- "y": 0,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id1" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "ellipse",
+ "width": 10,
+ "x": 110,
+ "y": 110,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 0,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "ellipse",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 10,
- "x": 110,
- "y": 110,
- },
- ],
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
},
],
}
@@ -5775,141 +4664,134 @@ exports[`regression tests > deselects group of selected elements on pointer up w
`;
exports[`regression tests > deselects group of selected elements on pointer up when pointer hits common bounding box without hitting any element > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 0,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
},
- "elements": [],
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 0,
- "y": 0,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id1" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "ellipse",
+ "width": 10,
+ "x": 110,
+ "y": 110,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 0,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "ellipse",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 10,
- "x": 110,
- "y": 110,
- },
- ],
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
},
],
}
@@ -6083,65 +4965,62 @@ exports[`regression tests > deselects selected element on pointer down when poin
`;
exports[`regression tests > deselects selected element on pointer down when pointer doesn't hit any element > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [],
- },
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 0,
- "y": 0,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 0,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
],
}
@@ -6255,65 +5134,81 @@ exports[`regression tests > deselects selected element, on pointer up, when clic
`;
exports[`regression tests > deselects selected element, on pointer up, when click hits element bounding box but doesn't hit the element > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [],
- },
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 100,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 2,
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "ellipse",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 100,
- "x": 0,
- "y": 0,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "ellipse",
+ "width": 100,
+ "x": 0,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {},
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
},
],
}
@@ -6427,365 +5322,264 @@ exports[`regression tests > double click to edit a group > [end of test] appStat
`;
exports[`regression tests > double click to edit a group > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 10,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
},
- "elements": [],
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 10,
- "y": 10,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id1" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 30,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id2": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id2" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a2",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 50,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 10,
- "y": 10,
},
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 10,
- "x": 30,
- "y": 10,
- },
- ],
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id2": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 10,
- "y": 10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 10,
- "x": 30,
- "y": 10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id2",
- "index": "a2",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1604849351,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 493213705,
- "width": 10,
- "x": 50,
- "y": 10,
- },
- ],
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- "id1": true,
- "id2": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedGroupIds": {
+ "id3": true,
+ },
+ },
+ "inserted": {
+ "selectedGroupIds": {},
+ },
},
- "selectedGroupIds": {
- "id3": true,
- },
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id3",
- ],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id0" => Delta {
+ "deleted": {
+ "groupIds": [
+ "id3",
+ ],
+ },
+ "inserted": {
+ "groupIds": [],
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 81784553,
- "width": 10,
- "x": 10,
- "y": 10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id3",
- ],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "id1" => Delta {
+ "deleted": {
+ "groupIds": [
+ "id3",
+ ],
+ },
+ "inserted": {
+ "groupIds": [],
+ },
},
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 747212839,
- "width": 10,
- "x": 30,
- "y": 10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id3",
- ],
- "height": 10,
- "id": "id2",
- "index": "a2",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "id2" => Delta {
+ "deleted": {
+ "groupIds": [
+ "id3",
+ ],
+ },
+ "inserted": {
+ "groupIds": [],
+ },
},
- "seed": 1604849351,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 1723083209,
- "width": 10,
- "x": 50,
- "y": 10,
},
- ],
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "editingGroupId": "id3",
+ "selectedElementIds": {},
+ "selectedGroupIds": {},
+ },
+ "inserted": {
+ "editingGroupId": null,
+ "selectedElementIds": {
+ "id0": true,
+ "id1": true,
+ },
+ "selectedGroupIds": {
+ "id3": true,
+ },
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
},
],
}
@@ -6903,218 +5697,168 @@ exports[`regression tests > drags selected elements from point inside common bou
`;
exports[`regression tests > drags selected elements from point inside common bounding box that doesn't hit any element and keeps elements selected after dragging > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 0,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
},
- "elements": [],
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 0,
- "y": 0,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id1" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "ellipse",
+ "width": 10,
+ "x": 110,
+ "y": 110,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 0,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "ellipse",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 10,
- "x": 110,
- "y": 110,
- },
- ],
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id0" => Delta {
+ "deleted": {
+ "x": 25,
+ "y": 25,
+ },
+ "inserted": {
+ "x": 0,
+ "y": 0,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 23633383,
- "width": 10,
- "x": 25,
- "y": 25,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 2,
+ "id1" => Delta {
+ "deleted": {
+ "x": 135,
+ "y": 135,
+ },
+ "inserted": {
+ "x": 110,
+ "y": 110,
+ },
},
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "ellipse",
- "updated": 1,
- "version": 4,
- "versionNonce": 915032327,
- "width": 10,
- "x": 135,
- "y": 135,
},
- ],
+ },
},
],
}
@@ -7226,2062 +5970,675 @@ exports[`regression tests > draw every type of shape > [end of test] appState 1`
`;
exports[`regression tests > draw every type of shape > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 20,
+ "x": 10,
+ "y": -10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
},
- "elements": [],
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 20,
- "x": 10,
- "y": -10,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id1" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "diamond",
+ "width": 20,
+ "x": 40,
+ "y": -10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id2": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id2" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a2",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "ellipse",
+ "width": 20,
+ "x": 70,
+ "y": -10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 20,
- "x": 10,
- "y": -10,
},
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "diamond",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 20,
- "x": 40,
- "y": -10,
- },
- ],
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id2": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id3": true,
+ },
+ "selectedLinearElementId": "id3",
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id2": true,
+ },
+ "selectedLinearElementId": null,
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id3" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "endArrowhead": "arrow",
+ "endBinding": null,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a3",
+ "isDeleted": false,
+ "lastCommittedPoint": null,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 50,
+ 10,
+ ],
+ ],
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "startArrowhead": null,
+ "startBinding": null,
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "arrow",
+ "width": 50,
+ "x": 130,
+ "y": -10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 20,
- "x": 10,
- "y": -10,
},
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "diamond",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 20,
- "x": 40,
- "y": -10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id2",
- "index": "a2",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 1604849351,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "ellipse",
- "updated": 1,
- "version": 3,
- "versionNonce": 493213705,
- "width": 20,
- "x": 70,
- "y": -10,
- },
- ],
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id3": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id4": true,
+ },
+ "selectedLinearElementId": "id4",
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id3": true,
+ },
+ "selectedLinearElementId": "id3",
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id4" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "endArrowhead": null,
+ "endBinding": null,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a4",
+ "isDeleted": false,
+ "lastCommittedPoint": null,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 50,
+ 10,
+ ],
+ ],
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "startArrowhead": null,
+ "startBinding": null,
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "line",
+ "width": 50,
+ "x": 220,
+ "y": -10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 20,
- "x": 10,
- "y": -10,
},
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "diamond",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 20,
- "x": 40,
- "y": -10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id2",
- "index": "a2",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 1604849351,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "ellipse",
- "updated": 1,
- "version": 3,
- "versionNonce": 493213705,
- "width": 20,
- "x": 70,
- "y": -10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "endArrowhead": "arrow",
- "endBinding": null,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id3",
- "index": "a3",
- "isDeleted": false,
- "lastCommittedPoint": null,
- "link": null,
- "locked": false,
- "opacity": 100,
- "points": [
- [
- 0,
- 0,
- ],
- [
- 50,
- 10,
- ],
- ],
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 81784553,
- "startArrowhead": null,
- "startBinding": null,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "arrow",
- "updated": 1,
- "version": 4,
- "versionNonce": 1006504105,
- "width": 50,
- "x": 130,
- "y": -10,
- },
- ],
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id4": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id5": true,
+ },
+ "selectedLinearElementId": null,
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id4": true,
+ },
+ "selectedLinearElementId": "id4",
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id5" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "endArrowhead": "arrow",
+ "endBinding": null,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a5",
+ "isDeleted": false,
+ "lastCommittedPoint": [
+ 50,
+ 10,
+ ],
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 50,
+ 10,
+ ],
+ ],
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "startArrowhead": null,
+ "startBinding": null,
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "arrow",
+ "width": 50,
+ "x": 310,
+ "y": -10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 20,
- "x": 10,
- "y": -10,
},
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "diamond",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 20,
- "x": 40,
- "y": -10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id2",
- "index": "a2",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 1604849351,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "ellipse",
- "updated": 1,
- "version": 3,
- "versionNonce": 493213705,
- "width": 20,
- "x": 70,
- "y": -10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "endArrowhead": "arrow",
- "endBinding": null,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id3",
- "index": "a3",
- "isDeleted": false,
- "lastCommittedPoint": null,
- "link": null,
- "locked": false,
- "opacity": 100,
- "points": [
- [
- 0,
- 0,
- ],
- [
- 50,
- 10,
- ],
- ],
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 81784553,
- "startArrowhead": null,
- "startBinding": null,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "arrow",
- "updated": 1,
- "version": 4,
- "versionNonce": 1006504105,
- "width": 50,
- "x": 130,
- "y": -10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "endArrowhead": null,
- "endBinding": null,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id4",
- "index": "a4",
- "isDeleted": false,
- "lastCommittedPoint": null,
- "link": null,
- "locked": false,
- "opacity": 100,
- "points": [
- [
- 0,
- 0,
- ],
- [
- 50,
- 10,
- ],
- ],
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 1315507081,
- "startArrowhead": null,
- "startBinding": null,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "line",
- "updated": 1,
- "version": 4,
- "versionNonce": 941653321,
- "width": 50,
- "x": 220,
- "y": -10,
- },
- ],
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id5": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id5" => Delta {
+ "deleted": {
+ "height": 20,
+ "lastCommittedPoint": [
+ 80,
+ 20,
+ ],
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 50,
+ 10,
+ ],
+ [
+ 80,
+ 20,
+ ],
+ ],
+ "width": 80,
+ },
+ "inserted": {
+ "height": 10,
+ "lastCommittedPoint": [
+ 50,
+ 10,
+ ],
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 50,
+ 10,
+ ],
+ ],
+ "width": 50,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 20,
- "x": 10,
- "y": -10,
},
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "diamond",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 20,
- "x": 40,
- "y": -10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id2",
- "index": "a2",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 1604849351,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "ellipse",
- "updated": 1,
- "version": 3,
- "versionNonce": 493213705,
- "width": 20,
- "x": 70,
- "y": -10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "endArrowhead": "arrow",
- "endBinding": null,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id3",
- "index": "a3",
- "isDeleted": false,
- "lastCommittedPoint": null,
- "link": null,
- "locked": false,
- "opacity": 100,
- "points": [
- [
- 0,
- 0,
- ],
- [
- 50,
- 10,
- ],
- ],
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 81784553,
- "startArrowhead": null,
- "startBinding": null,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "arrow",
- "updated": 1,
- "version": 4,
- "versionNonce": 1006504105,
- "width": 50,
- "x": 130,
- "y": -10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "endArrowhead": null,
- "endBinding": null,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id4",
- "index": "a4",
- "isDeleted": false,
- "lastCommittedPoint": null,
- "link": null,
- "locked": false,
- "opacity": 100,
- "points": [
- [
- 0,
- 0,
- ],
- [
- 50,
- 10,
- ],
- ],
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 1315507081,
- "startArrowhead": null,
- "startBinding": null,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "line",
- "updated": 1,
- "version": 4,
- "versionNonce": 941653321,
- "width": 50,
- "x": 220,
- "y": -10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "endArrowhead": "arrow",
- "endBinding": null,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id5",
- "index": "a5",
- "isDeleted": false,
- "lastCommittedPoint": [
- 50,
- 10,
- ],
- "link": null,
- "locked": false,
- "opacity": 100,
- "points": [
- [
- 0,
- 0,
- ],
- [
- 50,
- 10,
- ],
- ],
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 1402203177,
- "startArrowhead": null,
- "startBinding": null,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "arrow",
- "updated": 1,
- "version": 6,
- "versionNonce": 1163661225,
- "width": 50,
- "x": 310,
- "y": -10,
- },
- ],
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id5": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedLinearElementId": "id5",
+ },
+ "inserted": {
+ "selectedLinearElementId": null,
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 20,
- "x": 10,
- "y": -10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "diamond",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 20,
- "x": 40,
- "y": -10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id2",
- "index": "a2",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 1604849351,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "ellipse",
- "updated": 1,
- "version": 3,
- "versionNonce": 493213705,
- "width": 20,
- "x": 70,
- "y": -10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "endArrowhead": "arrow",
- "endBinding": null,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id3",
- "index": "a3",
- "isDeleted": false,
- "lastCommittedPoint": null,
- "link": null,
- "locked": false,
- "opacity": 100,
- "points": [
- [
- 0,
- 0,
- ],
- [
- 50,
- 10,
- ],
- ],
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 81784553,
- "startArrowhead": null,
- "startBinding": null,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "arrow",
- "updated": 1,
- "version": 4,
- "versionNonce": 1006504105,
- "width": 50,
- "x": 130,
- "y": -10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "endArrowhead": null,
- "endBinding": null,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id4",
- "index": "a4",
- "isDeleted": false,
- "lastCommittedPoint": null,
- "link": null,
- "locked": false,
- "opacity": 100,
- "points": [
- [
- 0,
- 0,
- ],
- [
- 50,
- 10,
- ],
- ],
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 1315507081,
- "startArrowhead": null,
- "startBinding": null,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "line",
- "updated": 1,
- "version": 4,
- "versionNonce": 941653321,
- "width": 50,
- "x": 220,
- "y": -10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "endArrowhead": "arrow",
- "endBinding": null,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id5",
- "index": "a5",
- "isDeleted": false,
- "lastCommittedPoint": [
- 80,
- 20,
- ],
- "link": null,
- "locked": false,
- "opacity": 100,
- "points": [
- [
- 0,
- 0,
- ],
- [
- 50,
- 10,
- ],
- [
- 80,
- 20,
- ],
- ],
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 1402203177,
- "startArrowhead": null,
- "startBinding": null,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "arrow",
- "updated": 1,
- "version": 8,
- "versionNonce": 1996028265,
- "width": 80,
- "x": 310,
- "y": -10,
- },
- ],
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id6": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id6": true,
+ },
+ "selectedLinearElementId": null,
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id5": true,
+ },
+ "selectedLinearElementId": "id5",
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id6" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "endArrowhead": null,
+ "endBinding": null,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a6",
+ "isDeleted": false,
+ "lastCommittedPoint": [
+ 50,
+ 10,
+ ],
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 50,
+ 10,
+ ],
+ ],
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "startArrowhead": null,
+ "startBinding": null,
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "line",
+ "width": 50,
+ "x": 430,
+ "y": -10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 20,
- "x": 10,
- "y": -10,
},
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "diamond",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 20,
- "x": 40,
- "y": -10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id2",
- "index": "a2",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 1604849351,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "ellipse",
- "updated": 1,
- "version": 3,
- "versionNonce": 493213705,
- "width": 20,
- "x": 70,
- "y": -10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "endArrowhead": "arrow",
- "endBinding": null,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id3",
- "index": "a3",
- "isDeleted": false,
- "lastCommittedPoint": null,
- "link": null,
- "locked": false,
- "opacity": 100,
- "points": [
- [
- 0,
- 0,
- ],
- [
- 50,
- 10,
- ],
- ],
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 81784553,
- "startArrowhead": null,
- "startBinding": null,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "arrow",
- "updated": 1,
- "version": 4,
- "versionNonce": 1006504105,
- "width": 50,
- "x": 130,
- "y": -10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "endArrowhead": null,
- "endBinding": null,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id4",
- "index": "a4",
- "isDeleted": false,
- "lastCommittedPoint": null,
- "link": null,
- "locked": false,
- "opacity": 100,
- "points": [
- [
- 0,
- 0,
- ],
- [
- 50,
- 10,
- ],
- ],
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 1315507081,
- "startArrowhead": null,
- "startBinding": null,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "line",
- "updated": 1,
- "version": 4,
- "versionNonce": 941653321,
- "width": 50,
- "x": 220,
- "y": -10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "endArrowhead": "arrow",
- "endBinding": null,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id5",
- "index": "a5",
- "isDeleted": false,
- "lastCommittedPoint": [
- 80,
- 20,
- ],
- "link": null,
- "locked": false,
- "opacity": 100,
- "points": [
- [
- 0,
- 0,
- ],
- [
- 50,
- 10,
- ],
- [
- 80,
- 20,
- ],
- ],
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 1402203177,
- "startArrowhead": null,
- "startBinding": null,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "arrow",
- "updated": 1,
- "version": 8,
- "versionNonce": 1996028265,
- "width": 80,
- "x": 310,
- "y": -10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "endArrowhead": null,
- "endBinding": null,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id6",
- "index": "a6",
- "isDeleted": false,
- "lastCommittedPoint": [
- 50,
- 10,
- ],
- "link": null,
- "locked": false,
- "opacity": 100,
- "points": [
- [
- 0,
- 0,
- ],
- [
- 50,
- 10,
- ],
- ],
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 1573789895,
- "startArrowhead": null,
- "startBinding": null,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "line",
- "updated": 1,
- "version": 6,
- "versionNonce": 1189086535,
- "width": 50,
- "x": 430,
- "y": -10,
- },
- ],
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id6": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id6" => Delta {
+ "deleted": {
+ "height": 20,
+ "lastCommittedPoint": [
+ 80,
+ 20,
+ ],
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 50,
+ 10,
+ ],
+ [
+ 80,
+ 20,
+ ],
+ ],
+ "width": 80,
+ },
+ "inserted": {
+ "height": 10,
+ "lastCommittedPoint": [
+ 50,
+ 10,
+ ],
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 50,
+ 10,
+ ],
+ ],
+ "width": 50,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 20,
- "x": 10,
- "y": -10,
},
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "diamond",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 20,
- "x": 40,
- "y": -10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id2",
- "index": "a2",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 1604849351,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "ellipse",
- "updated": 1,
- "version": 3,
- "versionNonce": 493213705,
- "width": 20,
- "x": 70,
- "y": -10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "endArrowhead": "arrow",
- "endBinding": null,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id3",
- "index": "a3",
- "isDeleted": false,
- "lastCommittedPoint": null,
- "link": null,
- "locked": false,
- "opacity": 100,
- "points": [
- [
- 0,
- 0,
- ],
- [
- 50,
- 10,
- ],
- ],
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 81784553,
- "startArrowhead": null,
- "startBinding": null,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "arrow",
- "updated": 1,
- "version": 4,
- "versionNonce": 1006504105,
- "width": 50,
- "x": 130,
- "y": -10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "endArrowhead": null,
- "endBinding": null,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id4",
- "index": "a4",
- "isDeleted": false,
- "lastCommittedPoint": null,
- "link": null,
- "locked": false,
- "opacity": 100,
- "points": [
- [
- 0,
- 0,
- ],
- [
- 50,
- 10,
- ],
- ],
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 1315507081,
- "startArrowhead": null,
- "startBinding": null,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "line",
- "updated": 1,
- "version": 4,
- "versionNonce": 941653321,
- "width": 50,
- "x": 220,
- "y": -10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "endArrowhead": "arrow",
- "endBinding": null,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id5",
- "index": "a5",
- "isDeleted": false,
- "lastCommittedPoint": [
- 80,
- 20,
- ],
- "link": null,
- "locked": false,
- "opacity": 100,
- "points": [
- [
- 0,
- 0,
- ],
- [
- 50,
- 10,
- ],
- [
- 80,
- 20,
- ],
- ],
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 1402203177,
- "startArrowhead": null,
- "startBinding": null,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "arrow",
- "updated": 1,
- "version": 8,
- "versionNonce": 1996028265,
- "width": 80,
- "x": 310,
- "y": -10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "endArrowhead": null,
- "endBinding": null,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id6",
- "index": "a6",
- "isDeleted": false,
- "lastCommittedPoint": [
- 80,
- 20,
- ],
- "link": null,
- "locked": false,
- "opacity": 100,
- "points": [
- [
- 0,
- 0,
- ],
- [
- 50,
- 10,
- ],
- [
- 80,
- 20,
- ],
- ],
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 1573789895,
- "startArrowhead": null,
- "startBinding": null,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "line",
- "updated": 1,
- "version": 8,
- "versionNonce": 337026951,
- "width": 80,
- "x": 430,
- "y": -10,
- },
- ],
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedLinearElementId": "id6",
+ },
+ "inserted": {
+ "selectedLinearElementId": null,
+ },
+ },
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {},
+ "selectedLinearElementId": null,
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 20,
- "x": 10,
- "y": -10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 2,
+ "inserted": {
+ "selectedElementIds": {
+ "id6": true,
+ },
+ "selectedLinearElementId": "id6",
},
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "diamond",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 20,
- "x": 40,
- "y": -10,
},
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id2",
- "index": "a2",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 2,
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id7" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a7",
+ "isDeleted": false,
+ "lastCommittedPoint": [
+ 50,
+ 10,
+ ],
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 50,
+ 10,
+ ],
+ [
+ 50,
+ 10,
+ ],
+ ],
+ "pressures": [
+ 0,
+ 0,
+ 0,
+ ],
+ "roughness": 1,
+ "roundness": null,
+ "simulatePressure": false,
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "freedraw",
+ "width": 50,
+ "x": 550,
+ "y": -10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
},
- "seed": 1604849351,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "ellipse",
- "updated": 1,
- "version": 3,
- "versionNonce": 493213705,
- "width": 20,
- "x": 70,
- "y": -10,
},
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "endArrowhead": "arrow",
- "endBinding": null,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id3",
- "index": "a3",
- "isDeleted": false,
- "lastCommittedPoint": null,
- "link": null,
- "locked": false,
- "opacity": 100,
- "points": [
- [
- 0,
- 0,
- ],
- [
- 50,
- 10,
- ],
- ],
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 81784553,
- "startArrowhead": null,
- "startBinding": null,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "arrow",
- "updated": 1,
- "version": 4,
- "versionNonce": 1006504105,
- "width": 50,
- "x": 130,
- "y": -10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "endArrowhead": null,
- "endBinding": null,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id4",
- "index": "a4",
- "isDeleted": false,
- "lastCommittedPoint": null,
- "link": null,
- "locked": false,
- "opacity": 100,
- "points": [
- [
- 0,
- 0,
- ],
- [
- 50,
- 10,
- ],
- ],
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 1315507081,
- "startArrowhead": null,
- "startBinding": null,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "line",
- "updated": 1,
- "version": 4,
- "versionNonce": 941653321,
- "width": 50,
- "x": 220,
- "y": -10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "endArrowhead": "arrow",
- "endBinding": null,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id5",
- "index": "a5",
- "isDeleted": false,
- "lastCommittedPoint": [
- 80,
- 20,
- ],
- "link": null,
- "locked": false,
- "opacity": 100,
- "points": [
- [
- 0,
- 0,
- ],
- [
- 50,
- 10,
- ],
- [
- 80,
- 20,
- ],
- ],
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 1402203177,
- "startArrowhead": null,
- "startBinding": null,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "arrow",
- "updated": 1,
- "version": 8,
- "versionNonce": 1996028265,
- "width": 80,
- "x": 310,
- "y": -10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "endArrowhead": null,
- "endBinding": null,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id6",
- "index": "a6",
- "isDeleted": false,
- "lastCommittedPoint": [
- 80,
- 20,
- ],
- "link": null,
- "locked": false,
- "opacity": 100,
- "points": [
- [
- 0,
- 0,
- ],
- [
- 50,
- 10,
- ],
- [
- 80,
- 20,
- ],
- ],
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 1573789895,
- "startArrowhead": null,
- "startBinding": null,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "line",
- "updated": 1,
- "version": 8,
- "versionNonce": 337026951,
- "width": 80,
- "x": 430,
- "y": -10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id7",
- "index": "a7",
- "isDeleted": false,
- "lastCommittedPoint": [
- 50,
- 10,
- ],
- "link": null,
- "locked": false,
- "opacity": 100,
- "points": [
- [
- 0,
- 0,
- ],
- [
- 50,
- 10,
- ],
- [
- 50,
- 10,
- ],
- ],
- "pressures": [
- 0,
- 0,
- 0,
- ],
- "roughness": 1,
- "roundness": null,
- "seed": 425216841,
- "simulatePressure": false,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "freedraw",
- "updated": 1,
- "version": 5,
- "versionNonce": 1688617961,
- "width": 50,
- "x": 550,
- "y": -10,
- },
- ],
+ "updated": Map {},
+ },
},
],
}
@@ -9398,248 +6755,209 @@ exports[`regression tests > given a group of selected elements with an element t
`;
exports[`regression tests > given a group of selected elements with an element that is not selected inside the group common bounding box when element that is not selected is clicked should switch selection to not selected element on pointer up > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 0,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
},
- "elements": [],
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 0,
- "y": 0,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id1" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "ellipse",
+ "width": 100,
+ "x": 110,
+ "y": 110,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id2": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id2" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a2",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "diamond",
+ "width": 100,
+ "x": 310,
+ "y": 310,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 0,
- "y": 0,
},
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 100,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "ellipse",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 100,
- "x": 110,
- "y": 110,
- },
- ],
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id2": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 0,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 100,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 2,
+ "inserted": {
+ "selectedElementIds": {
+ "id0": true,
+ "id2": true,
+ },
},
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "ellipse",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 100,
- "x": 110,
- "y": 110,
},
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 100,
- "id": "id2",
- "index": "a2",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 1604849351,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "diamond",
- "updated": 1,
- "version": 3,
- "versionNonce": 493213705,
- "width": 100,
- "x": 310,
- "y": 310,
- },
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
},
],
}
@@ -9756,141 +7074,155 @@ exports[`regression tests > given a selected element A and a not selected elemen
`;
exports[`regression tests > given a selected element A and a not selected element B with higher z-index than A and given B partially overlaps A when there's a shift-click on the overlapped section B is added to the selection > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "#ffc9c9",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 1000,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 1000,
+ "x": 0,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
},
- "elements": [],
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "#ffc9c9",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 1000,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
},
- "seed": 449462985,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 2019559783,
- "width": 1000,
- "x": 0,
- "y": 0,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id1" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "#ffc9c9",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 1000,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "ellipse",
+ "width": 1000,
+ "x": 500,
+ "y": 500,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "#ffc9c9",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 1000,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
},
- "seed": 449462985,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 2019559783,
- "width": 1000,
- "x": 0,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "#ffc9c9",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 1000,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 2,
+ "inserted": {
+ "selectedElementIds": {},
},
- "seed": 1116226695,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "ellipse",
- "updated": 1,
- "version": 3,
- "versionNonce": 400692809,
- "width": 1000,
- "x": 500,
- "y": 500,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
},
],
}
@@ -10006,96 +7338,114 @@ exports[`regression tests > given selected element A with lower z-index than uns
`;
exports[`regression tests > given selected element A with lower z-index than unselected element B and given B is partially over A when clicking intersection between A and B B should be selected on pointer up > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "red",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 1000,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 1000,
+ "x": 0,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ "id1" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "red",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 500,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 500,
+ "x": 500,
+ "y": 500,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
},
- "elements": [],
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "red",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 1000,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 2,
- "versionNonce": 453191,
- "width": 1000,
- "x": 0,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "red",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 500,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 449462985,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 2,
- "versionNonce": 401146281,
- "width": 500,
- "x": 500,
- "y": 500,
- },
- ],
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
},
],
}
@@ -10211,172 +7561,117 @@ exports[`regression tests > given selected element A with lower z-index than uns
`;
exports[`regression tests > given selected element A with lower z-index than unselected element B and given B is partially over A when dragging on intersection between A and B A should be dragged and keep being selected > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "red",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 1000,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 1000,
+ "x": 0,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ "id1" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "red",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 500,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 500,
+ "x": 500,
+ "y": 500,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
},
- "elements": [],
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "red",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 1000,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id0" => Delta {
+ "deleted": {
+ "x": 100,
+ "y": 100,
+ },
+ "inserted": {
+ "x": 0,
+ "y": 0,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 2,
- "versionNonce": 453191,
- "width": 1000,
- "x": 0,
- "y": 0,
},
- {
- "angle": 0,
- "backgroundColor": "red",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 500,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 449462985,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 2,
- "versionNonce": 401146281,
- "width": 500,
- "x": 500,
- "y": 500,
- },
- ],
- },
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "red",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 1000,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 1014066025,
- "width": 1000,
- "x": 100,
- "y": 100,
- },
- {
- "angle": 0,
- "backgroundColor": "red",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 500,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 449462985,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 2,
- "versionNonce": 401146281,
- "width": 500,
- "x": 500,
- "y": 500,
- },
- ],
},
],
}
@@ -10490,65 +7785,62 @@ exports[`regression tests > key 2 selects rectangle tool > [end of test] appStat
`;
exports[`regression tests > key 2 selects rectangle tool > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [],
- },
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 10,
- "y": 10,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 10,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
],
}
@@ -10662,65 +7954,62 @@ exports[`regression tests > key 3 selects diamond tool > [end of test] appState
`;
exports[`regression tests > key 3 selects diamond tool > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [],
- },
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 2,
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "diamond",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 10,
- "y": 10,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "diamond",
+ "width": 10,
+ "x": 10,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
],
}
@@ -10834,65 +8123,62 @@ exports[`regression tests > key 4 selects ellipse tool > [end of test] appState
`;
exports[`regression tests > key 4 selects ellipse tool > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [],
- },
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 2,
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "ellipse",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 10,
- "y": 10,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "ellipse",
+ "width": 10,
+ "x": 10,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
],
}
@@ -11029,80 +8315,79 @@ exports[`regression tests > key 5 selects arrow tool > [end of test] appState 1`
`;
exports[`regression tests > key 5 selects arrow tool > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [],
- },
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "endArrowhead": "arrow",
- "endBinding": null,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "lastCommittedPoint": null,
- "link": null,
- "locked": false,
- "opacity": 100,
- "points": [
- [
- 0,
- 0,
- ],
- [
- 10,
- 10,
- ],
- ],
- "roughness": 1,
- "roundness": {
- "type": 2,
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ "selectedLinearElementId": "id0",
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ "selectedLinearElementId": null,
},
- "seed": 1278240551,
- "startArrowhead": null,
- "startBinding": null,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "arrow",
- "updated": 1,
- "version": 4,
- "versionNonce": 2019559783,
- "width": 10,
- "x": 10,
- "y": 10,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "endArrowhead": "arrow",
+ "endBinding": null,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "lastCommittedPoint": null,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 10,
+ 10,
+ ],
+ ],
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "startArrowhead": null,
+ "startBinding": null,
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "arrow",
+ "width": 10,
+ "x": 10,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
],
}
@@ -11239,80 +8524,79 @@ exports[`regression tests > key 6 selects line tool > [end of test] appState 1`]
`;
exports[`regression tests > key 6 selects line tool > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [],
- },
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "endArrowhead": null,
- "endBinding": null,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "lastCommittedPoint": null,
- "link": null,
- "locked": false,
- "opacity": 100,
- "points": [
- [
- 0,
- 0,
- ],
- [
- 10,
- 10,
- ],
- ],
- "roughness": 1,
- "roundness": {
- "type": 2,
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ "selectedLinearElementId": "id0",
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ "selectedLinearElementId": null,
},
- "seed": 1278240551,
- "startArrowhead": null,
- "startBinding": null,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "line",
- "updated": 1,
- "version": 4,
- "versionNonce": 2019559783,
- "width": 10,
- "x": 10,
- "y": 10,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "endArrowhead": null,
+ "endBinding": null,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "lastCommittedPoint": null,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 10,
+ 10,
+ ],
+ ],
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "startArrowhead": null,
+ "startBinding": null,
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "line",
+ "width": 10,
+ "x": 10,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
],
}
@@ -11424,85 +8708,78 @@ exports[`regression tests > key 7 selects freedraw tool > [end of test] appState
`;
exports[`regression tests > key 7 selects freedraw tool > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [],
- },
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "lastCommittedPoint": [
- 10,
- 10,
- ],
- "link": null,
- "locked": false,
- "opacity": 100,
- "points": [
- [
- 0,
- 0,
- ],
- [
- 10,
- 10,
- ],
- [
- 10,
- 10,
- ],
- ],
- "pressures": [
- 0,
- 0,
- 0,
- ],
- "roughness": 1,
- "roundness": null,
- "seed": 1278240551,
- "simulatePressure": false,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "freedraw",
- "updated": 1,
- "version": 5,
- "versionNonce": 1116226695,
- "width": 10,
- "x": 10,
- "y": 10,
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "lastCommittedPoint": [
+ 10,
+ 10,
+ ],
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 10,
+ 10,
+ ],
+ [
+ 10,
+ 10,
+ ],
+ ],
+ "pressures": [
+ 0,
+ 0,
+ 0,
+ ],
+ "roughness": 1,
+ "roundness": null,
+ "simulatePressure": false,
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "freedraw",
+ "width": 10,
+ "x": 10,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
],
}
@@ -11639,80 +8916,79 @@ exports[`regression tests > key a selects arrow tool > [end of test] appState 1`
`;
exports[`regression tests > key a selects arrow tool > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [],
- },
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "endArrowhead": "arrow",
- "endBinding": null,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "lastCommittedPoint": null,
- "link": null,
- "locked": false,
- "opacity": 100,
- "points": [
- [
- 0,
- 0,
- ],
- [
- 10,
- 10,
- ],
- ],
- "roughness": 1,
- "roundness": {
- "type": 2,
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ "selectedLinearElementId": "id0",
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ "selectedLinearElementId": null,
},
- "seed": 1278240551,
- "startArrowhead": null,
- "startBinding": null,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "arrow",
- "updated": 1,
- "version": 4,
- "versionNonce": 2019559783,
- "width": 10,
- "x": 10,
- "y": 10,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "endArrowhead": "arrow",
+ "endBinding": null,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "lastCommittedPoint": null,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 10,
+ 10,
+ ],
+ ],
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "startArrowhead": null,
+ "startBinding": null,
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "arrow",
+ "width": 10,
+ "x": 10,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
],
}
@@ -11826,65 +9102,62 @@ exports[`regression tests > key d selects diamond tool > [end of test] appState
`;
exports[`regression tests > key d selects diamond tool > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [],
- },
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 2,
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "diamond",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 10,
- "y": 10,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "diamond",
+ "width": 10,
+ "x": 10,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
],
}
@@ -12021,80 +9294,79 @@ exports[`regression tests > key l selects line tool > [end of test] appState 1`]
`;
exports[`regression tests > key l selects line tool > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [],
- },
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "endArrowhead": null,
- "endBinding": null,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "lastCommittedPoint": null,
- "link": null,
- "locked": false,
- "opacity": 100,
- "points": [
- [
- 0,
- 0,
- ],
- [
- 10,
- 10,
- ],
- ],
- "roughness": 1,
- "roundness": {
- "type": 2,
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ "selectedLinearElementId": "id0",
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ "selectedLinearElementId": null,
},
- "seed": 1278240551,
- "startArrowhead": null,
- "startBinding": null,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "line",
- "updated": 1,
- "version": 4,
- "versionNonce": 2019559783,
- "width": 10,
- "x": 10,
- "y": 10,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "endArrowhead": null,
+ "endBinding": null,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "lastCommittedPoint": null,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 10,
+ 10,
+ ],
+ ],
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "startArrowhead": null,
+ "startBinding": null,
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "line",
+ "width": 10,
+ "x": 10,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
],
}
@@ -12208,65 +9480,62 @@ exports[`regression tests > key o selects ellipse tool > [end of test] appState
`;
exports[`regression tests > key o selects ellipse tool > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [],
- },
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 2,
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "ellipse",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 10,
- "y": 10,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "ellipse",
+ "width": 10,
+ "x": 10,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
],
}
@@ -12378,85 +9647,78 @@ exports[`regression tests > key p selects freedraw tool > [end of test] appState
`;
exports[`regression tests > key p selects freedraw tool > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [],
- },
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "lastCommittedPoint": [
- 10,
- 10,
- ],
- "link": null,
- "locked": false,
- "opacity": 100,
- "points": [
- [
- 0,
- 0,
- ],
- [
- 10,
- 10,
- ],
- [
- 10,
- 10,
- ],
- ],
- "pressures": [
- 0,
- 0,
- 0,
- ],
- "roughness": 1,
- "roundness": null,
- "seed": 1278240551,
- "simulatePressure": false,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "freedraw",
- "updated": 1,
- "version": 5,
- "versionNonce": 1116226695,
- "width": 10,
- "x": 10,
- "y": 10,
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "lastCommittedPoint": [
+ 10,
+ 10,
+ ],
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 10,
+ 10,
+ ],
+ [
+ 10,
+ 10,
+ ],
+ ],
+ "pressures": [
+ 0,
+ 0,
+ 0,
+ ],
+ "roughness": 1,
+ "roundness": null,
+ "simulatePressure": false,
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "freedraw",
+ "width": 10,
+ "x": 10,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
],
}
@@ -12570,65 +9832,62 @@ exports[`regression tests > key r selects rectangle tool > [end of test] appStat
`;
exports[`regression tests > key r selects rectangle tool > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [],
- },
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 10,
- "y": 10,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 10,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
],
}
@@ -12750,581 +10009,388 @@ exports[`regression tests > make a group and duplicate it > [end of test] appSta
`;
exports[`regression tests > make a group and duplicate it > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 10,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
},
- "elements": [],
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 10,
- "y": 10,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id1" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 30,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id2": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id2" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a2",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 50,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 10,
- "y": 10,
},
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 10,
- "x": 30,
- "y": 10,
- },
- ],
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id2": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 10,
- "y": 10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 10,
- "x": 30,
- "y": 10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id2",
- "index": "a2",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1604849351,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 493213705,
- "width": 10,
- "x": 50,
- "y": 10,
- },
- ],
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- "id1": true,
- "id2": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedGroupIds": {
+ "id4": true,
+ },
+ },
+ "inserted": {
+ "selectedGroupIds": {},
+ },
},
- "selectedGroupIds": {
- "id4": true,
- },
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4",
- ],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id0" => Delta {
+ "deleted": {
+ "groupIds": [
+ "id4",
+ ],
+ },
+ "inserted": {
+ "groupIds": [],
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 1723083209,
- "width": 10,
- "x": 10,
- "y": 10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4",
- ],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "id1" => Delta {
+ "deleted": {
+ "groupIds": [
+ "id4",
+ ],
+ },
+ "inserted": {
+ "groupIds": [],
+ },
},
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 760410951,
- "width": 10,
- "x": 30,
- "y": 10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4",
- ],
- "height": 10,
- "id": "id2",
- "index": "a2",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "id2" => Delta {
+ "deleted": {
+ "groupIds": [
+ "id4",
+ ],
+ },
+ "inserted": {
+ "groupIds": [],
+ },
},
- "seed": 1604849351,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 1006504105,
- "width": 10,
- "x": 50,
- "y": 10,
},
- ],
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- "id1": true,
- "id2": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
},
- "selectedGroupIds": {
- "id4": true,
- },
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4_copy",
- ],
- "height": 10,
- "id": "id0_copy",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0_copy" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [
+ "id4_copy",
+ ],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 10,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
},
- "seed": 1359939303,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 6,
- "versionNonce": 1349943049,
- "width": 10,
- "x": 10,
- "y": 10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4_copy",
- ],
- "height": 10,
- "id": "id1_copy",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "id1_copy" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [
+ "id4_copy",
+ ],
+ "height": 10,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 30,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
},
- "seed": 2004587015,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 6,
- "versionNonce": 2101589481,
- "width": 10,
- "x": 30,
- "y": 10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4_copy",
- ],
- "height": 10,
- "id": "id2_copy",
- "index": "a2",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "id2_copy" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [
+ "id4_copy",
+ ],
+ "height": 10,
+ "index": "a2",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 50,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
},
- "seed": 845789479,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 6,
- "versionNonce": 1292308681,
- "width": 10,
- "x": 50,
- "y": 10,
},
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4",
- ],
- "height": 10,
- "id": "id0",
- "index": "a3",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "updated": Map {
+ "id0" => Delta {
+ "deleted": {
+ "index": "a3",
+ "x": 20,
+ "y": 20,
+ },
+ "inserted": {
+ "index": "a0",
+ "x": 10,
+ "y": 10,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 6,
- "versionNonce": 927333447,
- "width": 10,
- "x": 20,
- "y": 20,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4",
- ],
- "height": 10,
- "id": "id1",
- "index": "a4",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "id1" => Delta {
+ "deleted": {
+ "index": "a4",
+ "x": 40,
+ "y": 20,
+ },
+ "inserted": {
+ "index": "a1",
+ "x": 30,
+ "y": 10,
+ },
},
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 6,
- "versionNonce": 1163661225,
- "width": 10,
- "x": 40,
- "y": 20,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4",
- ],
- "height": 10,
- "id": "id2",
- "index": "a5",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "id2" => Delta {
+ "deleted": {
+ "index": "a5",
+ "x": 60,
+ "y": 20,
+ },
+ "inserted": {
+ "index": "a2",
+ "x": 50,
+ "y": 10,
+ },
},
- "seed": 1604849351,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 6,
- "versionNonce": 1508694887,
- "width": 10,
- "x": 60,
- "y": 20,
},
- ],
+ },
},
],
}
@@ -13440,141 +10506,157 @@ exports[`regression tests > noop interaction after undo shouldn't create history
`;
exports[`regression tests > noop interaction after undo shouldn't create history entry > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 10,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
},
- "elements": [],
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 10,
- "y": 10,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id1" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 30,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 10,
- "y": 10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "inserted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
},
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 10,
- "x": 30,
- "y": 10,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
},
],
}
@@ -13686,22 +10768,12 @@ exports[`regression tests > pinch-to-zoom works > [end of test] appState 1`] = `
`;
exports[`regression tests > pinch-to-zoom works > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [],
- },
- ],
+ "undoStack": [],
}
`;
@@ -13813,65 +10885,81 @@ exports[`regression tests > shift click on selected element should deselect it o
`;
exports[`regression tests > shift click on selected element should deselect it on pointer up > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [],
- },
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 0,
- "y": 0,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 0,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {},
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
},
],
}
@@ -13989,218 +11077,189 @@ exports[`regression tests > shift-click to multiselect, then drag > [end of test
`;
exports[`regression tests > shift-click to multiselect, then drag > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 10,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
},
- "elements": [],
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 10,
- "y": 10,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id1" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 30,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 10,
- "y": 10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 10,
- "x": 30,
- "y": 10,
- },
- ],
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 493213705,
- "width": 10,
- "x": 20,
- "y": 20,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
},
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id0" => Delta {
+ "deleted": {
+ "x": 20,
+ "y": 20,
+ },
+ "inserted": {
+ "x": 10,
+ "y": 10,
+ },
+ },
+ "id1" => Delta {
+ "deleted": {
+ "x": 40,
+ "y": 20,
+ },
+ "inserted": {
+ "x": 30,
+ "y": 10,
+ },
},
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 81784553,
- "width": 10,
- "x": 40,
- "y": 20,
},
- ],
+ },
},
],
}
@@ -14320,474 +11379,288 @@ exports[`regression tests > should group elements and ungroup them > [end of tes
`;
exports[`regression tests > should group elements and ungroup them > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 10,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
},
- "elements": [],
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 10,
- "y": 10,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id1" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 30,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id2": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id2" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a2",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 50,
+ "y": 10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 10,
- "y": 10,
},
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 10,
- "x": 30,
- "y": 10,
- },
- ],
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id2": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 10,
- "y": 10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 10,
- "x": 30,
- "y": 10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id2",
- "index": "a2",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1604849351,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 493213705,
- "width": 10,
- "x": 50,
- "y": 10,
- },
- ],
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- "id1": true,
- "id2": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedGroupIds": {
+ "id4": true,
+ },
+ },
+ "inserted": {
+ "selectedGroupIds": {},
+ },
},
- "selectedGroupIds": {
- "id4": true,
- },
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4",
- ],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id0" => Delta {
+ "deleted": {
+ "groupIds": [
+ "id4",
+ ],
+ },
+ "inserted": {
+ "groupIds": [],
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 1723083209,
- "width": 10,
- "x": 10,
- "y": 10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4",
- ],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "id1" => Delta {
+ "deleted": {
+ "groupIds": [
+ "id4",
+ ],
+ },
+ "inserted": {
+ "groupIds": [],
+ },
},
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 760410951,
- "width": 10,
- "x": 30,
- "y": 10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4",
- ],
- "height": 10,
- "id": "id2",
- "index": "a2",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "id2" => Delta {
+ "deleted": {
+ "groupIds": [
+ "id4",
+ ],
+ },
+ "inserted": {
+ "groupIds": [],
+ },
},
- "seed": 1604849351,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 1006504105,
- "width": 10,
- "x": 50,
- "y": 10,
},
- ],
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- "id1": true,
- "id2": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedGroupIds": {},
+ },
+ "inserted": {
+ "selectedGroupIds": {
+ "id4": true,
+ },
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id0" => Delta {
+ "deleted": {
+ "groupIds": [],
+ },
+ "inserted": {
+ "groupIds": [
+ "id4",
+ ],
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 5,
- "versionNonce": 640725609,
- "width": 10,
- "x": 10,
- "y": 10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "id1" => Delta {
+ "deleted": {
+ "groupIds": [],
+ },
+ "inserted": {
+ "groupIds": [
+ "id4",
+ ],
+ },
},
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 5,
- "versionNonce": 406373543,
- "width": 10,
- "x": 30,
- "y": 10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id2",
- "index": "a2",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "id2" => Delta {
+ "deleted": {
+ "groupIds": [],
+ },
+ "inserted": {
+ "groupIds": [
+ "id4",
+ ],
+ },
},
- "seed": 1604849351,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 5,
- "versionNonce": 941653321,
- "width": 10,
- "x": 50,
- "y": 10,
},
- ],
+ },
},
],
}
@@ -14911,781 +11784,485 @@ exports[`regression tests > single-clicking on a subgroup of a selected group sh
`;
exports[`regression tests > single-clicking on a subgroup of a selected group should not alter selection > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 10,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
},
- "elements": [],
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 10,
- "y": 0,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id1" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 50,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 10,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 10,
- "x": 50,
- "y": 0,
- },
- ],
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
},
- "selectedGroupIds": {
- "id4": true,
- },
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4",
- ],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 23633383,
- "width": 10,
- "x": 10,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4",
- ],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 493213705,
- "width": 10,
- "x": 50,
- "y": 0,
- },
- ],
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id5": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedGroupIds": {
+ "id4": true,
+ },
+ },
+ "inserted": {
+ "selectedGroupIds": {},
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4",
- ],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id0" => Delta {
+ "deleted": {
+ "groupIds": [
+ "id4",
+ ],
+ },
+ "inserted": {
+ "groupIds": [],
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 23633383,
- "width": 10,
- "x": 10,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4",
- ],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "id1" => Delta {
+ "deleted": {
+ "groupIds": [
+ "id4",
+ ],
+ },
+ "inserted": {
+ "groupIds": [],
+ },
},
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 493213705,
- "width": 10,
- "x": 50,
- "y": 0,
},
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id5",
- "index": "a2",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 81784553,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 760410951,
- "width": 10,
- "x": 10,
- "y": 50,
- },
- ],
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id6": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id5": true,
+ },
+ "selectedGroupIds": {},
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id0": true,
+ "id1": true,
+ },
+ "selectedGroupIds": {
+ "id4": true,
+ },
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4",
- ],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id5" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a2",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 10,
+ "y": 50,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 23633383,
- "width": 10,
- "x": 10,
- "y": 0,
},
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4",
- ],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 493213705,
- "width": 10,
- "x": 50,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id5",
- "index": "a2",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 81784553,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 760410951,
- "width": 10,
- "x": 10,
- "y": 50,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id6",
- "index": "a3",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 289600103,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 640725609,
- "width": 10,
- "x": 50,
- "y": 50,
- },
- ],
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id5": true,
- "id6": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id6": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id5": true,
+ },
+ },
},
- "selectedGroupIds": {
- "id9": true,
- },
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4",
- ],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id6" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a3",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 50,
+ "y": 50,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 23633383,
- "width": 10,
- "x": 10,
- "y": 0,
},
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4",
- ],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 493213705,
- "width": 10,
- "x": 50,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id9",
- ],
- "height": 10,
- "id": "id5",
- "index": "a2",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 81784553,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 1402203177,
- "width": 10,
- "x": 10,
- "y": 50,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id9",
- ],
- "height": 10,
- "id": "id6",
- "index": "a3",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 289600103,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 1359939303,
- "width": 10,
- "x": 50,
- "y": 50,
- },
- ],
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- "id1": true,
- "id5": true,
- "id6": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id5": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id6": true,
+ },
+ },
},
- "selectedGroupIds": {
- "id10": true,
- },
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4",
- "id10",
- ],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id6": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 5,
- "versionNonce": 2004587015,
- "width": 10,
- "x": 10,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id4",
- "id10",
- ],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "inserted": {
+ "selectedElementIds": {},
},
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 5,
- "versionNonce": 2101589481,
- "width": 10,
- "x": 50,
- "y": 0,
},
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id9",
- "id10",
- ],
- "height": 10,
- "id": "id5",
- "index": "a2",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedGroupIds": {
+ "id9": true,
+ },
},
- "seed": 81784553,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 5,
- "versionNonce": 845789479,
- "width": 10,
- "x": 10,
- "y": 50,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id9",
- "id10",
- ],
- "height": 10,
- "id": "id6",
- "index": "a3",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "inserted": {
+ "selectedGroupIds": {},
},
- "seed": 289600103,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 5,
- "versionNonce": 1292308681,
- "width": 10,
- "x": 50,
- "y": 50,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id5" => Delta {
+ "deleted": {
+ "groupIds": [
+ "id9",
+ ],
+ },
+ "inserted": {
+ "groupIds": [],
+ },
+ },
+ "id6" => Delta {
+ "deleted": {
+ "groupIds": [
+ "id9",
+ ],
+ },
+ "inserted": {
+ "groupIds": [],
+ },
+ },
+ },
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ "id1": true,
+ },
+ "selectedGroupIds": {
+ "id4": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ "selectedGroupIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedGroupIds": {
+ "id10": true,
+ },
+ },
+ "inserted": {
+ "selectedGroupIds": {
+ "id4": true,
+ "id9": true,
+ },
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id0" => Delta {
+ "deleted": {
+ "groupIds": [
+ "id4",
+ "id10",
+ ],
+ },
+ "inserted": {
+ "groupIds": [
+ "id4",
+ ],
+ },
+ },
+ "id1" => Delta {
+ "deleted": {
+ "groupIds": [
+ "id4",
+ "id10",
+ ],
+ },
+ "inserted": {
+ "groupIds": [
+ "id4",
+ ],
+ },
+ },
+ "id5" => Delta {
+ "deleted": {
+ "groupIds": [
+ "id9",
+ "id10",
+ ],
+ },
+ "inserted": {
+ "groupIds": [
+ "id9",
+ ],
+ },
+ },
+ "id6" => Delta {
+ "deleted": {
+ "groupIds": [
+ "id9",
+ "id10",
+ ],
+ },
+ "inserted": {
+ "groupIds": [
+ "id9",
+ ],
+ },
+ },
+ },
+ },
},
],
}
@@ -15800,22 +12377,12 @@ exports[`regression tests > spacebar + drag scrolls the canvas > [end of test] a
`;
exports[`regression tests > spacebar + drag scrolls the canvas > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [],
- },
- ],
+ "undoStack": [],
}
`;
@@ -15929,716 +12496,462 @@ exports[`regression tests > supports nested groups > [end of test] appState 1`]
`;
exports[`regression tests > supports nested groups > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 50,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 50,
+ "x": 0,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
},
- "elements": [],
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 50,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 50,
- "x": 0,
- "y": 0,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id1" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 50,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 50,
+ "x": 100,
+ "y": 100,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id2": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 50,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id2" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 50,
+ "index": "a2",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 50,
+ "x": 200,
+ "y": 200,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 50,
- "x": 0,
- "y": 0,
},
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 50,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 50,
- "x": 100,
- "y": 100,
- },
- ],
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id2": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 50,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 50,
- "x": 0,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 50,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 50,
- "x": 100,
- "y": 100,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 50,
- "id": "id2",
- "index": "a2",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1604849351,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 493213705,
- "width": 50,
- "x": 200,
- "y": 200,
- },
- ],
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- "id1": true,
- "id2": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedGroupIds": {
+ "id3": true,
+ },
+ },
+ "inserted": {
+ "selectedGroupIds": {},
+ },
},
- "selectedGroupIds": {
- "id3": true,
- },
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id3",
- ],
- "height": 50,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id0" => Delta {
+ "deleted": {
+ "groupIds": [
+ "id3",
+ ],
+ },
+ "inserted": {
+ "groupIds": [],
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 81784553,
- "width": 50,
- "x": 0,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id3",
- ],
- "height": 50,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "id1" => Delta {
+ "deleted": {
+ "groupIds": [
+ "id3",
+ ],
+ },
+ "inserted": {
+ "groupIds": [],
+ },
},
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 747212839,
- "width": 50,
- "x": 100,
- "y": 100,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id3",
- ],
- "height": 50,
- "id": "id2",
- "index": "a2",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "id2" => Delta {
+ "deleted": {
+ "groupIds": [
+ "id3",
+ ],
+ },
+ "inserted": {
+ "groupIds": [],
+ },
},
- "seed": 1604849351,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 1723083209,
- "width": 50,
- "x": 200,
- "y": 200,
},
- ],
+ },
},
- {
- "appState": {
- "editingGroupId": "id3",
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- "id2": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "editingGroupId": "id3",
+ "selectedElementIds": {},
+ "selectedGroupIds": {},
+ },
+ "inserted": {
+ "editingGroupId": null,
+ "selectedElementIds": {
+ "id0": true,
+ "id1": true,
+ },
+ "selectedGroupIds": {
+ "id3": true,
+ },
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id3",
- ],
- "height": 50,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 81784553,
- "width": 50,
- "x": 0,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id3",
- ],
- "height": 50,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 747212839,
- "width": 50,
- "x": 100,
- "y": 100,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id3",
- ],
- "height": 50,
- "id": "id2",
- "index": "a2",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1604849351,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 1723083209,
- "width": 50,
- "x": 200,
- "y": 200,
- },
- ],
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": "id3",
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- "id2": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
},
- "selectedGroupIds": {
- "id5": true,
- },
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id3",
- ],
- "height": 50,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 747212839,
- "width": 50,
- "x": 100,
- "y": 100,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id5",
- "id3",
- ],
- "height": 50,
- "id": "id0",
- "index": "a1V",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 6,
- "versionNonce": 1898319239,
- "width": 50,
- "x": 0,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id5",
- "id3",
- ],
- "height": 50,
- "id": "id2",
- "index": "a2",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1604849351,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 5,
- "versionNonce": 1315507081,
- "width": 50,
- "x": 200,
- "y": 200,
- },
- ],
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- "id1": true,
- "id2": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedGroupIds": {
+ "id5": true,
+ },
+ },
+ "inserted": {
+ "selectedGroupIds": {},
+ },
},
- "selectedGroupIds": {
- "id3": true,
- },
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id3",
- ],
- "height": 50,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id0" => Delta {
+ "deleted": {
+ "groupIds": [
+ "id5",
+ "id3",
+ ],
+ "index": "a1V",
+ },
+ "inserted": {
+ "groupIds": [
+ "id3",
+ ],
+ "index": "a0",
+ },
},
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 4,
- "versionNonce": 747212839,
- "width": 50,
- "x": 100,
- "y": 100,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id5",
- "id3",
- ],
- "height": 50,
- "id": "id0",
- "index": "a1V",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "id2" => Delta {
+ "deleted": {
+ "groupIds": [
+ "id5",
+ "id3",
+ ],
+ },
+ "inserted": {
+ "groupIds": [
+ "id3",
+ ],
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 6,
- "versionNonce": 1898319239,
- "width": 50,
- "x": 0,
- "y": 0,
},
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [
- "id5",
- "id3",
- ],
- "height": 50,
- "id": "id2",
- "index": "a2",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "editingGroupId": null,
+ "selectedElementIds": {
+ "id1": true,
+ },
+ "selectedGroupIds": {
+ "id3": true,
+ },
+ },
+ "inserted": {
+ "editingGroupId": "id3",
+ "selectedElementIds": {},
+ "selectedGroupIds": {
+ "id5": true,
+ },
},
- "seed": 1604849351,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 5,
- "versionNonce": 1315507081,
- "width": 50,
- "x": 200,
- "y": 200,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "editingGroupId": "id3",
+ "selectedElementIds": {},
+ "selectedGroupIds": {
+ "id5": true,
+ },
+ },
+ "inserted": {
+ "editingGroupId": null,
+ "selectedElementIds": {
+ "id1": true,
+ },
+ "selectedGroupIds": {
+ "id3": true,
+ },
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "editingGroupId": "id5",
+ "selectedElementIds": {},
+ "selectedGroupIds": {},
+ },
+ "inserted": {
+ "editingGroupId": "id3",
+ "selectedElementIds": {
+ "id2": true,
+ },
+ "selectedGroupIds": {
+ "id5": true,
+ },
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "editingGroupId": null,
+ "selectedElementIds": {
+ "id1": true,
+ "id2": true,
+ },
+ "selectedGroupIds": {
+ "id3": true,
+ },
+ },
+ "inserted": {
+ "editingGroupId": "id5",
+ "selectedElementIds": {},
+ "selectedGroupIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "editingGroupId": "id3",
+ "selectedElementIds": {},
+ "selectedGroupIds": {},
+ },
+ "inserted": {
+ "editingGroupId": null,
+ "selectedElementIds": {
+ "id0": true,
+ "id2": true,
+ },
+ "selectedGroupIds": {
+ "id3": true,
+ },
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
},
],
}
@@ -16815,248 +13128,187 @@ exports[`regression tests > switches from group of selected elements to another
`;
exports[`regression tests > switches from group of selected elements to another element on pointer down > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 0,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
},
- "elements": [],
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 2019559783,
- "width": 10,
- "x": 0,
- "y": 0,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id1" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "ellipse",
+ "width": 100,
+ "x": 110,
+ "y": 110,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id2": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id2" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 100,
+ "index": "a2",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "diamond",
+ "width": 100,
+ "x": 310,
+ "y": 310,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 2019559783,
- "width": 10,
- "x": 0,
- "y": 0,
},
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 100,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 1116226695,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "ellipse",
- "updated": 1,
- "version": 3,
- "versionNonce": 400692809,
- "width": 100,
- "x": 110,
- "y": 110,
- },
- ],
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id2": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 2019559783,
- "width": 10,
- "x": 0,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 100,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 1116226695,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "ellipse",
- "updated": 1,
- "version": 3,
- "versionNonce": 400692809,
- "width": 100,
- "x": 110,
- "y": 110,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 100,
- "id": "id2",
- "index": "a2",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 1505387817,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "diamond",
- "updated": 1,
- "version": 3,
- "versionNonce": 915032327,
- "width": 100,
- "x": 310,
- "y": 310,
- },
- ],
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
},
],
}
@@ -17232,141 +13484,115 @@ exports[`regression tests > switches selected element on pointer down > [end of
`;
exports[`regression tests > switches selected element on pointer down > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 10,
+ "x": 0,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
},
- "elements": [],
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id1" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "ellipse",
+ "width": 10,
+ "x": 20,
+ "y": 20,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 0,
- "y": 0,
},
- ],
- },
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
+ "updated": Map {},
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 10,
- "x": 0,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "ellipse",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 10,
- "x": 20,
- "y": 20,
- },
- ],
},
],
}
@@ -17478,22 +13704,12 @@ exports[`regression tests > two-finger scroll works > [end of test] appState 1`]
`;
exports[`regression tests > two-finger scroll works > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [],
- },
- ],
+ "undoStack": [],
}
`;
@@ -17605,396 +13821,260 @@ exports[`regression tests > undo/redo drawing an element > [end of test] appStat
`;
exports[`regression tests > undo/redo drawing an element > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id2": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedLinearElementId": null,
+ },
+ "inserted": {
+ "selectedLinearElementId": "id2",
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 20,
- "x": 10,
- "y": -10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 30,
- "x": 40,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "endArrowhead": "arrow",
- "endBinding": null,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id2",
- "index": "a2",
- "isDeleted": false,
- "lastCommittedPoint": [
- 100,
- 20,
- ],
- "link": null,
- "locked": false,
- "opacity": 100,
- "points": [
- [
- 0,
- 0,
- ],
- [
- 60,
- 10,
- ],
- [
- 100,
- 20,
- ],
- ],
- "roughness": 1,
- "roundness": {
- "type": 2,
- },
- "seed": 1604849351,
- "startArrowhead": null,
- "startBinding": null,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "arrow",
- "updated": 1,
- "version": 8,
- "versionNonce": 1898319239,
- "width": 100,
- "x": 130,
- "y": 10,
- },
- ],
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {},
+ },
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id2": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {},
+ "inserted": {},
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {},
+ "updated": Map {
+ "id2" => Delta {
+ "deleted": {
+ "height": 10,
+ "lastCommittedPoint": [
+ 60,
+ 10,
+ ],
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 60,
+ 10,
+ ],
+ ],
+ "width": 60,
+ },
+ "inserted": {
+ "height": 20,
+ "lastCommittedPoint": [
+ 100,
+ 20,
+ ],
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 60,
+ 10,
+ ],
+ [
+ 100,
+ 20,
+ ],
+ ],
+ "width": 100,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 20,
- "x": 10,
- "y": -10,
},
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ },
+ },
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
},
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 30,
- "x": 40,
- "y": 0,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "endArrowhead": "arrow",
- "endBinding": null,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id2",
- "index": "a2",
- "isDeleted": false,
- "lastCommittedPoint": [
- 60,
- 10,
- ],
- "link": null,
- "locked": false,
- "opacity": 100,
- "points": [
- [
- 0,
- 0,
- ],
- [
- 60,
- 10,
- ],
- ],
- "roughness": 1,
- "roundness": {
- "type": 2,
+ "inserted": {
+ "selectedElementIds": {
+ "id2": true,
+ },
},
- "seed": 1604849351,
- "startArrowhead": null,
- "startBinding": null,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "arrow",
- "updated": 1,
- "version": 6,
- "versionNonce": 760410951,
- "width": 60,
- "x": 130,
- "y": 10,
},
- ],
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {
+ "id2" => Delta {
+ "deleted": {
+ "isDeleted": true,
+ },
+ "inserted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "endArrowhead": "arrow",
+ "endBinding": null,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a2",
+ "isDeleted": false,
+ "lastCommittedPoint": [
+ 60,
+ 10,
+ ],
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "points": [
+ [
+ 0,
+ 0,
+ ],
+ [
+ 60,
+ 10,
+ ],
+ ],
+ "roughness": 1,
+ "roundness": {
+ "type": 2,
+ },
+ "startArrowhead": null,
+ "startBinding": null,
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "arrow",
+ "width": 60,
+ "x": 130,
+ "y": 10,
+ },
+ },
+ },
+ "removed": Map {},
+ "updated": Map {},
+ },
},
],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
+ "undoStack": [
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {},
+ },
+ },
+ },
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id0" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 10,
+ "index": "a0",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 20,
+ "x": 10,
+ "y": -10,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
+ },
+ },
+ "updated": Map {},
},
- "elements": [],
},
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id0": true,
+ HistoryEntry {
+ "appStateChange": AppStateChange {
+ "delta": Delta {
+ "deleted": {
+ "selectedElementIds": {
+ "id1": true,
+ },
+ },
+ "inserted": {
+ "selectedElementIds": {
+ "id0": true,
+ },
+ },
},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
+ "elementsChange": ElementsChange {
+ "added": Map {},
+ "removed": Map {
+ "id1" => Delta {
+ "deleted": {
+ "angle": 0,
+ "backgroundColor": "transparent",
+ "boundElements": null,
+ "customData": undefined,
+ "fillStyle": "solid",
+ "frameId": null,
+ "groupIds": [],
+ "height": 20,
+ "index": "a1",
+ "isDeleted": false,
+ "link": null,
+ "locked": false,
+ "opacity": 100,
+ "roughness": 1,
+ "roundness": {
+ "type": 3,
+ },
+ "strokeColor": "#1e1e1e",
+ "strokeStyle": "solid",
+ "strokeWidth": 2,
+ "type": "rectangle",
+ "width": 30,
+ "x": 40,
+ "y": 0,
+ },
+ "inserted": {
+ "isDeleted": true,
+ },
},
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 20,
- "x": 10,
- "y": -10,
},
- ],
- },
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {
- "id1": true,
- },
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
+ "updated": Map {},
},
- "elements": [
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 10,
- "id": "id0",
- "index": "a0",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1278240551,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 401146281,
- "width": 20,
- "x": 10,
- "y": -10,
- },
- {
- "angle": 0,
- "backgroundColor": "transparent",
- "boundElements": null,
- "customData": undefined,
- "fillStyle": "solid",
- "frameId": null,
- "groupIds": [],
- "height": 20,
- "id": "id1",
- "index": "a1",
- "isDeleted": false,
- "link": null,
- "locked": false,
- "opacity": 100,
- "roughness": 1,
- "roundness": {
- "type": 3,
- },
- "seed": 1150084233,
- "strokeColor": "#1e1e1e",
- "strokeStyle": "solid",
- "strokeWidth": 2,
- "type": "rectangle",
- "updated": 1,
- "version": 3,
- "versionNonce": 238820263,
- "width": 30,
- "x": 40,
- "y": 0,
- },
- ],
},
],
}
@@ -18002,7 +14082,7 @@ exports[`regression tests > undo/redo drawing an element > [end of test] history
exports[`regression tests > undo/redo drawing an element > [end of test] number of elements 1`] = `0`;
-exports[`regression tests > undo/redo drawing an element > [end of test] number of renders 1`] = `23`;
+exports[`regression tests > undo/redo drawing an element > [end of test] number of renders 1`] = `24`;
exports[`regression tests > updates fontSize & fontFamily appState > [end of test] appState 1`] = `
{
@@ -18106,22 +14186,12 @@ exports[`regression tests > updates fontSize & fontFamily appState > [end of tes
`;
exports[`regression tests > updates fontSize & fontFamily appState > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [],
- },
- ],
+ "undoStack": [],
}
`;
@@ -18234,22 +14304,12 @@ exports[`regression tests > zoom hotkeys > [end of test] appState 1`] = `
`;
exports[`regression tests > zoom hotkeys > [end of test] history 1`] = `
-{
- "recording": false,
+History {
+ "onHistoryChangedEmitter": Emitter {
+ "subscribers": [],
+ },
"redoStack": [],
- "stateHistory": [
- {
- "appState": {
- "editingGroupId": null,
- "editingLinearElement": null,
- "name": "Untitled-201933152653",
- "selectedElementIds": {},
- "selectedGroupIds": {},
- "viewBackgroundColor": "#ffffff",
- },
- "elements": [],
- },
- ],
+ "undoStack": [],
}
`;
diff --git a/packages/excalidraw/tests/contextmenu.test.tsx b/packages/excalidraw/tests/contextmenu.test.tsx
index 643cedcfbe..a76e14997b 100644
--- a/packages/excalidraw/tests/contextmenu.test.tsx
+++ b/packages/excalidraw/tests/contextmenu.test.tsx
@@ -27,7 +27,7 @@ const checkpoint = (name: string) => {
`[${name}] number of renders`,
);
expect(h.state).toMatchSnapshot(`[${name}] appState`);
- expect(h.history.getSnapshotForTest()).toMatchSnapshot(`[${name}] history`);
+ expect(h.history).toMatchSnapshot(`[${name}] history`);
expect(h.elements.length).toMatchSnapshot(`[${name}] number of elements`);
h.elements.forEach((element, i) =>
expect(element).toMatchSnapshot(`[${name}] element ${i}`),
diff --git a/packages/excalidraw/tests/helpers/api.ts b/packages/excalidraw/tests/helpers/api.ts
index 28d14b8b10..4b54fad591 100644
--- a/packages/excalidraw/tests/helpers/api.ts
+++ b/packages/excalidraw/tests/helpers/api.ts
@@ -69,9 +69,18 @@ export class API {
return selectedElements[0];
};
- static getStateHistory = () => {
+ static getUndoStack = () => {
// @ts-ignore
- return h.history.stateHistory;
+ return h.history.undoStack;
+ };
+
+ static getRedoStack = () => {
+ // @ts-ignore
+ return h.history.redoStack;
+ };
+
+ static getSnapshot = () => {
+ return Array.from(h.store.snapshot.elements.values());
};
static clearSelection = () => {
diff --git a/packages/excalidraw/tests/helpers/ui.ts b/packages/excalidraw/tests/helpers/ui.ts
index ec0a743536..542434e789 100644
--- a/packages/excalidraw/tests/helpers/ui.ts
+++ b/packages/excalidraw/tests/helpers/ui.ts
@@ -113,6 +113,18 @@ export class Keyboard {
Keyboard.codeDown(code);
Keyboard.codeUp(code);
};
+
+ static undo = () => {
+ Keyboard.withModifierKeys({ ctrl: true }, () => {
+ Keyboard.keyPress("z");
+ });
+ };
+
+ static redo = () => {
+ Keyboard.withModifierKeys({ ctrl: true, shift: true }, () => {
+ Keyboard.keyPress("z");
+ });
+ };
}
const getElementPointForSelection = (element: ExcalidrawElement): Point => {
diff --git a/packages/excalidraw/tests/history.test.tsx b/packages/excalidraw/tests/history.test.tsx
index 677fa6b4f0..165cc8c0f3 100644
--- a/packages/excalidraw/tests/history.test.tsx
+++ b/packages/excalidraw/tests/history.test.tsx
@@ -1,192 +1,4507 @@
-import { assertSelectedElements, render } from "./test-utils";
+import * as StaticScene from "../renderer/staticScene";
+import {
+ GlobalTestState,
+ act,
+ assertSelectedElements,
+ render,
+ togglePopover,
+} from "./test-utils";
import { Excalidraw } from "../index";
import { Keyboard, Pointer, UI } from "./helpers/ui";
import { API } from "./helpers/api";
import { getDefaultAppState } from "../appState";
-import { waitFor } from "@testing-library/react";
+import { fireEvent, waitFor } from "@testing-library/react";
import { createUndoAction, createRedoAction } from "../actions/actionHistory";
import { EXPORT_DATA_TYPES, MIME_TYPES } from "../constants";
+import { AppState, ExcalidrawImperativeAPI } from "../types";
+import { arrayToMap, resolvablePromise } from "../utils";
+import { COLOR_PALETTE } from "../colors";
+import { KEYS } from "../keys";
+import { newElementWith } from "../element/mutateElement";
+import {
+ ExcalidrawFrameElement,
+ ExcalidrawGenericElement,
+ ExcalidrawLinearElement,
+ ExcalidrawTextElement,
+ FractionalIndex,
+ SceneElementsMap,
+} from "../element/types";
+import {
+ actionSendBackward,
+ actionBringForward,
+ actionSendToBack,
+} from "../actions";
+import { vi } from "vitest";
+import { queryByText } from "@testing-library/react";
+import { HistoryEntry } from "../history";
+import { AppStateChange, ElementsChange } from "../change";
+import { Snapshot } from "../store";
const { h } = window;
const mouse = new Pointer("mouse");
+const checkpoint = (name: string) => {
+ expect(renderStaticScene.mock.calls.length).toMatchSnapshot(
+ `[${name}] number of renders`,
+ );
+
+ // `scrolledOutside` does not appear to be stable between test runs
+ // `selectedLinearElemnt` includes `startBindingElement` containing seed and versionNonce
+ const {
+ name: _,
+ scrolledOutside,
+ selectedLinearElement,
+ ...strippedAppState
+ } = h.state;
+ expect(strippedAppState).toMatchSnapshot(`[${name}] appState`);
+ expect(h.history).toMatchSnapshot(`[${name}] history`);
+ expect(h.elements.length).toMatchSnapshot(`[${name}] number of elements`);
+ h.elements
+ .map(({ seed, versionNonce, ...strippedElement }) => strippedElement)
+ .forEach((element, i) =>
+ expect(element).toMatchSnapshot(`[${name}] element ${i}`),
+ );
+};
+
+const renderStaticScene = vi.spyOn(StaticScene, "renderStaticScene");
+
+const transparent = COLOR_PALETTE.transparent;
+const red = COLOR_PALETTE.red[1];
+const blue = COLOR_PALETTE.blue[1];
+const yellow = COLOR_PALETTE.yellow[1];
+const violet = COLOR_PALETTE.violet[1];
+
describe("history", () => {
- it("initializing scene should end up with single history entry", async () => {
- await render(
- ,
- );
-
- await waitFor(() => expect(h.state.zenModeEnabled).toBe(true));
- await waitFor(() =>
- expect(h.elements).toEqual([expect.objectContaining({ id: "A" })]),
- );
- const undoAction = createUndoAction(h.history);
- const redoAction = createRedoAction(h.history);
- h.app.actionManager.executeAction(undoAction);
- expect(h.elements).toEqual([
- expect.objectContaining({ id: "A", isDeleted: false }),
- ]);
- const rectangle = UI.createElement("rectangle");
- expect(h.elements).toEqual([
- expect.objectContaining({ id: "A" }),
- expect.objectContaining({ id: rectangle.id }),
- ]);
- h.app.actionManager.executeAction(undoAction);
- expect(h.elements).toEqual([
- expect.objectContaining({ id: "A", isDeleted: false }),
- expect.objectContaining({ id: rectangle.id, isDeleted: true }),
- ]);
-
- // noop
- h.app.actionManager.executeAction(undoAction);
- expect(h.elements).toEqual([
- expect.objectContaining({ id: "A", isDeleted: false }),
- expect.objectContaining({ id: rectangle.id, isDeleted: true }),
- ]);
- expect(API.getStateHistory().length).toBe(1);
-
- h.app.actionManager.executeAction(redoAction);
- expect(h.elements).toEqual([
- expect.objectContaining({ id: "A", isDeleted: false }),
- expect.objectContaining({ id: rectangle.id, isDeleted: false }),
- ]);
- expect(API.getStateHistory().length).toBe(2);
+ beforeEach(() => {
+ renderStaticScene.mockClear();
});
- it("scene import via drag&drop should create new history entry", async () => {
- await render(
- ,
- );
+ afterEach(() => {
+ checkpoint("end of test");
+ });
- await waitFor(() => expect(h.state.viewBackgroundColor).toBe("#FFF"));
- await waitFor(() =>
- expect(h.elements).toEqual([expect.objectContaining({ id: "A" })]),
- );
+ describe("singleplayer undo/redo", () => {
+ it("should not collapse when applying corrupted history entry", async () => {
+ await render();
+ const rect = API.createElement({ type: "rectangle" });
- API.drop(
- new Blob(
- [
- JSON.stringify({
- type: EXPORT_DATA_TYPES.excalidraw,
+ h.elements = [rect];
+
+ const corrupedEntry = HistoryEntry.create(
+ AppStateChange.empty(),
+ ElementsChange.empty(),
+ );
+
+ vi.spyOn(corrupedEntry, "applyTo").mockImplementation(() => {
+ throw new Error("Oh no, I am corrupted!");
+ });
+
+ (h.history as any).undoStack.push(corrupedEntry);
+
+ const appState = getDefaultAppState() as AppState;
+
+ try {
+ // due to this we unfortunately we couldn't do simple .toThrow()
+ act(
+ () =>
+ h.history.undo(
+ arrayToMap(h.elements) as SceneElementsMap,
+ appState,
+ Snapshot.empty(),
+ ) as any,
+ );
+ } catch (e) {
+ expect(e).toBeInstanceOf(Error);
+ }
+ // we popped the entry, even though it is corrupted, so the user could perform subsequent undo/redo and would not be stuck on this entry forever
+ expect(API.getUndoStack().length).toBe(0);
+ // we pushed the entr, as we don't want just lose it and throw it away - it might be perfectly valid on subsequent redo
+ expect(API.getRedoStack().length).toBe(1);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect.id, isDeleted: false }), // no changes detected
+ ]);
+
+ try {
+ // due to this we unfortunately we couldn't do simple .toThrow()
+ act(
+ () =>
+ h.history.redo(
+ arrayToMap(h.elements) as SceneElementsMap,
+ appState,
+ Snapshot.empty(),
+ ) as any,
+ );
+ } catch (e) {
+ expect(e).toBeInstanceOf(Error);
+ }
+ expect(API.getUndoStack().length).toBe(1); // vice versa for redo
+ expect(API.getRedoStack().length).toBe(0); // vice versa for undo
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect.id, isDeleted: false }),
+ ]);
+ });
+
+ it("should not end up with history entry when there are no appstate changes", async () => {
+ await render();
+ const rect1 = API.createElement({ type: "rectangle", groupIds: ["A"] });
+ const rect2 = API.createElement({ type: "rectangle", groupIds: ["A"] });
+
+ h.elements = [rect1, rect2];
+ mouse.select(rect1);
+ assertSelectedElements([rect1, rect2]);
+ expect(h.state.selectedGroupIds).toEqual({ A: true });
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(0);
+
+ mouse.select(rect2);
+ assertSelectedElements([rect1, rect2]);
+ expect(h.state.selectedGroupIds).toEqual({ A: true });
+ expect(API.getUndoStack().length).toBe(1); // no new entry was created
+ expect(API.getRedoStack().length).toBe(0);
+ });
+
+ it("should not end up with history entry when there are no elements changes", async () => {
+ const excalidrawAPIPromise = resolvablePromise();
+ await render(
+ excalidrawAPIPromise.resolve(api as any)}
+ handleKeyboardGlobally={true}
+ />,
+ );
+ const excalidrawAPI = await excalidrawAPIPromise;
+
+ const rect1 = API.createElement({ type: "rectangle" });
+ const rect2 = API.createElement({ type: "rectangle" });
+
+ excalidrawAPI.updateScene({
+ elements: [rect1, rect2],
+ commitToStore: true,
+ });
+
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect1.id, isDeleted: false }),
+ expect.objectContaining({ id: rect2.id, isDeleted: false }),
+ ]);
+
+ excalidrawAPI.updateScene({
+ elements: [rect1, rect2],
+ commitToStore: true, // even though the flag is on, same elements are passed, nothing to commit
+ });
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect1.id, isDeleted: false }),
+ expect.objectContaining({ id: rect2.id, isDeleted: false }),
+ ]);
+ });
+
+ it("should not clear the redo stack on standalone appstate change", async () => {
+ await render();
+
+ const rect1 = UI.createElement("rectangle", { x: 10 });
+ const rect2 = UI.createElement("rectangle", { x: 20 });
+
+ expect(API.getUndoStack().length).toBe(2);
+ expect(API.getRedoStack().length).toBe(0);
+ assertSelectedElements(rect2);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect1.id, isDeleted: false }),
+ expect.objectContaining({ id: rect2.id, isDeleted: false }),
+ ]);
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(1);
+ assertSelectedElements(rect1);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect1.id, isDeleted: false }),
+ expect.objectContaining({ id: rect2.id, isDeleted: true }),
+ ]);
+
+ mouse.clickAt(-10, -10);
+ expect(API.getUndoStack().length).toBe(2);
+ expect(API.getRedoStack().length).toBe(1); // we still have a possibility to redo!
+ expect(API.getSelectedElements().length).toBe(0);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect1.id, isDeleted: false }),
+ expect.objectContaining({ id: rect2.id, isDeleted: true }),
+ ]);
+
+ mouse.downAt(0, 0);
+ mouse.moveTo(50, 50);
+ mouse.upAt(50, 50);
+ expect(API.getUndoStack().length).toBe(3);
+ expect(API.getRedoStack().length).toBe(1); // even after re-select!
+ assertSelectedElements(rect1);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect1.id, isDeleted: false }),
+ expect.objectContaining({ id: rect2.id, isDeleted: true }),
+ ]);
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(4);
+ expect(API.getRedoStack().length).toBe(0);
+ assertSelectedElements(rect2);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect1.id, isDeleted: false }),
+ expect.objectContaining({ id: rect2.id, isDeleted: false }),
+ ]);
+ });
+
+ it("should not override appstate changes when redo stack is not cleared", async () => {
+ await render();
+
+ const rect = UI.createElement("rectangle", { x: 10 });
+ togglePopover("Background");
+ UI.clickOnTestId("color-red");
+ UI.clickOnTestId("color-blue");
+
+ expect(API.getUndoStack().length).toBe(3);
+ expect(API.getRedoStack().length).toBe(0);
+ assertSelectedElements(rect);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect.id, backgroundColor: blue }),
+ ]);
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(2);
+ expect(API.getRedoStack().length).toBe(1);
+ assertSelectedElements(rect);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect.id, backgroundColor: red }),
+ ]);
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(2);
+ assertSelectedElements(rect);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect.id, backgroundColor: transparent }),
+ ]);
+
+ mouse.clickAt(-10, -10);
+ expect(API.getUndoStack().length).toBe(2); // pushed appstate change,
+ expect(API.getRedoStack().length).toBe(2); // redo stack is not cleared
+ expect(API.getSelectedElements().length).toBe(0);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect.id, backgroundColor: transparent }),
+ ]);
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(3);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(API.getSelectedElements().length).toBe(0); // previously the item was selected, not it is not
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect.id, backgroundColor: red }),
+ ]);
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(4);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(API.getSelectedElements().length).toBe(0); // previously the item was selected, not it is not
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect.id, backgroundColor: blue }),
+ ]);
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(3);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(API.getSelectedElements().length).toBe(0); // previously the item was selected, not it is not
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect.id, backgroundColor: red }),
+ ]);
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(2);
+ expect(API.getRedoStack().length).toBe(2);
+ expect(API.getSelectedElements().length).toBe(0);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect.id, backgroundColor: transparent }),
+ ]);
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(3);
+ assertSelectedElements(rect); // get's reselected with out pushed entry!
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect.id, backgroundColor: transparent }),
+ ]);
+ });
+
+ it("should clear the redo stack on elements change", async () => {
+ await render();
+
+ const rect1 = UI.createElement("rectangle", { x: 10 });
+
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(0);
+ assertSelectedElements(rect1);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect1.id, isDeleted: false }),
+ ]);
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(0);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(API.getSelectedElements()).toEqual([]);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect1.id, isDeleted: true }),
+ ]);
+
+ const rect2 = UI.createElement("rectangle", { x: 20 });
+
+ assertSelectedElements(rect2);
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(0); // redo stack got cleared
+ expect(API.getSnapshot()).toEqual([
+ expect.objectContaining({ id: rect1.id, isDeleted: true }),
+ expect.objectContaining({ id: rect2.id, isDeleted: false }),
+ ]);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect1.id, isDeleted: true }),
+ expect.objectContaining({ id: rect2.id, isDeleted: false }),
+ ]);
+ });
+
+ it("should iterate through the history when selection changes do not produce visible change", async () => {
+ await render();
+
+ const rect = UI.createElement("rectangle", { x: 10 });
+
+ mouse.clickAt(-10, -10);
+ expect(API.getUndoStack().length).toBe(2);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(API.getSelectedElements().length).toBe(0);
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(1);
+ assertSelectedElements(rect);
+
+ mouse.clickAt(-10, -10);
+ expect(API.getUndoStack().length).toBe(2);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(API.getSelectedElements().length).toBe(0);
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(2); // now we have two same redos
+ assertSelectedElements(rect);
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(2);
+ expect(API.getRedoStack().length).toBe(1); // didn't iterate through completely, as first redo already results in a visible change
+ expect(API.getSelectedElements().length).toBe(0);
+
+ Keyboard.redo(); // acceptable empty redo
+ expect(API.getUndoStack().length).toBe(3);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(API.getSelectedElements().length).toBe(0);
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(2);
+ expect(API.getRedoStack().length).toBe(1);
+ assertSelectedElements(rect);
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(0); // now we iterated through the same undos!
+ expect(API.getRedoStack().length).toBe(3);
+ expect(API.getSelectedElements().length).toBe(0);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect.id, isDeleted: true }),
+ ]);
+ });
+
+ it("should end up with no history entry after initializing scene", async () => {
+ await render(
+ ,
+ );
- await waitFor(() => expect(API.getStateHistory().length).toBe(2));
- expect(h.state.viewBackgroundColor).toBe("#000");
- expect(h.elements).toEqual([
- expect.objectContaining({ id: "B", isDeleted: false }),
- ]);
+ await waitFor(() => {
+ expect(h.state.zenModeEnabled).toBe(true);
+ expect(h.elements).toEqual([expect.objectContaining({ id: "A" })]);
+ expect(h.history.isUndoStackEmpty).toBeTruthy();
+ });
- const undoAction = createUndoAction(h.history);
- const redoAction = createRedoAction(h.history);
- h.app.actionManager.executeAction(undoAction);
- expect(h.elements).toEqual([
- expect.objectContaining({ id: "A", isDeleted: false }),
- expect.objectContaining({ id: "B", isDeleted: true }),
- ]);
- expect(h.state.viewBackgroundColor).toBe("#FFF");
- h.app.actionManager.executeAction(redoAction);
- expect(h.state.viewBackgroundColor).toBe("#000");
- expect(h.elements).toEqual([
- expect.objectContaining({ id: "B", isDeleted: false }),
- expect.objectContaining({ id: "A", isDeleted: true }),
- ]);
- });
+ const undoAction = createUndoAction(h.history, h.store);
+ const redoAction = createRedoAction(h.history, h.store);
+ // noop
+ act(() => h.app.actionManager.executeAction(undoAction));
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: "A", isDeleted: false }),
+ ]);
+ const rectangle = UI.createElement("rectangle");
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: "A" }),
+ expect.objectContaining({ id: rectangle.id }),
+ ]);
+ act(() => h.app.actionManager.executeAction(undoAction));
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: "A", isDeleted: false }),
+ expect.objectContaining({ id: rectangle.id, isDeleted: true }),
+ ]);
- it("undo/redo works properly with groups", async () => {
- await render();
- const rect1 = API.createElement({ type: "rectangle", groupIds: ["A"] });
- const rect2 = API.createElement({ type: "rectangle", groupIds: ["A"] });
+ // noop
+ act(() => h.app.actionManager.executeAction(undoAction));
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: "A", isDeleted: false }),
+ expect.objectContaining({ id: rectangle.id, isDeleted: true }),
+ ]);
+ expect(API.getUndoStack().length).toBe(0);
- h.elements = [rect1, rect2];
- mouse.select(rect1);
- assertSelectedElements([rect1, rect2]);
- expect(h.state.selectedGroupIds).toEqual({ A: true });
-
- Keyboard.withModifierKeys({ ctrl: true }, () => {
- Keyboard.keyPress("d");
+ act(() => h.app.actionManager.executeAction(redoAction));
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: "A", isDeleted: false }),
+ expect.objectContaining({ id: rectangle.id, isDeleted: false }),
+ ]);
+ expect(API.getUndoStack().length).toBe(1);
});
- expect(h.elements.length).toBe(4);
- assertSelectedElements([h.elements[2], h.elements[3]]);
- expect(h.state.selectedGroupIds).not.toEqual(
- expect.objectContaining({ A: true }),
- );
- Keyboard.withModifierKeys({ ctrl: true }, () => {
- Keyboard.keyPress("z");
+ it("should create new history entry on scene import via drag&drop", async () => {
+ await render(
+ ,
+ );
+
+ await waitFor(() => expect(h.state.viewBackgroundColor).toBe("#FFF"));
+ await waitFor(() =>
+ expect(h.elements).toEqual([expect.objectContaining({ id: "A" })]),
+ );
+
+ API.drop(
+ new Blob(
+ [
+ JSON.stringify({
+ type: EXPORT_DATA_TYPES.excalidraw,
+ appState: {
+ ...getDefaultAppState(),
+ viewBackgroundColor: "#000",
+ },
+ elements: [API.createElement({ type: "rectangle", id: "B" })],
+ }),
+ ],
+ { type: MIME_TYPES.json },
+ ),
+ );
+
+ await waitFor(() => expect(API.getUndoStack().length).toBe(1));
+ expect(h.state.viewBackgroundColor).toBe("#000");
+ expect(API.getSnapshot()).toEqual([
+ expect.objectContaining({ id: "A", isDeleted: true }),
+ expect.objectContaining({ id: "B", isDeleted: false }),
+ ]);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: "B", isDeleted: false }),
+ ]);
+
+ const undoAction = createUndoAction(h.history, h.store);
+ const redoAction = createRedoAction(h.history, h.store);
+ act(() => h.app.actionManager.executeAction(undoAction));
+
+ expect(API.getSnapshot()).toEqual([
+ expect.objectContaining({ id: "A", isDeleted: false }),
+ expect.objectContaining({ id: "B", isDeleted: true }),
+ ]);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: "A", isDeleted: false }),
+ expect.objectContaining({ id: "B", isDeleted: true }),
+ ]);
+ expect(h.state.viewBackgroundColor).toBe("#FFF");
+
+ act(() => h.app.actionManager.executeAction(redoAction));
+ expect(h.state.viewBackgroundColor).toBe("#000");
+ expect(API.getSnapshot()).toEqual([
+ expect.objectContaining({ id: "A", isDeleted: true }),
+ expect.objectContaining({ id: "B", isDeleted: false }),
+ ]);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: "A", isDeleted: true }),
+ expect.objectContaining({ id: "B", isDeleted: false }),
+ ]);
});
- expect(h.elements.length).toBe(4);
- expect(h.elements).toEqual([
- expect.objectContaining({ id: rect1.id, isDeleted: false }),
- expect.objectContaining({ id: rect2.id, isDeleted: false }),
- expect.objectContaining({ id: `${rect1.id}_copy`, isDeleted: true }),
- expect.objectContaining({ id: `${rect2.id}_copy`, isDeleted: true }),
- ]);
- expect(h.state.selectedGroupIds).toEqual({ A: true });
- Keyboard.withModifierKeys({ ctrl: true, shift: true }, () => {
- Keyboard.keyPress("z");
+ it("should support appstate name or viewBackgroundColor change", async () => {
+ const excalidrawAPIPromise = resolvablePromise();
+ await render(
+ excalidrawAPIPromise.resolve(api as any)}
+ handleKeyboardGlobally={true}
+ initialData={{
+ appState: {
+ name: "Old name",
+ viewBackgroundColor: "#FFF",
+ },
+ }}
+ />,
+ );
+ const excalidrawAPI = await excalidrawAPIPromise;
+
+ excalidrawAPI.updateScene({
+ appState: {
+ name: "New name",
+ },
+ commitToStore: true,
+ });
+
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.state.name).toBe("New name");
+
+ excalidrawAPI.updateScene({
+ appState: {
+ viewBackgroundColor: "#000",
+ },
+ commitToStore: true,
+ });
+ expect(API.getUndoStack().length).toBe(2);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.state.name).toBe("New name");
+ expect(h.state.viewBackgroundColor).toBe("#000");
+
+ // just to double check that same change is not recorded
+ excalidrawAPI.updateScene({
+ appState: {
+ name: "New name",
+ viewBackgroundColor: "#000",
+ },
+ commitToStore: true,
+ });
+ expect(API.getUndoStack().length).toBe(2);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.state.name).toBe("New name");
+ expect(h.state.viewBackgroundColor).toBe("#000");
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(h.state.name).toBe("New name");
+ expect(h.state.viewBackgroundColor).toBe("#FFF");
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(0);
+ expect(API.getRedoStack().length).toBe(2);
+ expect(h.state.name).toBe("Old name");
+ expect(h.state.viewBackgroundColor).toBe("#FFF");
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(h.state.name).toBe("New name");
+ expect(h.state.viewBackgroundColor).toBe("#FFF");
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(2);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.state.name).toBe("New name");
+ expect(h.state.viewBackgroundColor).toBe("#000");
});
- expect(h.elements.length).toBe(4);
- expect(h.elements).toEqual([
- expect.objectContaining({ id: rect1.id, isDeleted: false }),
- expect.objectContaining({ id: rect2.id, isDeleted: false }),
- expect.objectContaining({ id: `${rect1.id}_copy`, isDeleted: false }),
- expect.objectContaining({ id: `${rect2.id}_copy`, isDeleted: false }),
- ]);
- expect(h.state.selectedGroupIds).not.toEqual(
- expect.objectContaining({ A: true }),
- );
- // undo again, and duplicate once more
- // -------------------------------------------------------------------------
+ it("should support element creation, deletion and appstate element selection change", async () => {
+ await render();
- Keyboard.withModifierKeys({ ctrl: true }, () => {
- Keyboard.keyPress("z");
- Keyboard.keyPress("d");
+ const rect1 = UI.createElement("rectangle", { x: 10 });
+ const rect2 = UI.createElement("rectangle", { x: 20, y: 20 });
+ const rect3 = UI.createElement("rectangle", { x: 40, y: 40 });
+
+ mouse.select([rect2, rect3]);
+ Keyboard.keyDown(KEYS.DELETE);
+
+ expect(API.getUndoStack().length).toBe(6);
+
+ Keyboard.undo();
+ assertSelectedElements(rect2, rect3);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect1.id }),
+ expect.objectContaining({ id: rect2.id, isDeleted: false }),
+ expect.objectContaining({ id: rect3.id, isDeleted: false }),
+ ]);
+
+ Keyboard.undo();
+ assertSelectedElements(rect2);
+
+ Keyboard.undo();
+ assertSelectedElements(rect3);
+
+ Keyboard.undo();
+ assertSelectedElements(rect2);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect1.id }),
+ expect.objectContaining({ id: rect2.id }),
+ expect.objectContaining({ id: rect3.id, isDeleted: true }),
+ ]);
+
+ Keyboard.undo();
+ assertSelectedElements(rect1);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect1.id }),
+ expect.objectContaining({ id: rect2.id, isDeleted: true }),
+ expect.objectContaining({ id: rect3.id, isDeleted: true }),
+ ]);
+
+ Keyboard.undo();
+ assertSelectedElements();
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect1.id, isDeleted: true }),
+ expect.objectContaining({ id: rect2.id, isDeleted: true }),
+ expect.objectContaining({ id: rect3.id, isDeleted: true }),
+ ]);
+
+ // no-op
+ Keyboard.undo();
+ assertSelectedElements();
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect1.id, isDeleted: true }),
+ expect.objectContaining({ id: rect2.id, isDeleted: true }),
+ expect.objectContaining({ id: rect3.id, isDeleted: true }),
+ ]);
+
+ Keyboard.redo();
+ assertSelectedElements(rect1);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect1.id }),
+ expect.objectContaining({ id: rect2.id, isDeleted: true }),
+ expect.objectContaining({ id: rect3.id, isDeleted: true }),
+ ]);
+
+ Keyboard.redo();
+ assertSelectedElements(rect2);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect1.id }),
+ expect.objectContaining({ id: rect2.id }),
+ expect.objectContaining({ id: rect3.id, isDeleted: true }),
+ ]);
+
+ Keyboard.redo();
+ assertSelectedElements(rect3);
+
+ Keyboard.redo();
+ assertSelectedElements(rect2);
+
+ Keyboard.redo();
+ assertSelectedElements(rect2, rect3);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect1.id }),
+ expect.objectContaining({ id: rect2.id, isDeleted: false }),
+ expect.objectContaining({ id: rect3.id, isDeleted: false }),
+ ]);
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(6);
+ expect(API.getRedoStack().length).toBe(0);
+ assertSelectedElements();
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect1.id, isDeleted: false }),
+ expect.objectContaining({ id: rect2.id, isDeleted: true }),
+ expect.objectContaining({ id: rect3.id, isDeleted: true }),
+ ]);
+
+ // no-op
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(6);
+ expect(API.getRedoStack().length).toBe(0);
+ assertSelectedElements();
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect1.id, isDeleted: false }),
+ expect.objectContaining({ id: rect2.id, isDeleted: true }),
+ expect.objectContaining({ id: rect3.id, isDeleted: true }),
+ ]);
});
- expect(h.elements.length).toBe(6);
- expect(h.elements).toEqual(
- expect.arrayContaining([
+
+ it("should support linear element creation and points manipulation through the editor", async () => {
+ await render();
+
+ // create three point arrow
+ UI.clickTool("arrow");
+ mouse.click(0, 0);
+ mouse.click(10, 10);
+ mouse.click(10, -10);
+
+ // actionFinalize
+ Keyboard.keyPress(KEYS.ENTER);
+
+ // open editor
+ Keyboard.withModifierKeys({ ctrl: true }, () => {
+ Keyboard.keyPress(KEYS.ENTER);
+ });
+
+ // move point
+ mouse.downAt(20, 0);
+ mouse.moveTo(20, 20);
+ mouse.up();
+
+ // leave editor
+ Keyboard.keyPress(KEYS.ESCAPE);
+
+ expect(API.getUndoStack().length).toBe(6);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(assertSelectedElements(h.elements[0]));
+ expect(h.state.editingLinearElement).toBeNull();
+ expect(h.state.selectedLinearElement).toBeNull();
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ isDeleted: false,
+ points: [
+ [0, 0],
+ [10, 10],
+ [20, 20],
+ ],
+ }),
+ ]);
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(5);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(assertSelectedElements(h.elements[0]));
+ expect(h.state.editingLinearElement?.elementId).toBe(h.elements[0].id);
+ expect(h.state.selectedLinearElement?.elementId).toBe(h.elements[0].id);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ isDeleted: false,
+ points: [
+ [0, 0],
+ [10, 10],
+ [20, 20],
+ ],
+ }),
+ ]);
+
+ // making sure clicking on points in the editor does not generate new history entries!
+ mouse.clickAt(0, 0);
+ mouse.clickAt(10, 10);
+ mouse.clickAt(20, 20);
+ expect(API.getUndoStack().length).toBe(5);
+ expect(API.getRedoStack().length).toBe(1);
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(4);
+ expect(API.getRedoStack().length).toBe(2);
+ expect(assertSelectedElements(h.elements[0]));
+ expect(h.state.editingLinearElement?.elementId).toBe(h.elements[0].id);
+ expect(h.state.selectedLinearElement?.elementId).toBe(h.elements[0].id);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ isDeleted: false,
+ points: [
+ [0, 0],
+ [10, 10],
+ [20, 0],
+ ],
+ }),
+ ]);
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(3);
+ expect(API.getRedoStack().length).toBe(3);
+ expect(assertSelectedElements(h.elements[0]));
+ expect(h.state.editingLinearElement).toBeNull(); // undo `open editor`
+ expect(h.state.selectedLinearElement?.elementId).toBe(h.elements[0].id);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ isDeleted: false,
+ points: [
+ [0, 0],
+ [10, 10],
+ [20, 0],
+ ],
+ }),
+ ]);
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(2);
+ expect(API.getRedoStack().length).toBe(4);
+ expect(assertSelectedElements(h.elements[0]));
+ expect(h.state.editingLinearElement).toBeNull();
+ expect(h.state.selectedLinearElement).toBeNull(); // undo `actionFinalize`
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ isDeleted: false,
+ points: [
+ [0, 0],
+ [10, 10],
+ [20, 0],
+ ],
+ }),
+ ]);
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(5);
+ expect(assertSelectedElements(h.elements[0]));
+ expect(h.state.editingLinearElement).toBeNull();
+ expect(h.state.selectedLinearElement).toBeNull();
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ isDeleted: false,
+ points: [
+ [0, 0],
+ [10, 10],
+ ],
+ }),
+ ]);
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(0);
+ expect(API.getRedoStack().length).toBe(6);
+ expect(API.getSelectedElements().length).toBe(0);
+ expect(h.state.editingLinearElement).toBeNull();
+ expect(h.state.selectedLinearElement).toBeNull();
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ isDeleted: true,
+ points: [
+ [0, 0],
+ [10, 10],
+ ],
+ }),
+ ]);
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(5);
+ expect(assertSelectedElements(h.elements[0]));
+ expect(h.state.editingLinearElement).toBeNull();
+ expect(h.state.selectedLinearElement).toBeNull();
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ isDeleted: false,
+ points: [
+ [0, 0],
+ [10, 10],
+ ],
+ }),
+ ]);
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(2);
+ expect(API.getRedoStack().length).toBe(4);
+ expect(assertSelectedElements(h.elements[0]));
+ expect(h.state.editingLinearElement).toBeNull();
+ expect(h.state.selectedLinearElement).toBeNull(); // undo `actionFinalize`
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ isDeleted: false,
+ points: [
+ [0, 0],
+ [10, 10],
+ [20, 0],
+ ],
+ }),
+ ]);
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(3);
+ expect(API.getRedoStack().length).toBe(3);
+ expect(assertSelectedElements(h.elements[0]));
+ expect(h.state.editingLinearElement).toBeNull(); // undo `open editor`
+ expect(h.state.selectedLinearElement?.elementId).toBe(h.elements[0].id);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ isDeleted: false,
+ points: [
+ [0, 0],
+ [10, 10],
+ [20, 0],
+ ],
+ }),
+ ]);
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(4);
+ expect(API.getRedoStack().length).toBe(2);
+ expect(assertSelectedElements(h.elements[0]));
+ expect(h.state.editingLinearElement?.elementId).toBe(h.elements[0].id);
+ expect(h.state.selectedLinearElement?.elementId).toBe(h.elements[0].id);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ isDeleted: false,
+ points: [
+ [0, 0],
+ [10, 10],
+ [20, 0],
+ ],
+ }),
+ ]);
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(5);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(assertSelectedElements(h.elements[0]));
+ expect(h.state.editingLinearElement?.elementId).toBe(h.elements[0].id);
+ expect(h.state.selectedLinearElement?.elementId).toBe(h.elements[0].id);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ isDeleted: false,
+ points: [
+ [0, 0],
+ [10, 10],
+ [20, 20],
+ ],
+ }),
+ ]);
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(6);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(assertSelectedElements(h.elements[0]));
+ expect(h.state.editingLinearElement).toBeNull();
+ expect(h.state.selectedLinearElement).toBeNull();
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ isDeleted: false,
+ points: [
+ [0, 0],
+ [10, 10],
+ [20, 20],
+ ],
+ }),
+ ]);
+ });
+
+ it("should support duplication of groups, appstate group selection and editing group", async () => {
+ await render();
+ const rect1 = API.createElement({
+ type: "rectangle",
+ groupIds: ["A"],
+ x: 0,
+ });
+ const rect2 = API.createElement({
+ type: "rectangle",
+ groupIds: ["A"],
+ x: 100,
+ });
+
+ h.elements = [rect1, rect2];
+ mouse.select(rect1);
+ assertSelectedElements([rect1, rect2]);
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.state.editingGroupId).toBeNull();
+ expect(h.state.selectedGroupIds).toEqual({ A: true });
+
+ // inside the editing group
+ mouse.doubleClickOn(rect2);
+ assertSelectedElements([rect2]);
+ expect(API.getUndoStack().length).toBe(2);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.state.editingGroupId).toBe("A");
+ expect(h.state.selectedGroupIds).not.toEqual({ A: true });
+
+ mouse.clickOn(rect1);
+ assertSelectedElements([rect1]);
+ expect(API.getUndoStack().length).toBe(3);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.state.editingGroupId).toBe("A");
+ expect(h.state.selectedGroupIds).not.toEqual({ A: true });
+
+ Keyboard.undo();
+ assertSelectedElements([rect2]);
+ expect(API.getUndoStack().length).toBe(2);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(h.state.editingGroupId).toBe("A");
+ expect(h.state.selectedGroupIds).not.toEqual({ A: true });
+
+ Keyboard.undo();
+ assertSelectedElements([rect1, rect2]);
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(2);
+ expect(h.state.editingGroupId).toBeNull();
+ expect(h.state.selectedGroupIds).toEqual({ A: true });
+
+ Keyboard.redo();
+ assertSelectedElements([rect2]);
+ expect(API.getUndoStack().length).toBe(2);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(h.state.editingGroupId).toBe("A");
+ expect(h.state.selectedGroupIds).not.toEqual({ A: true });
+
+ Keyboard.redo();
+ assertSelectedElements([rect1]);
+ expect(API.getUndoStack().length).toBe(3);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.state.editingGroupId).toBe("A");
+ expect(h.state.selectedGroupIds).not.toEqual({ A: true });
+
+ Keyboard.undo();
+ assertSelectedElements([rect2]);
+ expect(API.getUndoStack().length).toBe(2);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(h.state.editingGroupId).toBe("A");
+ expect(h.state.selectedGroupIds).not.toEqual({ A: true });
+
+ Keyboard.undo();
+ assertSelectedElements([rect1, rect2]);
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(2);
+ expect(h.state.editingGroupId).toBeNull();
+ expect(h.state.selectedGroupIds).toEqual({ A: true });
+
+ // outside the editing group, testing duplication
+ Keyboard.withModifierKeys({ ctrl: true }, () => {
+ Keyboard.keyPress("d");
+ });
+ assertSelectedElements([h.elements[2], h.elements[3]]);
+ expect(API.getUndoStack().length).toBe(2);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.elements.length).toBe(4);
+ expect(h.state.editingGroupId).toBeNull();
+ expect(h.state.selectedGroupIds).not.toEqual(
+ expect.objectContaining({ A: true }),
+ );
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(h.elements.length).toBe(4);
+ expect(h.elements).toEqual([
expect.objectContaining({ id: rect1.id, isDeleted: false }),
expect.objectContaining({ id: rect2.id, isDeleted: false }),
expect.objectContaining({ id: `${rect1.id}_copy`, isDeleted: true }),
expect.objectContaining({ id: `${rect2.id}_copy`, isDeleted: true }),
+ ]);
+ expect(h.state.editingGroupId).toBeNull();
+ expect(h.state.selectedGroupIds).toEqual({ A: true });
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(2);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.elements.length).toBe(4);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect1.id, isDeleted: false }),
+ expect.objectContaining({ id: rect2.id, isDeleted: false }),
+ expect.objectContaining({ id: `${rect1.id}_copy`, isDeleted: false }),
+ expect.objectContaining({ id: `${rect2.id}_copy`, isDeleted: false }),
+ ]);
+ expect(h.state.editingGroupId).toBeNull();
+ expect(h.state.selectedGroupIds).not.toEqual(
+ expect.objectContaining({ A: true }),
+ );
+
+ // undo again, and duplicate once more
+ Keyboard.withModifierKeys({ ctrl: true }, () => {
+ Keyboard.keyPress("z");
+ Keyboard.keyPress("d");
+ });
+ expect(API.getUndoStack().length).toBe(2);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.elements.length).toBe(6);
+ expect(h.elements).toEqual(
+ expect.arrayContaining([
+ expect.objectContaining({ id: rect1.id, isDeleted: false }),
+ expect.objectContaining({ id: rect2.id, isDeleted: false }),
+ expect.objectContaining({ id: `${rect1.id}_copy`, isDeleted: true }),
+ expect.objectContaining({ id: `${rect2.id}_copy`, isDeleted: true }),
+ expect.objectContaining({
+ id: `${rect1.id}_copy_copy`,
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: `${rect2.id}_copy_copy`,
+ isDeleted: false,
+ }),
+ ]),
+ );
+ expect(h.state.editingGroupId).toBeNull();
+ expect(h.state.selectedGroupIds).not.toEqual(
+ expect.objectContaining({ A: true }),
+ );
+ });
+
+ it("should support changes in elements' order", async () => {
+ await render();
+
+ const rect1 = UI.createElement("rectangle", { x: 10 });
+ const rect2 = UI.createElement("rectangle", { x: 20, y: 20 });
+ const rect3 = UI.createElement("rectangle", { x: 40, y: 40 });
+
+ act(() => h.app.actionManager.executeAction(actionSendBackward));
+
+ expect(API.getUndoStack().length).toBe(4);
+ expect(API.getRedoStack().length).toBe(0);
+ assertSelectedElements(rect3);
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(3);
+ expect(API.getRedoStack().length).toBe(1);
+ assertSelectedElements(rect3);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect1.id }),
+ expect.objectContaining({ id: rect2.id }),
+ expect.objectContaining({ id: rect3.id }),
+ ]);
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(4);
+ expect(API.getRedoStack().length).toBe(0);
+ assertSelectedElements(rect3);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect1.id }),
+ expect.objectContaining({ id: rect3.id }),
+ expect.objectContaining({ id: rect2.id }),
+ ]);
+
+ mouse.select([rect1, rect3]);
+ expect(API.getUndoStack().length).toBe(6);
+ expect(API.getRedoStack().length).toBe(0);
+ assertSelectedElements([rect1, rect3]);
+
+ act(() => h.app.actionManager.executeAction(actionBringForward));
+
+ expect(API.getUndoStack().length).toBe(7);
+ expect(API.getRedoStack().length).toBe(0);
+ assertSelectedElements([rect1, rect3]);
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(6);
+ expect(API.getRedoStack().length).toBe(1);
+ assertSelectedElements([rect1, rect3]);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect1.id }),
+ expect.objectContaining({ id: rect3.id }),
+ expect.objectContaining({ id: rect2.id }),
+ ]);
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(7);
+ expect(API.getRedoStack().length).toBe(0);
+ assertSelectedElements([rect1, rect3]);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect2.id }),
+ expect.objectContaining({ id: rect1.id }),
+ expect.objectContaining({ id: rect3.id }),
+ ]);
+ });
+
+ describe("should support bidirectional bindings", async () => {
+ let excalidrawAPI: ExcalidrawImperativeAPI;
+
+ let rect1: ExcalidrawGenericElement;
+ let rect2: ExcalidrawGenericElement;
+ let text: ExcalidrawTextElement;
+ let arrow: ExcalidrawLinearElement;
+
+ const rect1Props = {
+ type: "rectangle",
+ height: 100,
+ width: 100,
+ x: -100,
+ y: -50,
+ } as const;
+
+ const rect2Props = {
+ type: "rectangle",
+ height: 100,
+ width: 100,
+ x: 100,
+ y: -50,
+ } as const;
+
+ const textProps = {
+ type: "text",
+ x: -200,
+ text: "ola",
+ } as const;
+
+ beforeEach(async () => {
+ const excalidrawAPIPromise =
+ resolvablePromise();
+
+ await render(
+ excalidrawAPIPromise.resolve(api as any)}
+ handleKeyboardGlobally={true}
+ />,
+ );
+ excalidrawAPI = await excalidrawAPIPromise;
+
+ rect1 = API.createElement({ ...rect1Props });
+ text = API.createElement({ ...textProps });
+ rect2 = API.createElement({ ...rect2Props });
+
+ excalidrawAPI.updateScene({
+ elements: [rect1, text, rect2],
+ commitToStore: true,
+ });
+
+ // bind text1 to rect1
+ mouse.select([rect1, text]);
+ fireEvent.contextMenu(GlobalTestState.interactiveCanvas);
+ fireEvent.click(
+ queryByText(
+ document.querySelector(".context-menu") as HTMLElement,
+ "Bind text to the container",
+ )!,
+ );
+
+ expect(API.getUndoStack().length).toBe(4);
+ expect(text.containerId).toBe(rect1.id);
+ expect(rect1.boundElements).toStrictEqual([
+ { id: text.id, type: "text" },
+ ]);
+
+ // bind arrow to rect1 and rect2
+ UI.clickTool("arrow");
+ mouse.down(0, 0);
+ mouse.up(100, 0);
+
+ arrow = h.elements[3] as ExcalidrawLinearElement;
+
+ expect(API.getUndoStack().length).toBe(5);
+ expect(arrow.startBinding).toEqual({
+ elementId: rect1.id,
+ focus: expect.toBeNonNaNNumber(),
+ gap: expect.toBeNonNaNNumber(),
+ });
+ expect(arrow.endBinding).toEqual({
+ elementId: rect2.id,
+ focus: expect.toBeNonNaNNumber(),
+ gap: expect.toBeNonNaNNumber(),
+ });
+ expect(rect1.boundElements).toStrictEqual([
+ { id: text.id, type: "text" },
+ { id: arrow.id, type: "arrow" },
+ ]);
+ expect(rect2.boundElements).toStrictEqual([
+ { id: arrow.id, type: "arrow" },
+ ]);
+ });
+
+ it("should unbind arrow from non deleted bindable elements on undo and rebind on redo", async () => {
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(4);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(arrow.startBinding).toEqual({
+ elementId: rect1.id,
+ focus: expect.toBeNonNaNNumber(),
+ gap: expect.toBeNonNaNNumber(),
+ });
+ expect(arrow.endBinding).toEqual({
+ elementId: rect2.id,
+ focus: expect.toBeNonNaNNumber(),
+ gap: expect.toBeNonNaNNumber(),
+ });
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: rect1.id,
+ boundElements: [{ id: text.id, type: "text" }],
+ }),
+ expect.objectContaining({ id: text.id }),
+ expect.objectContaining({ id: rect2.id, boundElements: [] }),
+ expect.objectContaining({ id: arrow.id, isDeleted: true }),
+ ]);
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(5);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(arrow.startBinding).toEqual({
+ elementId: rect1.id,
+ focus: expect.toBeNonNaNNumber(),
+ gap: expect.toBeNonNaNNumber(),
+ });
+ expect(arrow.endBinding).toEqual({
+ elementId: rect2.id,
+ focus: expect.toBeNonNaNNumber(),
+ gap: expect.toBeNonNaNNumber(),
+ });
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: rect1.id,
+ boundElements: [
+ { id: text.id, type: "text" },
+ { id: arrow.id, type: "arrow" },
+ ],
+ }),
+ expect.objectContaining({ id: text.id }),
+ expect.objectContaining({
+ id: rect2.id,
+ boundElements: [{ id: arrow.id, type: "arrow" }],
+ }),
+ expect.objectContaining({ id: arrow.id, isDeleted: false }),
+ ]);
+ });
+
+ it("should unbind arrow from non deleted bindable elements on deletion and rebind on undo", async () => {
+ Keyboard.keyDown(KEYS.DELETE);
+ expect(API.getUndoStack().length).toBe(6);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(arrow.startBinding).toEqual({
+ elementId: rect1.id,
+ focus: expect.toBeNonNaNNumber(),
+ gap: expect.toBeNonNaNNumber(),
+ });
+ expect(arrow.endBinding).toEqual({
+ elementId: rect2.id,
+ focus: expect.toBeNonNaNNumber(),
+ gap: expect.toBeNonNaNNumber(),
+ });
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: rect1.id,
+ boundElements: [{ id: text.id, type: "text" }],
+ }),
+ expect.objectContaining({ id: text.id }),
+ expect.objectContaining({ id: rect2.id, boundElements: [] }),
+ expect.objectContaining({ id: arrow.id, isDeleted: true }),
+ ]);
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(5);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(arrow.startBinding).toEqual({
+ elementId: rect1.id,
+ focus: expect.toBeNonNaNNumber(),
+ gap: expect.toBeNonNaNNumber(),
+ });
+ expect(arrow.endBinding).toEqual({
+ elementId: rect2.id,
+ focus: expect.toBeNonNaNNumber(),
+ gap: expect.toBeNonNaNNumber(),
+ });
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: rect1.id,
+ boundElements: [
+ { id: text.id, type: "text" },
+ { id: arrow.id, type: "arrow" },
+ ],
+ }),
+ expect.objectContaining({ id: text.id }),
+ expect.objectContaining({
+ id: rect2.id,
+ boundElements: [{ id: arrow.id, type: "arrow" }],
+ }),
+ expect.objectContaining({ id: arrow.id, isDeleted: false }),
+ ]);
+ });
+
+ it("should unbind everything from non deleted elements when iterating through the whole undo stack and vice versa rebind everything on redo", async () => {
+ Keyboard.undo();
+ Keyboard.undo();
+ Keyboard.undo();
+ Keyboard.undo();
+ Keyboard.undo();
+
+ expect(API.getUndoStack().length).toBe(0);
+ expect(API.getRedoStack().length).toBe(5);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: rect1.id,
+ boundElements: [],
+ isDeleted: true,
+ }),
+ expect.objectContaining({
+ id: text.id,
+ containerId: null,
+ isDeleted: true,
+ }),
+ expect.objectContaining({
+ id: rect2.id,
+ boundElements: [],
+ isDeleted: true,
+ }),
+ expect.objectContaining({
+ id: arrow.id,
+ startBinding: {
+ elementId: rect1.id,
+ focus: expect.toBeNonNaNNumber(),
+ gap: expect.toBeNonNaNNumber(),
+ },
+ endBinding: {
+ elementId: rect2.id,
+ focus: expect.toBeNonNaNNumber(),
+ gap: expect.toBeNonNaNNumber(),
+ },
+ isDeleted: true,
+ }),
+ ]);
+
+ Keyboard.redo();
+ Keyboard.redo();
+ Keyboard.redo();
+ Keyboard.redo();
+ Keyboard.redo();
+
+ expect(API.getUndoStack().length).toBe(5);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: rect1.id,
+ boundElements: [
+ { id: text.id, type: "text" },
+ { id: arrow.id, type: "arrow" },
+ ],
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: text.id,
+ containerId: rect1.id,
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: rect2.id,
+ boundElements: [{ id: arrow.id, type: "arrow" }],
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: arrow.id,
+ startBinding: {
+ elementId: rect1.id,
+ focus: expect.toBeNonNaNNumber(),
+ gap: expect.toBeNonNaNNumber(),
+ },
+ endBinding: {
+ elementId: rect2.id,
+ focus: expect.toBeNonNaNNumber(),
+ gap: expect.toBeNonNaNNumber(),
+ },
+ isDeleted: false,
+ }),
+ ]);
+ });
+
+ it("should unbind rectangle from arrow on deletion and rebind on undo", async () => {
+ mouse.select(rect1);
+ Keyboard.keyPress(KEYS.DELETE);
+ expect(API.getUndoStack().length).toBe(7);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: rect1.id,
+ boundElements: [
+ { id: text.id, type: "text" },
+ { id: arrow.id, type: "arrow" },
+ ],
+ isDeleted: true,
+ }),
+ expect.objectContaining({
+ id: text.id,
+ containerId: rect1.id,
+ isDeleted: true,
+ }),
+ expect.objectContaining({
+ id: rect2.id,
+ boundElements: [{ id: arrow.id, type: "arrow" }],
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: arrow.id,
+ startBinding: null,
+ endBinding: {
+ elementId: rect2.id,
+ focus: expect.toBeNonNaNNumber(),
+ gap: expect.toBeNonNaNNumber(),
+ },
+ isDeleted: false,
+ }),
+ ]);
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(6);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: rect1.id,
+ boundElements: [
+ { id: arrow.id, type: "arrow" },
+ { id: text.id, type: "text" }, // order has now changed!
+ ],
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: text.id,
+ containerId: rect1.id,
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: rect2.id,
+ boundElements: [{ id: arrow.id, type: "arrow" }],
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: arrow.id,
+ startBinding: {
+ elementId: rect1.id,
+ focus: expect.toBeNonNaNNumber(),
+ gap: expect.toBeNonNaNNumber(),
+ },
+ endBinding: {
+ elementId: rect2.id,
+ focus: expect.toBeNonNaNNumber(),
+ gap: expect.toBeNonNaNNumber(),
+ },
+ isDeleted: false,
+ }),
+ ]);
+ });
+
+ it("should unbind rectangles from arrow on deletion and rebind on undo", async () => {
+ mouse.select([rect1, rect2]);
+ Keyboard.keyPress(KEYS.DELETE);
+ expect(API.getUndoStack().length).toBe(8);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: rect1.id,
+ boundElements: [
+ { id: text.id, type: "text" },
+ { id: arrow.id, type: "arrow" },
+ ],
+ isDeleted: true,
+ }),
+ expect.objectContaining({
+ id: text.id,
+ containerId: rect1.id,
+ isDeleted: true,
+ }),
+ expect.objectContaining({
+ id: rect2.id,
+ boundElements: [{ id: arrow.id, type: "arrow" }],
+ isDeleted: true,
+ }),
+ expect.objectContaining({
+ id: arrow.id,
+ startBinding: null,
+ endBinding: null,
+ isDeleted: false,
+ }),
+ ]);
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(7);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: rect1.id,
+ boundElements: [
+ { id: arrow.id, type: "arrow" },
+ { id: text.id, type: "text" }, // order has now changed!
+ ],
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: text.id,
+ containerId: rect1.id,
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: rect2.id,
+ boundElements: [{ id: arrow.id, type: "arrow" }],
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: arrow.id,
+ startBinding: {
+ elementId: rect1.id,
+ focus: expect.toBeNonNaNNumber(),
+ gap: expect.toBeNonNaNNumber(),
+ },
+ endBinding: {
+ elementId: rect2.id,
+ focus: expect.toBeNonNaNNumber(),
+ gap: expect.toBeNonNaNNumber(),
+ },
+ isDeleted: false,
+ }),
+ ]);
+ });
+ });
+ });
+
+ describe("multiplayer undo/redo", () => {
+ let excalidrawAPI: ExcalidrawImperativeAPI;
+
+ // Util to check that we end up in the same state after series of undo / redo
+ function runTwice(callback: () => void) {
+ for (let i = 0; i < 2; i++) {
+ callback();
+ }
+ }
+
+ beforeEach(async () => {
+ const excalidrawAPIPromise = resolvablePromise();
+ await render(
+ excalidrawAPIPromise.resolve(api as any)}
+ handleKeyboardGlobally={true}
+ />,
+ );
+ excalidrawAPI = await excalidrawAPIPromise;
+ });
+
+ it("should not override remote changes on different elements", async () => {
+ UI.createElement("rectangle", { x: 10 });
+ togglePopover("Background");
+ UI.clickOnTestId("color-red");
+
+ expect(API.getUndoStack().length).toBe(2);
+
+ expect(h.elements).toEqual([
+ expect.objectContaining({ backgroundColor: red }),
+ ]);
+
+ // Simulate remote update
+ excalidrawAPI.updateScene({
+ elements: [
+ ...h.elements,
+ API.createElement({
+ type: "rectangle",
+ strokeColor: blue,
+ }),
+ ],
+ });
+
+ Keyboard.undo();
+ expect(h.elements).toEqual([
+ expect.objectContaining({ backgroundColor: transparent }),
+ expect.objectContaining({ strokeColor: blue }),
+ ]);
+
+ Keyboard.redo();
+ expect(h.elements).toEqual([
+ expect.objectContaining({ backgroundColor: red }),
+ expect.objectContaining({ strokeColor: blue }),
+ ]);
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getUndoStack().length).toBe(1);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ backgroundColor: transparent }),
+ expect.objectContaining({ strokeColor: blue }),
+ ]);
+ });
+
+ it("should not override remote changes on different properties", async () => {
+ UI.createElement("rectangle", { x: 10 });
+ togglePopover("Background");
+ UI.clickOnTestId("color-red");
+
+ expect(API.getUndoStack().length).toBe(2);
+
+ // Simulate remote update
+ excalidrawAPI.updateScene({
+ elements: [
+ newElementWith(h.elements[0], {
+ strokeColor: yellow,
+ }),
+ ],
+ });
+
+ Keyboard.undo();
+ expect(h.elements).toEqual([
expect.objectContaining({
- id: `${rect1.id}_copy_copy`,
+ backgroundColor: transparent,
+ strokeColor: yellow,
+ }),
+ ]);
+
+ Keyboard.redo();
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ backgroundColor: red,
+ strokeColor: yellow,
+ }),
+ ]);
+ });
+
+ // https://www.figma.com/blog/how-figmas-multiplayer-technology-works/#implementing-undo
+ // This is due to the fact that deltas are updated in `applyLatestChanges`.
+ it("should update history entries after remote changes on the same properties", async () => {
+ UI.createElement("rectangle", { x: 10 });
+ togglePopover("Background");
+ UI.clickOnTestId("color-red");
+ UI.clickOnTestId("color-blue");
+
+ // At this point we have all the history entries created, no new entries will be created, only existing entries will get inversed and updated
+ expect(API.getUndoStack().length).toBe(3);
+
+ Keyboard.undo();
+ expect(h.elements).toEqual([
+ expect.objectContaining({ backgroundColor: red }),
+ ]);
+
+ Keyboard.redo();
+ expect(h.elements).toEqual([
+ expect.objectContaining({ backgroundColor: blue }),
+ ]);
+
+ // Simulate remote update
+ excalidrawAPI.updateScene({
+ elements: [
+ newElementWith(h.elements[0], {
+ backgroundColor: yellow,
+ }),
+ ],
+ });
+
+ // At this point our entry gets updated from `red` -> `blue` into `red` -> `yellow`
+ Keyboard.undo();
+ expect(h.elements).toEqual([
+ expect.objectContaining({ backgroundColor: red }),
+ ]);
+
+ // Simulate remote update
+ excalidrawAPI.updateScene({
+ elements: [
+ newElementWith(h.elements[0], {
+ backgroundColor: violet,
+ }),
+ ],
+ });
+
+ // At this point our (inversed) entry gets updated from `red` -> `yellow` into `violet` -> `yellow`
+ Keyboard.redo();
+ expect(h.elements).toEqual([
+ expect.objectContaining({ backgroundColor: yellow }),
+ ]);
+
+ Keyboard.undo();
+ expect(h.elements).toEqual([
+ expect.objectContaining({ backgroundColor: violet }),
+ ]);
+
+ Keyboard.undo();
+ expect(h.elements).toEqual([
+ expect.objectContaining({ backgroundColor: transparent }),
+ ]);
+ });
+
+ // TODO: #7348 ideally we should not override, but since the order of groupIds matters, right now we cannot ensure that with postprocssed groupIds the order will be consistent after series or undos/redos, we don't postprocess them at all
+ // in other words, if we would postprocess groupIds, the groupIds order on "redo" below would be ["B", "A"] instead of ["A", "B"]
+ it("should override remotely added groups on undo, but restore them on redo", async () => {
+ const rect1 = API.createElement({ type: "rectangle" });
+ const rect2 = API.createElement({ type: "rectangle" });
+
+ // Initialize scene
+ excalidrawAPI.updateScene({
+ elements: [rect1, rect2],
+ });
+
+ // Simulate local update
+ excalidrawAPI.updateScene({
+ elements: [
+ newElementWith(h.elements[0], { groupIds: ["A"] }),
+ newElementWith(h.elements[1], { groupIds: ["A"] }),
+ ],
+ commitToStore: true,
+ });
+
+ const rect3 = API.createElement({ type: "rectangle", groupIds: ["B"] });
+ const rect4 = API.createElement({ type: "rectangle", groupIds: ["B"] });
+
+ // Simulate remote update
+ excalidrawAPI.updateScene({
+ elements: [
+ newElementWith(h.elements[0], { groupIds: ["A", "B"] }),
+ newElementWith(h.elements[1], { groupIds: ["A", "B"] }),
+ rect3,
+ rect4,
+ ],
+ });
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(0);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect1.id, groupIds: [] }),
+ expect.objectContaining({ id: rect2.id, groupIds: [] }),
+ expect.objectContaining({ id: rect3.id, groupIds: ["B"] }),
+ expect.objectContaining({ id: rect4.id, groupIds: ["B"] }),
+ ]);
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect1.id, groupIds: ["A", "B"] }),
+ expect.objectContaining({ id: rect2.id, groupIds: ["A", "B"] }),
+ expect.objectContaining({ id: rect3.id, groupIds: ["B"] }),
+ expect.objectContaining({ id: rect4.id, groupIds: ["B"] }),
+ ]);
+ });
+
+ it("should override remotely added points on undo, but restore them on redo", async () => {
+ UI.clickTool("arrow");
+ mouse.click(0, 0);
+ mouse.click(10, 10);
+ mouse.click(20, 20);
+
+ // actionFinalize
+ Keyboard.keyPress(KEYS.ENTER);
+
+ // Simulate remote update
+ excalidrawAPI.updateScene({
+ elements: [
+ newElementWith(h.elements[0] as ExcalidrawLinearElement, {
+ points: [
+ [0, 0],
+ [5, 5],
+ [10, 10],
+ [15, 15],
+ [20, 20],
+ ],
+ }),
+ ],
+ });
+
+ Keyboard.undo(); // undo `actionFinalize`
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(2);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ points: [
+ [0, 0],
+ // overriding all the remote points as they are not being postprocessed (as we cannot ensure the order consistency similar to groupIds)
+ // but in this case it might not make even sense to combine the points, as in some cases the linear element might lead unexpected results
+ [10, 10],
+ ],
+ }),
+ ]);
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(0);
+ expect(API.getRedoStack().length).toBe(3);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ isDeleted: true,
+ points: [
+ [0, 0],
+ [10, 10],
+ ],
+ }),
+ ]);
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(2);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ isDeleted: false,
+ points: [
+ [0, 0],
+ [10, 10],
+ ],
+ }),
+ ]);
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(2);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ points: [
+ [0, 0],
+ [5, 5],
+ [10, 10],
+ [15, 15],
+ [20, 20],
+ ],
+ }),
+ ]);
+
+ Keyboard.redo(); // redo `actionFinalize`
+ expect(API.getUndoStack().length).toBe(3);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ points: [
+ [0, 0],
+ [5, 5],
+ [10, 10],
+ [15, 15],
+ [20, 20],
+ ],
+ }),
+ ]);
+ });
+
+ it("should redistribute deltas when element gets removed locally but is restored remotely", async () => {
+ UI.createElement("rectangle", { x: 10 });
+ Keyboard.keyDown(KEYS.DELETE);
+
+ expect(API.getUndoStack().length).toBe(2);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ backgroundColor: transparent,
+ isDeleted: true,
+ }),
+ ]);
+
+ // Simulate remote update & restore
+ excalidrawAPI.updateScene({
+ elements: [
+ newElementWith(h.elements[0], {
+ backgroundColor: yellow,
+ isDeleted: false, // undeletion might happen due to concurrency between clients
+ }),
+ ],
+ });
+
+ expect(API.getSelectedElements()).toEqual([]);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ backgroundColor: yellow,
+ isDeleted: false,
+ }),
+ ]);
+
+ // inserted.isDeleted: true is updated with the latest changes to false
+ // deleted.isDeleted and inserted.isDeleted are the same and therefore removed delta becomes an updated delta
+ Keyboard.undo();
+ expect(assertSelectedElements(h.elements[0]));
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ backgroundColor: yellow,
+ isDeleted: false,
+ }),
+ ]);
+
+ Keyboard.undo();
+ expect(API.getSelectedElements()).toEqual([]);
+ expect(API.getUndoStack().length).toBe(0);
+ expect(API.getRedoStack().length).toBe(2);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ backgroundColor: yellow,
+ isDeleted: true,
+ }),
+ ]);
+
+ Keyboard.redo();
+ expect(assertSelectedElements(h.elements[0]));
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ backgroundColor: yellow,
+ isDeleted: false,
+ }),
+ ]);
+
+ Keyboard.redo();
+ expect(assertSelectedElements([]));
+ expect(API.getUndoStack().length).toBe(2);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ backgroundColor: yellow,
+ isDeleted: false, // isDeleted got updated
+ }),
+ ]);
+ });
+
+ it("should iterate through the history when when element change relates to remotely deleted element", async () => {
+ UI.createElement("rectangle", { x: 10 });
+ togglePopover("Background");
+ UI.clickOnTestId("color-red");
+
+ expect(API.getUndoStack().length).toBe(2);
+
+ expect(h.elements).toEqual([
+ expect.objectContaining({ backgroundColor: red }),
+ ]);
+
+ // Simulate remote update & deletion
+ excalidrawAPI.updateScene({
+ elements: [
+ newElementWith(h.elements[0], {
+ backgroundColor: yellow,
+ isDeleted: true,
+ }),
+ ],
+ });
+
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ backgroundColor: yellow,
+ isDeleted: true,
+ }),
+ ]);
+
+ // Will iterate through undo stack since applying the change
+ // results in no visible change on a deleted element
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(0);
+ expect(API.getRedoStack().length).toBe(2);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ backgroundColor: transparent,
+ isDeleted: true,
+ }),
+ ]);
+
+ // We reached the bottom, again we iterate through invisible changes and reach the top
+ Keyboard.redo();
+ assertSelectedElements();
+ expect(API.getUndoStack().length).toBe(2);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ backgroundColor: yellow, // the color still get's updated
+ isDeleted: true, // but the element remains deleted
+ }),
+ ]);
+ });
+
+ it("should iterate through the history when element changes relate only to remotely deleted elements", async () => {
+ const rect1 = UI.createElement("rectangle", { x: 10 });
+
+ const rect2 = UI.createElement("rectangle", { x: 20 });
+ togglePopover("Background");
+ UI.clickOnTestId("color-red");
+
+ const rect3 = UI.createElement("rectangle", { x: 30, y: 30 });
+
+ // move rect3
+ mouse.downAt(35, 35);
+ mouse.moveTo(55, 55);
+ mouse.upAt(55, 55);
+
+ expect(API.getUndoStack().length).toBe(5);
+
+ // Simulate remote update
+ excalidrawAPI.updateScene({
+ elements: [
+ h.elements[0],
+ newElementWith(h.elements[1], {
+ isDeleted: true,
+ }),
+ newElementWith(h.elements[2], {
+ isDeleted: true,
+ }),
+ ],
+ });
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(4);
+ expect(API.getSelectedElements()).toEqual([
+ expect.objectContaining({ id: rect1.id }),
+ ]);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: rect1.id,
isDeleted: false,
}),
expect.objectContaining({
- id: `${rect2.id}_copy_copy`,
+ id: rect2.id,
+ isDeleted: true,
+ backgroundColor: transparent,
+ }),
+ expect.objectContaining({
+ id: rect3.id,
+ isDeleted: true,
+ x: 30,
+ y: 30,
+ }),
+ ]);
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(5);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(API.getSelectedElements()).toEqual([]);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: rect1.id,
isDeleted: false,
}),
- ]),
- );
- expect(h.state.selectedGroupIds).not.toEqual(
- expect.objectContaining({ A: true }),
- );
+ expect.objectContaining({
+ id: rect2.id,
+ isDeleted: true,
+ backgroundColor: red,
+ }),
+ expect.objectContaining({
+ id: rect3.id,
+ isDeleted: true,
+ x: 50,
+ y: 50,
+ }),
+ ]);
+ });
+
+ it("should iterate through the history when selected elements relate only to remotely deleted elements", async () => {
+ const rect1 = API.createElement({ type: "rectangle", x: 10, y: 10 });
+ const rect2 = API.createElement({ type: "rectangle", x: 20, y: 20 });
+ const rect3 = API.createElement({ type: "rectangle", x: 30, y: 30 });
+
+ h.elements = [rect1, rect2, rect3];
+ mouse.select(rect1);
+ mouse.select([rect2, rect3]);
+
+ expect(API.getUndoStack().length).toBe(3);
+ expect(API.getSelectedElements()).toEqual([
+ expect.objectContaining({ id: rect2.id }),
+ expect.objectContaining({ id: rect3.id }),
+ ]);
+
+ // Simulate remote update
+ excalidrawAPI.updateScene({
+ elements: [
+ h.elements[0],
+ newElementWith(h.elements[1], {
+ isDeleted: true,
+ }),
+ newElementWith(h.elements[2], {
+ isDeleted: true,
+ }),
+ ],
+ });
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(2);
+ expect(API.getSelectedElements()).toEqual([
+ expect.objectContaining({ id: rect1.id, isDeleted: false }),
+ ]);
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(3);
+ expect(API.getRedoStack().length).toBe(0);
+ // do not expect any selectedElementIds, as all relate to deleted elements
+ expect(API.getSelectedElements()).toEqual([]);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect1.id, isDeleted: false }),
+ expect.objectContaining({ id: rect2.id, isDeleted: true }),
+ expect.objectContaining({ id: rect3.id, isDeleted: true }),
+ ]);
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(2);
+ expect(API.getSelectedElements()).toEqual([
+ expect.objectContaining({ id: rect1.id, isDeleted: false }),
+ ]);
+
+ // Simulate remote update
+ excalidrawAPI.updateScene({
+ elements: [
+ h.elements[0],
+ newElementWith(h.elements[1], {
+ isDeleted: false,
+ }),
+ newElementWith(h.elements[2], {
+ isDeleted: false,
+ }),
+ ],
+ });
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(2);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(API.getSelectedElements()).toEqual([
+ expect.objectContaining({ id: rect2.id, isDeleted: false }),
+ ]);
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(3);
+ expect(API.getRedoStack().length).toBe(0);
+ // now we again expect these as selected, as they got restored remotely
+ expect(API.getSelectedElements()).toEqual([
+ expect.objectContaining({ id: rect2.id }),
+ expect.objectContaining({ id: rect3.id }),
+ ]);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect1.id, isDeleted: false }),
+ expect.objectContaining({ id: rect2.id, isDeleted: false }),
+ expect.objectContaining({ id: rect3.id, isDeleted: false }),
+ ]);
+ });
+
+ it("should iterate through the history when selected groups contain only remotely deleted elements", async () => {
+ const rect1 = API.createElement({
+ type: "rectangle",
+ groupIds: ["A"],
+ });
+ const rect2 = API.createElement({
+ type: "rectangle",
+ groupIds: ["A"],
+ });
+ const rect3 = API.createElement({
+ type: "rectangle",
+ groupIds: ["B"],
+ });
+ const rect4 = API.createElement({
+ type: "rectangle",
+ groupIds: ["B"],
+ });
+
+ // Simulate remote update
+ excalidrawAPI.updateScene({
+ elements: [rect1, rect2],
+ });
+
+ Keyboard.withModifierKeys({ ctrl: true }, () => {
+ Keyboard.keyPress(KEYS.A);
+ });
+
+ // Simulate remote update
+ excalidrawAPI.updateScene({
+ elements: [h.elements[0], h.elements[1], rect3, rect4],
+ });
+
+ Keyboard.withModifierKeys({ ctrl: true }, () => {
+ Keyboard.keyPress(KEYS.A);
+ });
+
+ expect(API.getUndoStack().length).toBe(2);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.state.selectedGroupIds).toEqual({ A: true, B: true });
+
+ // Simulate remote update
+ excalidrawAPI.updateScene({
+ elements: [
+ newElementWith(h.elements[0], {
+ isDeleted: true,
+ }),
+ newElementWith(h.elements[1], {
+ isDeleted: true,
+ }),
+ ],
+ });
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(0);
+ expect(API.getRedoStack().length).toBe(2); // iterated two steps back!
+ expect(h.state.selectedGroupIds).toEqual({});
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(2); // iterated two steps forward!
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.state.selectedGroupIds).toEqual({});
+
+ Keyboard.undo();
+
+ // Simulate remote update
+ excalidrawAPI.updateScene({
+ elements: [
+ newElementWith(h.elements[0], {
+ isDeleted: false,
+ }),
+ newElementWith(h.elements[1], {
+ isDeleted: false,
+ }),
+ ],
+ });
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(h.state.selectedGroupIds).toEqual({ A: true });
+
+ // Simulate remote update
+ excalidrawAPI.updateScene({
+ elements: [h.elements[0], h.elements[1], rect3, rect4],
+ });
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(2);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.state.selectedGroupIds).toEqual({ A: true, B: true });
+ });
+
+ it("should iterate through the history when editing group contains only remotely deleted elements", async () => {
+ const rect1 = API.createElement({
+ type: "rectangle",
+ groupIds: ["A"],
+ x: 0,
+ });
+ const rect2 = API.createElement({
+ type: "rectangle",
+ groupIds: ["A"],
+ x: 100,
+ });
+
+ h.elements = [rect1, rect2];
+ mouse.select(rect1);
+
+ // inside the editing group
+ mouse.doubleClickOn(rect2);
+ expect(API.getUndoStack().length).toBe(2);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.state.editingGroupId).toBe("A");
+
+ mouse.clickAt(-10, -10);
+ expect(API.getSelectedElements().length).toBe(0);
+ expect(API.getUndoStack().length).toBe(3);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.state.editingGroupId).toBeNull();
+
+ // Simulate remote update
+ excalidrawAPI.updateScene({
+ elements: [
+ newElementWith(h.elements[0], {
+ isDeleted: true,
+ }),
+ newElementWith(h.elements[1], {
+ isDeleted: true,
+ }),
+ ],
+ });
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(0);
+ expect(API.getRedoStack().length).toBe(3);
+ expect(h.state.editingGroupId).toBeNull();
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(3);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.state.editingGroupId).toBeNull();
+
+ // Simulate remote update
+ excalidrawAPI.updateScene({
+ elements: [
+ newElementWith(h.elements[0], {
+ isDeleted: false,
+ }),
+ h.elements[1],
+ ],
+ });
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(2);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(h.state.editingGroupId).toBe("A");
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(3);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.state.editingGroupId).toBeNull();
+ });
+
+ it("should iterate through the history when selected or editing linear element was remotely deleted", async () => {
+ // create three point arrow
+ UI.clickTool("arrow");
+ mouse.click(0, 0);
+ mouse.click(10, 10);
+
+ // actionFinalize
+ Keyboard.keyPress(KEYS.ENTER);
+
+ // open editor
+ Keyboard.withModifierKeys({ ctrl: true }, () => {
+ Keyboard.keyPress(KEYS.ENTER);
+ });
+
+ // leave editor
+ Keyboard.keyPress(KEYS.ESCAPE);
+
+ expect(API.getUndoStack().length).toBe(4);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.state.editingLinearElement).toBeNull();
+ expect(h.state.selectedLinearElement).toBeNull();
+
+ // Simulate remote update
+ excalidrawAPI.updateScene({
+ elements: [
+ newElementWith(h.elements[0], {
+ isDeleted: true,
+ }),
+ ],
+ });
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(0);
+ expect(API.getRedoStack().length).toBe(4);
+ expect(h.state.editingLinearElement).toBeNull();
+ expect(h.state.selectedLinearElement).toBeNull();
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(4);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.state.editingLinearElement).toBeNull();
+ expect(h.state.selectedLinearElement).toBeNull();
+ });
+
+ it("should iterate through the history when z-index changes do not produce visible change and we synced changed indices", async () => {
+ const rect1 = API.createElement({ type: "rectangle", x: 10, y: 10 }); // a "a0"
+ const rect2 = API.createElement({ type: "rectangle", x: 20, y: 20 }); // b "a1"
+ const rect3 = API.createElement({ type: "rectangle", x: 30, y: 30 }); // c "a2"
+
+ h.elements = [rect1, rect2, rect3];
+
+ mouse.select(rect2);
+
+ act(() => h.app.actionManager.executeAction(actionSendToBack));
+
+ expect(API.getUndoStack().length).toBe(2);
+ expect(API.getRedoStack().length).toBe(0);
+ assertSelectedElements([rect2]);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect2.id }), // b "Zz"
+ expect.objectContaining({ id: rect1.id }), // a "a0"
+ expect.objectContaining({ id: rect3.id }), // c "a2"
+ ]);
+
+ // Simulate remote update
+ excalidrawAPI.updateScene({
+ elements: [
+ newElementWith(h.elements[2], { index: "Zy" as FractionalIndex }),
+ h.elements[0],
+ h.elements[1],
+ ],
+ });
+
+ expect(API.getUndoStack().length).toBe(2);
+ expect(API.getRedoStack().length).toBe(0);
+ assertSelectedElements([rect2]);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect3.id }), // c "Zy"
+ expect.objectContaining({ id: rect2.id }), // b "Zz"
+ expect.objectContaining({ id: rect1.id }), // a "a0"
+ ]);
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(1);
+ assertSelectedElements([rect2]);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect3.id }), // c "Zy"
+ expect.objectContaining({ id: rect1.id }), // a "a0"
+ expect.objectContaining({ id: rect2.id }), // b "a1"
+ ]);
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(2);
+ expect(API.getRedoStack().length).toBe(0);
+ assertSelectedElements([rect2]);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect3.id }), // c "Zy"
+ expect.objectContaining({ id: rect2.id }), // b "Zz"
+ expect.objectContaining({ id: rect1.id }), // a "a0"
+ ]);
+
+ // Simulate remote update
+ excalidrawAPI.updateScene({
+ elements: [
+ newElementWith(h.elements[2], { index: "Zx" as FractionalIndex }),
+ h.elements[0],
+ h.elements[1],
+ ],
+ });
+
+ expect(API.getUndoStack().length).toBe(2);
+ expect(API.getRedoStack().length).toBe(0);
+ assertSelectedElements([rect2]);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect1.id }), // a "Zx"
+ expect.objectContaining({ id: rect3.id }), // c "Zy"
+ expect.objectContaining({ id: rect2.id }), // b "Zz"
+ ]);
+
+ Keyboard.undo();
+ // We iterated two steps as there was no change in order!
+ expect(API.getUndoStack().length).toBe(0);
+ expect(API.getRedoStack().length).toBe(2);
+ expect(API.getSelectedElements().length).toBe(0);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect1.id }), // a "Zx"
+ expect.objectContaining({ id: rect3.id }), // c "Zy"
+ expect.objectContaining({ id: rect2.id }), // b "a1"
+ ]);
+ });
+
+ it("should iterate through the history when z-index changes do not produce visible change and we synced all indices", async () => {
+ const rect1 = API.createElement({ type: "rectangle", x: 10, y: 10 });
+ const rect2 = API.createElement({ type: "rectangle", x: 20, y: 20 });
+ const rect3 = API.createElement({ type: "rectangle", x: 30, y: 30 });
+
+ h.elements = [rect1, rect2, rect3];
+
+ mouse.select(rect2);
+
+ act(() => h.app.actionManager.executeAction(actionSendToBack));
+
+ expect(API.getUndoStack().length).toBe(2);
+ expect(API.getRedoStack().length).toBe(0);
+ assertSelectedElements([rect2]);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect2.id }),
+ expect.objectContaining({ id: rect1.id }),
+ expect.objectContaining({ id: rect3.id }),
+ ]);
+
+ // Simulate remote update (fixes all invalid z-indices)
+ excalidrawAPI.updateScene({
+ elements: [
+ h.elements[2], // rect3
+ h.elements[0], // rect2
+ h.elements[1], // rect1
+ ],
+ });
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(1);
+ assertSelectedElements([rect2]);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect2.id }),
+ expect.objectContaining({ id: rect3.id }),
+ expect.objectContaining({ id: rect1.id }),
+ ]);
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(2);
+ expect(API.getRedoStack().length).toBe(0);
+ assertSelectedElements([rect2]);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect3.id }),
+ expect.objectContaining({ id: rect2.id }),
+ expect.objectContaining({ id: rect1.id }),
+ ]);
+
+ // Simulate remote update
+ excalidrawAPI.updateScene({
+ elements: [
+ h.elements[1], // rect2
+ h.elements[0], // rect3
+ h.elements[2], // rect1
+ ],
+ });
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(0);
+ expect(API.getRedoStack().length).toBe(2); // now we iterated two steps back!
+ assertSelectedElements([]);
+ expect(h.elements).toEqual([
+ expect.objectContaining({ id: rect2.id }),
+ expect.objectContaining({ id: rect3.id }),
+ expect.objectContaining({ id: rect1.id }),
+ ]);
+ });
+
+ it("should not let remote changes to interfere with in progress freedraw", async () => {
+ UI.clickTool("freedraw");
+ mouse.down(10, 10);
+ mouse.moveTo(30, 30);
+
+ const rectProps = {
+ type: "rectangle",
+ strokeColor: blue,
+ } as const;
+
+ // Simulate remote update
+ const rect = API.createElement({ ...rectProps });
+
+ // Simulate remote update
+ excalidrawAPI.updateScene({
+ elements: [...h.elements, rect],
+ });
+
+ mouse.moveTo(60, 60);
+ mouse.up();
+
+ Keyboard.undo();
+
+ expect(API.getUndoStack().length).toBe(0);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: h.elements[0].id,
+ type: "freedraw",
+ isDeleted: true,
+ }),
+ expect.objectContaining(rectProps),
+ ]);
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: h.elements[0].id,
+ type: "freedraw",
+ isDeleted: false,
+ }),
+ expect.objectContaining(rectProps),
+ ]);
+ });
+
+ it("should not let remote changes to interfere with in progress resizing", async () => {
+ const props1 = { x: 10, y: 10, width: 10, height: 10 };
+ const rect1 = UI.createElement("rectangle", { ...props1 });
+
+ mouse.downAt(20, 20);
+ mouse.moveTo(40, 40);
+
+ assertSelectedElements(rect1);
+ expect(API.getUndoStack().length).toBe(1);
+
+ const rect3Props = {
+ type: "rectangle",
+ strokeColor: blue,
+ } as const;
+
+ const rect3 = API.createElement({ ...rect3Props });
+
+ // // Simulate remote update
+ excalidrawAPI.updateScene({
+ elements: [...h.elements, rect3],
+ });
+
+ mouse.moveTo(100, 100);
+ mouse.up();
+
+ expect(API.getUndoStack().length).toBe(2);
+ expect(API.getRedoStack().length).toBe(0);
+ assertSelectedElements(rect1);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: rect1.id,
+ ...props1,
+ isDeleted: false,
+ width: 90,
+ height: 90,
+ }),
+ expect.objectContaining(rect3Props),
+ ]);
+
+ Keyboard.undo();
+ assertSelectedElements(rect1);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: rect1.id,
+ ...props1,
+ isDeleted: false,
+ }),
+ expect.objectContaining(rect3Props),
+ ]);
+
+ Keyboard.undo();
+ expect(API.getSelectedElements()).toEqual([]);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: rect1.id,
+ ...props1,
+ isDeleted: true,
+ }),
+ expect.objectContaining(rect3Props),
+ ]);
+
+ Keyboard.redo();
+ assertSelectedElements(rect1);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: rect1.id,
+ ...props1,
+ isDeleted: false,
+ }),
+ expect.objectContaining(rect3Props),
+ ]);
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(2);
+ expect(API.getRedoStack().length).toBe(0);
+ assertSelectedElements(rect1);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: rect1.id,
+ ...props1,
+ isDeleted: false,
+ width: 90,
+ height: 90,
+ }),
+ expect.objectContaining(rect3Props),
+ ]);
+ });
+
+ it("should not let remote changes to interfere with in progress dragging", async () => {
+ const rect1 = UI.createElement("rectangle", { x: 10, y: 10 });
+ const rect2 = UI.createElement("rectangle", { x: 30, y: 30 });
+
+ mouse.select([rect1, rect2]);
+ mouse.downAt(20, 20);
+ mouse.moveTo(50, 50);
+
+ assertSelectedElements(rect1, rect2);
+ expect(API.getUndoStack().length).toBe(4);
+
+ const rect3Props = {
+ type: "rectangle",
+ strokeColor: blue,
+ } as const;
+
+ const rect3 = API.createElement({ ...rect3Props });
+
+ // Simulate remote update
+ excalidrawAPI.updateScene({
+ elements: [...h.elements, rect3],
+ });
+
+ mouse.moveTo(100, 100);
+ mouse.up();
+
+ expect(API.getUndoStack().length).toBe(5);
+ expect(API.getRedoStack().length).toBe(0);
+ assertSelectedElements(rect1, rect2);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: rect1.id,
+ x: 90,
+ y: 90,
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: rect2.id,
+ x: 110,
+ y: 110,
+ isDeleted: false,
+ }),
+ expect.objectContaining(rect3Props),
+ ]);
+
+ Keyboard.undo();
+ assertSelectedElements(rect1, rect2);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: rect1.id,
+ x: 10,
+ y: 10,
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: rect2.id,
+ x: 30,
+ y: 30,
+ isDeleted: false,
+ }),
+ expect.objectContaining(rect3Props),
+ ]);
+
+ Keyboard.undo();
+ assertSelectedElements(rect1);
+
+ Keyboard.undo();
+ assertSelectedElements(rect2);
+
+ Keyboard.undo();
+ assertSelectedElements(rect1);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: rect1.id,
+ x: 10,
+ y: 10,
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: rect2.id,
+ x: 30,
+ y: 30,
+ isDeleted: true,
+ }),
+ expect.objectContaining(rect3Props),
+ ]);
+
+ Keyboard.undo();
+ assertSelectedElements();
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: rect1.id,
+ x: 10,
+ y: 10,
+ isDeleted: true,
+ }),
+ expect.objectContaining({
+ id: rect2.id,
+ x: 30,
+ y: 30,
+ isDeleted: true,
+ }),
+ expect.objectContaining(rect3Props),
+ ]);
+
+ Keyboard.redo();
+ assertSelectedElements(rect1);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: rect1.id,
+ x: 10,
+ y: 10,
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: rect2.id,
+ x: 30,
+ y: 30,
+ isDeleted: true,
+ }),
+ expect.objectContaining(rect3Props),
+ ]);
+
+ Keyboard.redo();
+ assertSelectedElements(rect2);
+
+ Keyboard.redo();
+ assertSelectedElements(rect1);
+
+ Keyboard.redo();
+ assertSelectedElements(rect1, rect2);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: rect1.id,
+ x: 10,
+ y: 10,
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: rect2.id,
+ x: 30,
+ y: 30,
+ isDeleted: false,
+ }),
+ expect.objectContaining(rect3Props),
+ ]);
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(5);
+ expect(API.getRedoStack().length).toBe(0);
+ assertSelectedElements(rect1, rect2);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: rect1.id,
+ x: 90,
+ y: 90,
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: rect2.id,
+ x: 110,
+ y: 110,
+ isDeleted: false,
+ }),
+ expect.objectContaining(rect3Props),
+ ]);
+ });
+
+ describe("conflicts in bound text elements and their containers", () => {
+ let container: ExcalidrawGenericElement;
+ let text: ExcalidrawTextElement;
+
+ const containerProps = {
+ type: "rectangle",
+ width: 100,
+ x: 10,
+ y: 10,
+ angle: 0,
+ } as const;
+
+ const textProps = {
+ type: "text",
+ text: "que pasa",
+ x: 15,
+ y: 15,
+ angle: 0,
+ } as const;
+
+ beforeEach(() => {
+ container = API.createElement({ ...containerProps });
+ text = API.createElement({ ...textProps });
+ });
+
+ it("should rebind bindings when both are updated through the history and there no conflicting updates in the meantime", async () => {
+ // Initialize the scene
+ excalidrawAPI.updateScene({
+ elements: [container, text],
+ });
+
+ // Simulate local update
+ excalidrawAPI.updateScene({
+ elements: [
+ newElementWith(h.elements[0], {
+ boundElements: [{ id: text.id, type: "text" }],
+ }),
+ newElementWith(h.elements[1] as ExcalidrawTextElement, {
+ containerId: container.id,
+ }),
+ ],
+ commitToStore: true,
+ });
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(0);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: container.id,
+ boundElements: [],
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: text.id,
+ containerId: null,
+ isDeleted: false,
+ }),
+ ]);
+
+ // Simulate remote update
+ excalidrawAPI.updateScene({
+ elements: [
+ newElementWith(h.elements[0], {
+ // no conflicting updates
+ x: h.elements[1].x + 20,
+ }),
+ newElementWith(h.elements[1] as ExcalidrawTextElement, {
+ // no conflicting updates
+ x: h.elements[1].x + 10,
+ }),
+ ],
+ });
+
+ runTwice(() => {
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: container.id,
+ boundElements: [{ id: text.id, type: "text" }],
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: text.id,
+ containerId: container.id,
+ isDeleted: false,
+ }),
+ ]);
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(0);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: container.id,
+ boundElements: [],
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: text.id,
+ containerId: null,
+ isDeleted: false,
+ }),
+ ]);
+ });
+ });
+
+ // TODO: #7348 we do rebind now, when we have bi-directional binding in history, to eliminate potential data-integrity issues, but we should consider not rebinding in the future
+ it("should rebind bindings when both are updated through the history and the container got bound to a different text in the meantime", async () => {
+ // Initialize the scene
+ excalidrawAPI.updateScene({
+ elements: [container, text],
+ });
+
+ // Simulate local update
+ excalidrawAPI.updateScene({
+ elements: [
+ newElementWith(h.elements[0], {
+ boundElements: [{ id: text.id, type: "text" }],
+ }),
+ newElementWith(h.elements[1] as ExcalidrawTextElement, {
+ containerId: container.id,
+ }),
+ ],
+ commitToStore: true,
+ });
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(0);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: container.id,
+ boundElements: [],
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: text.id,
+ containerId: null,
+ isDeleted: false,
+ }),
+ ]);
+
+ const remoteText = API.createElement({
+ type: "text",
+ text: "ola",
+ containerId: container.id,
+ });
+
+ // Simulate remote update
+ excalidrawAPI.updateScene({
+ elements: [
+ newElementWith(h.elements[0], {
+ boundElements: [{ id: remoteText.id, type: "text" }],
+ }),
+ remoteText,
+ h.elements[1],
+ ],
+ });
+
+ runTwice(() => {
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: container.id,
+ // last added was `text.id`, removing `remoteText.id`
+ boundElements: [{ id: text.id, type: "text" }],
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: remoteText.id,
+ // unbound as `remoteText.id` was removed
+ containerId: null,
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: text.id,
+ // rebound!
+ containerId: container.id,
+ isDeleted: false,
+ }),
+ ]);
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(0);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: container.id,
+ boundElements: [{ id: remoteText.id, type: "text" }],
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: remoteText.id,
+ containerId: container.id,
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: text.id,
+ containerId: null,
+ isDeleted: false,
+ }),
+ ]);
+ });
+ });
+
+ // TODO: #7348 we do rebind now, when we have bi-directional binding in history, to eliminate potential data-integrity issues, but we should consider not rebinding in the future
+ it("should rebind bindings when both are updated through the history and the text got bound to a different container in the meantime", async () => {
+ // Initialize the scene
+ excalidrawAPI.updateScene({
+ elements: [container, text],
+ });
+
+ // Simulate local update
+ excalidrawAPI.updateScene({
+ elements: [
+ newElementWith(h.elements[0], {
+ boundElements: [{ id: text.id, type: "text" }],
+ }),
+ newElementWith(h.elements[1] as ExcalidrawTextElement, {
+ containerId: container.id,
+ }),
+ ],
+ commitToStore: true,
+ });
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(0);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: container.id,
+ boundElements: [],
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: text.id,
+ containerId: null,
+ isDeleted: false,
+ }),
+ ]);
+
+ const remoteContainer = API.createElement({
+ type: "rectangle",
+ width: 50,
+ x: 100,
+ boundElements: [{ id: text.id, type: "text" }],
+ });
+
+ // Simulate remote update
+ excalidrawAPI.updateScene({
+ elements: [
+ h.elements[0],
+ newElementWith(remoteContainer, {
+ boundElements: [{ id: text.id, type: "text" }],
+ }),
+ newElementWith(h.elements[1] as ExcalidrawTextElement, {
+ containerId: remoteContainer.id,
+ }),
+ ],
+ });
+
+ runTwice(() => {
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: container.id,
+ // rebound the text as we captured the full bidirectional binding in history!
+ boundElements: [{ id: text.id, type: "text" }],
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: remoteContainer.id,
+ // previous binding got unbound, as text is no longer bound to this element
+ boundElements: [],
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: text.id,
+ // rebound!
+ containerId: container.id,
+ isDeleted: false,
+ }),
+ ]);
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(0);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: container.id,
+ // deleted binding (already during applyDelta)
+ boundElements: [],
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: remoteContainer.id,
+ // #2 due to restored binding in #1, we could rebind the remote container!
+ boundElements: [{ id: text.id, type: "text" }],
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: text.id,
+ // #1 due to applying latest changes to the history entries, we could restore this binding
+ containerId: remoteContainer.id,
+ isDeleted: false,
+ }),
+ ]);
+ });
+ });
+
+ it("should rebind remotely added bound text when it's container is added through the history", async () => {
+ // Simulate local update
+ excalidrawAPI.updateScene({
+ elements: [container],
+ commitToStore: true,
+ });
+
+ // Simulate remote update
+ excalidrawAPI.updateScene({
+ elements: [
+ newElementWith(h.elements[0], {
+ boundElements: [{ id: text.id, type: "text" }],
+ }),
+ newElementWith(text, { containerId: container.id }),
+ ],
+ });
+
+ runTwice(() => {
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(0);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ ...containerProps,
+ id: container.id,
+ // binding from deleted to non deleted is correct!
+ // so that we could restore the bindings on history actions (subsequent redo in this case)
+ boundElements: [{ id: text.id, type: "text" }],
+ isDeleted: true,
+ }),
+ expect.objectContaining({
+ ...textProps,
+ id: text.id,
+ // we trigger unbind - binding from non deleted to deleted cannot exist!
+ containerId: null,
+ isDeleted: false,
+ }),
+ ]);
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ ...containerProps,
+ id: container.id,
+ boundElements: [{ id: text.id, type: "text" }],
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ ...textProps,
+ id: text.id,
+ // we triggered rebind!
+ containerId: container.id,
+ isDeleted: false,
+ }),
+ ]);
+ });
+ });
+
+ it("should rebind remotely added container when it's bound text is added through the history", async () => {
+ // Simulate local update
+ excalidrawAPI.updateScene({
+ elements: [text],
+ commitToStore: true,
+ });
+
+ // Simulate remote update
+ excalidrawAPI.updateScene({
+ elements: [
+ newElementWith(container, {
+ boundElements: [{ id: text.id, type: "text" }],
+ }),
+ newElementWith(text, { containerId: container.id }),
+ ],
+ });
+
+ runTwice(() => {
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(0);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ ...containerProps,
+ id: container.id,
+ // we trigged unbind - bindings from non deleted to deleted cannot exist!
+ boundElements: [],
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ ...textProps,
+ // binding from deleted to non deleted is correct, so that we could restore the bindings on history actions
+ containerId: container.id,
+ id: text.id,
+ isDeleted: true,
+ }),
+ ]);
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ ...containerProps,
+ id: container.id,
+ // we triggered rebind!
+ boundElements: [{ id: text.id, type: "text" }],
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ ...textProps,
+ containerId: container.id,
+ id: text.id,
+ isDeleted: false,
+ }),
+ ]);
+ });
+ });
+
+ it("should preserve latest remotely added binding and unbind previous one when the container is added through the history", async () => {
+ // Simulate local update
+ excalidrawAPI.updateScene({
+ elements: [container],
+ commitToStore: true,
+ });
+
+ // Simulate remote update
+ excalidrawAPI.updateScene({
+ elements: [
+ newElementWith(h.elements[0], {
+ boundElements: [{ id: text.id, type: "text" }],
+ }),
+ newElementWith(text, {
+ containerId: container.id,
+ }),
+ ],
+ });
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(0);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: container.id,
+ boundElements: [{ id: text.id, type: "text" }],
+ isDeleted: true,
+ }),
+ expect.objectContaining({
+ id: text.id,
+ // unbound!
+ containerId: null,
+ isDeleted: false,
+ }),
+ ]);
+
+ const remoteText = API.createElement({
+ type: "text",
+ text: "ola",
+ containerId: container.id,
+ });
+
+ // Simulate remote update
+ excalidrawAPI.updateScene({
+ elements: [
+ newElementWith(h.elements[0], {
+ boundElements: [{ id: remoteText.id, type: "text" }],
+ isDeleted: false, // purposefully undeleting, mimicing concurrenct update
+ }),
+ h.elements[1],
+ // rebinding the container with a new text element!
+ remoteText,
+ ],
+ });
+
+ runTwice(() => {
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: container.id,
+ // previously bound text is preserved
+ // text bindings are not duplicated
+ boundElements: [{ id: remoteText.id, type: "text" }],
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: text.id,
+ // unbound
+ containerId: null,
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: remoteText.id,
+ // preserved existing binding!
+ containerId: container.id,
+ isDeleted: false,
+ }),
+ ]);
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(0);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: container.id,
+ boundElements: [{ id: remoteText.id, type: "text" }],
+ isDeleted: false, // isDeleted got remotely updated to false
+ }),
+ expect.objectContaining({
+ id: text.id,
+ containerId: null,
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: remoteText.id,
+ // unbound
+ containerId: container.id,
+ isDeleted: false,
+ }),
+ ]);
+ });
+ });
+
+ it("should preserve latest remotely added binding and unbind previous one when the text is added through history", async () => {
+ // Simulate local update
+ excalidrawAPI.updateScene({
+ elements: [text],
+ commitToStore: true,
+ });
+
+ // Simulate remote update
+ excalidrawAPI.updateScene({
+ elements: [
+ newElementWith(container, {
+ boundElements: [{ id: text.id, type: "text" }],
+ }),
+ newElementWith(h.elements[0] as ExcalidrawTextElement, {
+ containerId: container.id,
+ }),
+ ],
+ });
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(0);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: container.id,
+ // unbind affected bindable element
+ boundElements: [],
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: text.id,
+ containerId: container.id,
+ isDeleted: true,
+ }),
+ ]);
+
+ const remoteText = API.createElement({
+ type: "text",
+ text: "ola",
+ containerId: container.id,
+ });
+
+ // Simulate remote update
+ excalidrawAPI.updateScene({
+ elements: [
+ newElementWith(h.elements[0], {
+ boundElements: [{ id: remoteText.id, type: "text" }],
+ }),
+ h.elements[1],
+ newElementWith(remoteText as ExcalidrawTextElement, {
+ containerId: container.id,
+ }),
+ ],
+ });
+
+ runTwice(() => {
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: container.id,
+ // previously bound text is preserved
+ // text bindings are not duplicated
+ boundElements: [{ id: remoteText.id, type: "text" }],
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: text.id,
+ // unbound from container!
+ containerId: null,
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: remoteText.id,
+ // preserved existing binding!
+ containerId: container.id,
+ isDeleted: false,
+ }),
+ ]);
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(0);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: container.id,
+ boundElements: [{ id: remoteText.id, type: "text" }],
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: text.id,
+ containerId: container.id,
+ isDeleted: true,
+ }),
+ expect.objectContaining({
+ id: remoteText.id,
+ containerId: container.id,
+ isDeleted: false,
+ }),
+ ]);
+ });
+ });
+
+ it("should unbind remotely deleted bound text from container when the container is added through the history", async () => {
+ // Simulate local update
+ excalidrawAPI.updateScene({
+ elements: [container],
+ commitToStore: true,
+ });
+
+ // Simulate remote update
+ excalidrawAPI.updateScene({
+ elements: [
+ newElementWith(h.elements[0], {
+ boundElements: [{ id: text.id, type: "text" }],
+ }),
+ newElementWith(text, {
+ containerId: container.id,
+ isDeleted: true,
+ }),
+ ],
+ });
+
+ runTwice(() => {
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(0);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: container.id,
+ boundElements: [{ id: text.id, type: "text" }],
+ isDeleted: true,
+ }),
+ expect.objectContaining({
+ id: text.id,
+ containerId: container.id,
+ isDeleted: true,
+ }),
+ ]);
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: container.id,
+ // unbound!
+ boundElements: [],
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: text.id,
+ containerId: container.id,
+ isDeleted: true,
+ }),
+ ]);
+ });
+ });
+
+ it("should unbind remotely deleted container from bound text when the text is added through the history", async () => {
+ // Simulate local update
+ excalidrawAPI.updateScene({
+ elements: [text],
+ commitToStore: true,
+ });
+
+ // Simulate remote update
+ excalidrawAPI.updateScene({
+ elements: [
+ newElementWith(container, {
+ boundElements: [{ id: text.id, type: "text" }],
+ isDeleted: true,
+ }),
+ newElementWith(h.elements[0] as ExcalidrawTextElement, {
+ containerId: container.id,
+ }),
+ ],
+ });
+
+ runTwice(() => {
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(0);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: container.id,
+ boundElements: [{ id: text.id, type: "text" }],
+ isDeleted: true,
+ }),
+ expect.objectContaining({
+ id: text.id,
+ containerId: container.id,
+ isDeleted: true,
+ }),
+ ]);
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: container.id,
+ boundElements: [{ id: text.id, type: "text" }],
+ isDeleted: true,
+ }),
+ expect.objectContaining({
+ id: text.id,
+ // unbound!
+ containerId: null,
+ isDeleted: false,
+ }),
+ ]);
+ });
+ });
+
+ it("should redraw remotely added bound text when it's container is updated through the history", async () => {
+ // Initialize the scene
+ excalidrawAPI.updateScene({
+ elements: [container],
+ });
+
+ // Simulate local update
+ excalidrawAPI.updateScene({
+ elements: [
+ newElementWith(h.elements[0], {
+ x: 200,
+ y: 200,
+ angle: 90,
+ }),
+ ],
+ commitToStore: true,
+ });
+
+ Keyboard.undo();
+
+ // Simulate remote update
+ excalidrawAPI.updateScene({
+ elements: [
+ newElementWith(h.elements[0], {
+ boundElements: [{ id: text.id, type: "text" }],
+ }),
+ newElementWith(text, { containerId: container.id }),
+ ],
+ });
+
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ ...containerProps,
+ id: container.id,
+ boundElements: [{ id: text.id, type: "text" }],
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ ...textProps,
+ id: text.id,
+ containerId: container.id,
+ isDeleted: false,
+ }),
+ ]);
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ ...containerProps,
+ x: 200,
+ y: 200,
+ angle: 90,
+ id: container.id,
+ boundElements: [{ id: text.id, type: "text" }],
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ ...textProps,
+ // text element got redrawn!
+ x: 205,
+ y: 205,
+ angle: 90,
+ id: text.id,
+ containerId: container.id,
+ isDeleted: false,
+ }),
+ ]);
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(0);
+ expect(API.getRedoStack().length).toBe(1);
+ // both elements got redrawn!
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ ...containerProps,
+ id: container.id,
+ boundElements: [{ id: text.id, type: "text" }],
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ ...textProps,
+ id: text.id,
+ containerId: container.id,
+ isDeleted: false,
+ }),
+ ]);
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(0);
+ // both elements got redrawn!
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ ...containerProps,
+ x: 200,
+ y: 200,
+ angle: 90,
+ id: container.id,
+ boundElements: [{ id: text.id, type: "text" }],
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ ...textProps,
+ x: 205,
+ y: 205,
+ angle: 90,
+ id: text.id,
+ containerId: container.id,
+ isDeleted: false,
+ }),
+ ]);
+ });
+
+ // TODO: #7348 this leads to empty undo/redo and could be confusing - instead we might consider redrawing container based on the text dimensions
+ it("should redraw bound text to match container dimensions when the bound text is updated through the history", async () => {
+ // Initialize the scene
+ excalidrawAPI.updateScene({
+ elements: [text],
+ });
+
+ // Simulate local update
+ excalidrawAPI.updateScene({
+ elements: [
+ newElementWith(h.elements[0], {
+ x: 205,
+ y: 205,
+ angle: 90,
+ }),
+ ],
+ commitToStore: true,
+ });
+
+ Keyboard.undo();
+
+ // Simulate remote update
+ excalidrawAPI.updateScene({
+ elements: [
+ newElementWith(container, {
+ boundElements: [{ id: text.id, type: "text" }],
+ }),
+ newElementWith(h.elements[0] as ExcalidrawTextElement, {
+ containerId: container.id,
+ }),
+ ],
+ });
+
+ expect(API.getUndoStack().length).toBe(0);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ ...containerProps,
+ id: container.id,
+ boundElements: [{ id: text.id, type: "text" }],
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ ...textProps,
+ id: text.id,
+ containerId: container.id,
+ isDeleted: false,
+ }),
+ ]);
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ ...containerProps,
+ id: container.id,
+ boundElements: [{ id: text.id, type: "text" }],
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ ...textProps,
+ // bound text got redrawn, as redraw is triggered based on container positon!
+ id: text.id,
+ containerId: container.id,
+ isDeleted: false,
+ }),
+ ]);
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(0);
+ expect(API.getRedoStack().length).toBe(1);
+ // both elements got redrawn!
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ ...containerProps,
+ id: container.id,
+ boundElements: [{ id: text.id, type: "text" }],
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ ...textProps,
+ id: text.id,
+ containerId: container.id,
+ isDeleted: false,
+ }),
+ ]);
+ });
+ });
+
+ describe("conflicts in arrows and their bindable elements", () => {
+ let rect1: ExcalidrawGenericElement;
+ let rect2: ExcalidrawGenericElement;
+
+ const rect1Props = {
+ type: "rectangle",
+ height: 100,
+ width: 100,
+ x: -100,
+ y: -50,
+ } as const;
+
+ const rect2Props = {
+ type: "rectangle",
+ height: 100,
+ width: 100,
+ x: 100,
+ y: -50,
+ } as const;
+
+ function roundToNearestHundred(number: number) {
+ return Math.round(number / 100) * 100;
+ }
+
+ beforeEach(() => {
+ rect1 = API.createElement({ ...rect1Props });
+ rect2 = API.createElement({ ...rect2Props });
+
+ // Simulate local update
+ excalidrawAPI.updateScene({
+ elements: [rect1, rect2],
+ commitToStore: true,
+ });
+
+ mouse.reset();
+ });
+
+ it("should rebind bindings when both are updated through the history and there are no conflicting updates in the meantime", async () => {
+ // create arrow without bindings
+ Keyboard.withModifierKeys({ ctrl: true }, () => {
+ UI.clickTool("arrow");
+ mouse.down(0, 0);
+ mouse.up(100, 0);
+ });
+
+ const arrowId = h.elements[2].id;
+
+ // create binding
+ mouse.downAt(0, 0);
+ mouse.moveTo(0, 1);
+ mouse.moveTo(0, 0);
+ mouse.up();
+
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: rect1.id,
+ boundElements: [{ id: arrowId, type: "arrow" }],
+ }),
+ expect.objectContaining({
+ id: rect2.id,
+ boundElements: [{ id: arrowId, type: "arrow" }],
+ }),
+ expect.objectContaining({
+ id: arrowId,
+ startBinding: {
+ elementId: rect1.id,
+ focus: expect.toBeNonNaNNumber(),
+ gap: expect.toBeNonNaNNumber(),
+ },
+ endBinding: {
+ elementId: rect2.id,
+ focus: expect.toBeNonNaNNumber(),
+ gap: expect.toBeNonNaNNumber(),
+ },
+ }),
+ ]);
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(2);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: rect1.id,
+ boundElements: [],
+ }),
+ expect.objectContaining({ id: rect2.id, boundElements: [] }),
+ expect.objectContaining({
+ id: arrowId,
+ startBinding: null,
+ endBinding: null,
+ }),
+ ]);
+
+ // Simulate remote update
+ excalidrawAPI.updateScene({
+ elements: [
+ newElementWith(h.elements[0], {
+ // no conflicting updates
+ x: h.elements[1].x + 50,
+ }),
+ newElementWith(h.elements[1], {
+ // no conflicting updates
+ x: h.elements[1].x + 50,
+ }),
+ newElementWith(h.elements[2], {
+ // no conflicting updates
+ x: h.elements[1].x + 50,
+ }),
+ ],
+ });
+
+ runTwice(() => {
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(3);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: rect1.id,
+ boundElements: [{ id: arrowId, type: "arrow" }],
+ }),
+ expect.objectContaining({
+ id: rect2.id,
+ boundElements: [{ id: arrowId, type: "arrow" }],
+ }),
+ expect.objectContaining({
+ id: arrowId,
+ startBinding: {
+ elementId: rect1.id,
+ focus: expect.toBeNonNaNNumber(),
+ gap: expect.toBeNonNaNNumber(),
+ },
+ endBinding: {
+ elementId: rect2.id,
+ focus: expect.toBeNonNaNNumber(),
+ gap: expect.toBeNonNaNNumber(),
+ },
+ }),
+ ]);
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(2);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: rect1.id,
+ boundElements: [],
+ }),
+ expect.objectContaining({ id: rect2.id, boundElements: [] }),
+ expect.objectContaining({
+ id: arrowId,
+ startBinding: null,
+ endBinding: null,
+ }),
+ ]);
+ });
+ });
+
+ it("should rebind bindings when both are updated through the history and the arrow got bound to a different element in the meantime", async () => {
+ // create arrow without bindings
+ Keyboard.withModifierKeys({ ctrl: true }, () => {
+ UI.clickTool("arrow");
+ mouse.down(0, 0);
+ mouse.up(100, 0);
+ });
+
+ const arrowId = h.elements[2].id;
+
+ // create binding
+ mouse.downAt(0, 0);
+ mouse.moveTo(0, 1);
+ mouse.upAt(0, 0);
+
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: rect1.id,
+ boundElements: [{ id: arrowId, type: "arrow" }],
+ }),
+ expect.objectContaining({
+ id: rect2.id,
+ boundElements: [{ id: arrowId, type: "arrow" }],
+ }),
+ expect.objectContaining({
+ id: arrowId,
+ startBinding: {
+ elementId: rect1.id,
+ focus: expect.toBeNonNaNNumber(),
+ gap: expect.toBeNonNaNNumber(),
+ },
+ endBinding: {
+ elementId: rect2.id,
+ focus: expect.toBeNonNaNNumber(),
+ gap: expect.toBeNonNaNNumber(),
+ },
+ }),
+ ]);
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(2);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: rect1.id,
+ boundElements: [],
+ }),
+ expect.objectContaining({ id: rect2.id, boundElements: [] }),
+ expect.objectContaining({
+ id: arrowId,
+ startBinding: null,
+ endBinding: null,
+ }),
+ ]);
+
+ const remoteContainer = API.createElement({
+ type: "rectangle",
+ width: 50,
+ x: 100,
+ boundElements: [{ id: arrowId, type: "arrow" }],
+ });
+
+ // Simulate remote update
+ excalidrawAPI.updateScene({
+ elements: [
+ h.elements[0],
+ newElementWith(h.elements[1], { boundElements: [] }),
+ newElementWith(h.elements[2] as ExcalidrawLinearElement, {
+ endBinding: { elementId: remoteContainer.id, gap: 1, focus: 0 },
+ }),
+ remoteContainer,
+ ],
+ });
+
+ runTwice(() => {
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(3);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: rect1.id,
+ boundElements: [{ id: arrowId, type: "arrow" }],
+ }),
+ expect.objectContaining({
+ id: rect2.id,
+ boundElements: [{ id: arrowId, type: "arrow" }],
+ }),
+ expect.objectContaining({
+ id: arrowId,
+ startBinding: {
+ elementId: rect1.id,
+ focus: expect.toBeNonNaNNumber(),
+ gap: expect.toBeNonNaNNumber(),
+ },
+ // rebound with previous rectangle
+ endBinding: {
+ elementId: rect2.id,
+ focus: expect.toBeNonNaNNumber(),
+ gap: expect.toBeNonNaNNumber(),
+ },
+ }),
+ expect.objectContaining({
+ id: remoteContainer.id,
+ boundElements: [],
+ }),
+ ]);
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(2);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: rect1.id,
+ boundElements: [],
+ }),
+ expect.objectContaining({
+ id: rect2.id,
+ boundElements: [],
+ }),
+ expect.objectContaining({
+ id: arrowId,
+ startBinding: null,
+ endBinding: {
+ // now we are back in the previous state!
+ elementId: remoteContainer.id,
+ focus: expect.toBeNonNaNNumber(),
+ gap: expect.toBeNonNaNNumber(),
+ },
+ }),
+ expect.objectContaining({
+ id: remoteContainer.id,
+ // leaving as bound until we can rebind arrows!
+ boundElements: [{ id: arrowId, type: "arrow" }],
+ }),
+ ]);
+ });
+ });
+
+ it("should rebind remotely added arrow when it's bindable elements are added through the history", async () => {
+ const arrow = API.createElement({
+ type: "arrow",
+ startBinding: { elementId: rect1.id, gap: 1, focus: 0 },
+ endBinding: { elementId: rect2.id, gap: 1, focus: 0 },
+ });
+
+ // Simulate remote update
+ excalidrawAPI.updateScene({
+ elements: [
+ arrow,
+ newElementWith(h.elements[0], {
+ boundElements: [{ id: arrow.id, type: "arrow" }],
+ }),
+ newElementWith(h.elements[1], {
+ boundElements: [{ id: arrow.id, type: "arrow" }],
+ }),
+ ],
+ });
+
+ runTwice(() => {
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(0);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: arrow.id,
+ startBinding: null,
+ endBinding: null,
+ }),
+ expect.objectContaining({
+ id: rect1.id,
+ boundElements: [{ id: arrow.id, type: "arrow" }],
+ isDeleted: true,
+ }),
+ expect.objectContaining({
+ id: rect2.id,
+ boundElements: [{ id: arrow.id, type: "arrow" }],
+ isDeleted: true,
+ }),
+ ]);
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: arrow.id,
+ startBinding: {
+ // now we are back in the previous state!
+ elementId: rect1.id,
+ focus: expect.toBeNonNaNNumber(),
+ gap: expect.toBeNonNaNNumber(),
+ },
+ endBinding: {
+ // now we are back in the previous state!
+ elementId: rect2.id,
+ focus: expect.toBeNonNaNNumber(),
+ gap: expect.toBeNonNaNNumber(),
+ },
+ }),
+ expect.objectContaining({
+ id: rect1.id,
+ boundElements: [{ id: arrow.id, type: "arrow" }],
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: rect2.id,
+ boundElements: [{ id: arrow.id, type: "arrow" }],
+ isDeleted: false,
+ }),
+ ]);
+ });
+ });
+
+ it("should rebind remotely added bindable elements when it's arrow is added through the history", async () => {
+ Keyboard.undo();
+ const arrow = API.createElement({
+ type: "arrow",
+ });
+
+ // Simulate local update
+ excalidrawAPI.updateScene({ elements: [arrow], commitToStore: true });
+
+ // Simulate remote update
+ excalidrawAPI.updateScene({
+ elements: [
+ newElementWith(h.elements[0] as ExcalidrawLinearElement, {
+ startBinding: { elementId: rect1.id, gap: 1, focus: 0 },
+ endBinding: { elementId: rect2.id, gap: 1, focus: 0 },
+ }),
+ newElementWith(rect1, {
+ boundElements: [{ id: arrow.id, type: "arrow" }],
+ }),
+ newElementWith(rect2, {
+ boundElements: [{ id: arrow.id, type: "arrow" }],
+ }),
+ ],
+ });
+
+ runTwice(() => {
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(0);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: arrow.id,
+ startBinding: {
+ elementId: rect1.id,
+ focus: expect.toBeNonNaNNumber(),
+ gap: expect.toBeNonNaNNumber(),
+ },
+ endBinding: {
+ elementId: rect2.id,
+ focus: expect.toBeNonNaNNumber(),
+ gap: expect.toBeNonNaNNumber(),
+ },
+ isDeleted: true,
+ }),
+ expect.objectContaining({
+ id: rect1.id,
+ boundElements: [],
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: rect2.id,
+ boundElements: [],
+ isDeleted: false,
+ }),
+ ]);
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: arrow.id,
+ startBinding: {
+ elementId: rect1.id,
+ focus: expect.toBeNonNaNNumber(),
+ gap: expect.toBeNonNaNNumber(),
+ },
+ endBinding: {
+ elementId: rect2.id,
+ focus: expect.toBeNonNaNNumber(),
+ gap: expect.toBeNonNaNNumber(),
+ },
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: rect1.id,
+ boundElements: [{ id: arrow.id, type: "arrow" }],
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: rect2.id,
+ boundElements: [{ id: arrow.id, type: "arrow" }],
+ isDeleted: false,
+ }),
+ ]);
+ });
+ });
+
+ it("should unbind remotely deleted bindable elements from arrow when the arrow is added through the history", async () => {});
+
+ it("should update bound element points when rectangle was remotely moved and arrow is added back through the history", async () => {
+ // bind arrow to rect1 and rect2
+ UI.clickTool("arrow");
+ mouse.down(0, 0);
+ mouse.up(100, 0);
+
+ const arrowId = h.elements[2].id;
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: rect1.id,
+ boundElements: [],
+ }),
+ expect.objectContaining({ id: rect2.id, boundElements: [] }),
+ expect.objectContaining({
+ id: arrowId,
+ points: [
+ [0, 0],
+ [100, 0],
+ ],
+ startBinding: {
+ elementId: rect1.id,
+ focus: expect.toBeNonNaNNumber(),
+ gap: expect.toBeNonNaNNumber(),
+ },
+ endBinding: {
+ elementId: rect2.id,
+ focus: expect.toBeNonNaNNumber(),
+ gap: expect.toBeNonNaNNumber(),
+ },
+ isDeleted: true,
+ }),
+ ]);
+
+ // Simulate remote update
+ excalidrawAPI.updateScene({
+ elements: [
+ h.elements[0],
+ newElementWith(h.elements[1], { x: 500, y: -500 }),
+ h.elements[2],
+ ],
+ });
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(2);
+ expect(API.getRedoStack().length).toBe(0);
+ {
+ // no need to be strict about points, hence the rounding
+ const points = (h.elements[2] as ExcalidrawLinearElement).points[1];
+ expect([
+ roundToNearestHundred(points[0]),
+ roundToNearestHundred(points[1]),
+ ]).toEqual([500, -400]);
+ }
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: rect1.id,
+ boundElements: [{ id: arrowId, type: "arrow" }],
+ }),
+ expect.objectContaining({
+ id: rect2.id,
+ boundElements: [{ id: arrowId, type: "arrow" }],
+ }),
+ expect.objectContaining({
+ id: arrowId,
+ startBinding: {
+ elementId: rect1.id,
+ focus: expect.toBeNonNaNNumber(),
+ gap: expect.toBeNonNaNNumber(),
+ },
+ endBinding: {
+ elementId: rect2.id,
+ focus: expect.toBeNonNaNNumber(),
+ gap: expect.toBeNonNaNNumber(),
+ },
+ isDeleted: false,
+ }),
+ ]);
+ });
+ });
+
+ describe("conflicts in frames and their children", () => {
+ let frame: ExcalidrawFrameElement;
+ let rect: ExcalidrawGenericElement;
+
+ const frameProps = {
+ type: "frame",
+ x: 0,
+ width: 500,
+ } as const;
+
+ const rectProps = {
+ type: "rectangle",
+ width: 100,
+ x: 10,
+ y: 10,
+ angle: 0,
+ } as const;
+
+ beforeEach(() => {
+ frame = API.createElement({ ...frameProps });
+ rect = API.createElement({ ...rectProps });
+ });
+
+ it("should not rebind frame child with frame when frame was remotely deleted and frame child is added back through the history ", async () => {
+ // Initialize the scene
+ excalidrawAPI.updateScene({
+ elements: [frame],
+ });
+
+ // Simulate local update
+ excalidrawAPI.updateScene({
+ elements: [rect, h.elements[0]],
+ commitToStore: true,
+ });
+
+ // Simulate local update
+ excalidrawAPI.updateScene({
+ elements: [
+ newElementWith(h.elements[0], {
+ frameId: frame.id,
+ }),
+ h.elements[1],
+ ],
+ commitToStore: true,
+ });
+
+ Keyboard.undo();
+ expect(API.getUndoStack().length).toBe(1);
+ expect(API.getRedoStack().length).toBe(1);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: rect.id,
+ frameId: null,
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: frame.id,
+ isDeleted: false,
+ }),
+ ]);
+
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(2);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: rect.id,
+ frameId: frame.id, // double check that the element is rebound
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: frame.id,
+ isDeleted: false,
+ }),
+ ]);
+
+ Keyboard.undo();
+ Keyboard.undo();
+
+ // Simulate remote update
+ excalidrawAPI.updateScene({
+ elements: [
+ h.elements[0],
+ newElementWith(h.elements[1], {
+ isDeleted: true,
+ }),
+ ],
+ });
+
+ Keyboard.redo();
+ Keyboard.redo();
+ expect(API.getUndoStack().length).toBe(2);
+ expect(API.getRedoStack().length).toBe(0);
+ expect(h.elements).toEqual([
+ expect.objectContaining({
+ id: rect.id,
+ frameId: null, // element is not unbound from
+ isDeleted: false,
+ }),
+ expect.objectContaining({
+ id: frame.id,
+ isDeleted: true,
+ }),
+ ]);
+ });
+ });
});
});
diff --git a/packages/excalidraw/tests/move.test.tsx b/packages/excalidraw/tests/move.test.tsx
index 8a0e562bea..dfa365d325 100644
--- a/packages/excalidraw/tests/move.test.tsx
+++ b/packages/excalidraw/tests/move.test.tsx
@@ -77,30 +77,30 @@ describe("move element", () => {
// create elements
const rectA = UI.createElement("rectangle", { size: 100 });
const rectB = UI.createElement("rectangle", { x: 200, y: 0, size: 300 });
- const line = UI.createElement("line", { x: 110, y: 50, size: 80 });
+ const arrow = UI.createElement("arrow", { x: 110, y: 50, size: 80 });
const elementsMap = h.app.scene.getNonDeletedElementsMap();
// bind line to two rectangles
bindOrUnbindLinearElement(
- line.get() as NonDeleted,
+ arrow.get() as NonDeleted,
rectA.get() as ExcalidrawRectangleElement,
rectB.get() as ExcalidrawRectangleElement,
elementsMap,
);
- // select the second rectangles
+ // select the second rectangle
new Pointer("mouse").clickOn(rectB);
expect(renderInteractiveScene.mock.calls.length).toMatchInlineSnapshot(
- `21`,
+ `20`,
);
- expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`19`);
+ expect(renderStaticScene.mock.calls.length).toMatchInlineSnapshot(`17`);
expect(h.state.selectionElement).toBeNull();
expect(h.elements.length).toEqual(3);
expect(h.state.selectedElementIds[rectB.id]).toBeTruthy();
expect([rectA.x, rectA.y]).toEqual([0, 0]);
expect([rectB.x, rectB.y]).toEqual([200, 0]);
- expect([line.x, line.y]).toEqual([110, 50]);
- expect([line.width, line.height]).toEqual([80, 80]);
+ expect([arrow.x, arrow.y]).toEqual([110, 50]);
+ expect([arrow.width, arrow.height]).toEqual([80, 80]);
renderInteractiveScene.mockClear();
renderStaticScene.mockClear();
@@ -118,8 +118,10 @@ describe("move element", () => {
expect(h.state.selectedElementIds[rectB.id]).toBeTruthy();
expect([rectA.x, rectA.y]).toEqual([0, 0]);
expect([rectB.x, rectB.y]).toEqual([201, 2]);
- expect([Math.round(line.x), Math.round(line.y)]).toEqual([110, 50]);
- expect([Math.round(line.width), Math.round(line.height)]).toEqual([81, 81]);
+ expect([Math.round(arrow.x), Math.round(arrow.y)]).toEqual([110, 50]);
+ expect([Math.round(arrow.width), Math.round(arrow.height)]).toEqual([
+ 81, 81,
+ ]);
h.elements.forEach((element) => expect(element).toMatchSnapshot());
});
diff --git a/packages/excalidraw/tests/regressionTests.test.tsx b/packages/excalidraw/tests/regressionTests.test.tsx
index f7103a8f7b..e9d6b58bf6 100644
--- a/packages/excalidraw/tests/regressionTests.test.tsx
+++ b/packages/excalidraw/tests/regressionTests.test.tsx
@@ -35,7 +35,7 @@ const checkpoint = (name: string) => {
`[${name}] number of renders`,
);
expect(h.state).toMatchSnapshot(`[${name}] appState`);
- expect(h.history.getSnapshotForTest()).toMatchSnapshot(`[${name}] history`);
+ expect(h.history).toMatchSnapshot(`[${name}] history`);
expect(h.elements.length).toMatchSnapshot(`[${name}] number of elements`);
h.elements.forEach((element, i) =>
expect(element).toMatchSnapshot(`[${name}] element ${i}`),
@@ -359,6 +359,7 @@ describe("regression tests", () => {
Keyboard.withModifierKeys({ ctrl: true }, () => {
Keyboard.keyPress(KEYS.Z);
Keyboard.keyPress(KEYS.Z);
+ Keyboard.keyPress(KEYS.Z);
});
expect(h.elements.filter((element) => !element.isDeleted).length).toBe(2);
Keyboard.withModifierKeys({ ctrl: true }, () => {
@@ -372,7 +373,7 @@ describe("regression tests", () => {
});
it("noop interaction after undo shouldn't create history entry", () => {
- expect(API.getStateHistory().length).toBe(1);
+ expect(API.getUndoStack().length).toBe(0);
UI.clickTool("rectangle");
mouse.down(10, 10);
@@ -386,35 +387,35 @@ describe("regression tests", () => {
const secondElementEndPoint = mouse.getPosition();
- expect(API.getStateHistory().length).toBe(3);
+ expect(API.getUndoStack().length).toBe(2);
Keyboard.withModifierKeys({ ctrl: true }, () => {
Keyboard.keyPress(KEYS.Z);
});
- expect(API.getStateHistory().length).toBe(2);
+ expect(API.getUndoStack().length).toBe(1);
// clicking an element shouldn't add to history
mouse.restorePosition(...firstElementEndPoint);
mouse.click();
- expect(API.getStateHistory().length).toBe(2);
+ expect(API.getUndoStack().length).toBe(1);
Keyboard.withModifierKeys({ shift: true, ctrl: true }, () => {
Keyboard.keyPress(KEYS.Z);
});
- expect(API.getStateHistory().length).toBe(3);
+ expect(API.getUndoStack().length).toBe(2);
- // clicking an element shouldn't add to history
+ // clicking an element should add to history
mouse.click();
- expect(API.getStateHistory().length).toBe(3);
+ expect(API.getUndoStack().length).toBe(3);
const firstSelectedElementId = API.getSelectedElement().id;
// same for clicking the element just redo-ed
mouse.restorePosition(...secondElementEndPoint);
mouse.click();
- expect(API.getStateHistory().length).toBe(3);
+ expect(API.getUndoStack().length).toBe(4);
expect(API.getSelectedElement().id).not.toEqual(firstSelectedElementId);
});
diff --git a/packages/excalidraw/types.ts b/packages/excalidraw/types.ts
index e7cfed7403..6f1eeebac9 100644
--- a/packages/excalidraw/types.ts
+++ b/packages/excalidraw/types.ts
@@ -199,6 +199,24 @@ export type InteractiveCanvasAppState = Readonly<
}
>;
+export type ObservedAppState = ObservedStandaloneAppState &
+ ObservedElementsAppState;
+
+export type ObservedStandaloneAppState = {
+ name: AppState["name"];
+ viewBackgroundColor: AppState["viewBackgroundColor"];
+};
+
+export type ObservedElementsAppState = {
+ editingGroupId: AppState["editingGroupId"];
+ selectedElementIds: AppState["selectedElementIds"];
+ selectedGroupIds: AppState["selectedGroupIds"];
+ // Avoiding storing whole instance, as it could lead into state incosistencies, empty undos/redos and etc.
+ editingLinearElementId: LinearElementEditor["elementId"] | null;
+ // Right now it's coupled to `editingLinearElement`, ideally it should not be really needed as we already have selectedElementIds & editingLinearElementId
+ selectedLinearElementId: LinearElementEditor["elementId"] | null;
+};
+
export interface AppState {
contextMenu: {
items: ContextMenuItems;
@@ -489,7 +507,7 @@ export type SceneData = {
elements?: ImportedDataState["elements"];
appState?: ImportedDataState["appState"];
collaborators?: Map;
- commitToHistory?: boolean;
+ commitToStore?: boolean;
};
export enum UserIdleState {
diff --git a/packages/excalidraw/utils.ts b/packages/excalidraw/utils.ts
index 88a89a68bf..203a8c3f04 100644
--- a/packages/excalidraw/utils.ts
+++ b/packages/excalidraw/utils.ts
@@ -671,6 +671,18 @@ export const arrayToMapWithIndex = (
return acc;
}, new Map());
+/**
+ * Transform array into an object, use only when array order is irrelevant.
+ */
+export const arrayToObject = (
+ array: readonly T[],
+ groupBy?: (value: T) => string,
+) =>
+ array.reduce((acc, value) => {
+ acc[groupBy ? groupBy(value) : String(value)] = value;
+ return acc;
+ }, {} as { [key: string]: T });
+
export const isTestEnv = () => import.meta.env.MODE === "test";
export const isDevEnv = () => import.meta.env.MODE === "development";