chore: Remove editingLinearElement (#9771)

Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>
This commit is contained in:
Márk Tolmács
2025-07-24 17:02:21 +02:00
committed by GitHub
parent 416da62138
commit d6a934ed19
25 changed files with 348 additions and 398 deletions

View File

@ -9,7 +9,7 @@ import {
} from "@excalidraw/excalidraw/renderer/helpers";
import { type AppState } from "@excalidraw/excalidraw/types";
import { throttleRAF } from "@excalidraw/common";
import { useCallback, useImperativeHandle, useRef } from "react";
import { useCallback } from "react";
import {
isLineSegment,
@ -18,6 +18,8 @@ import {
} from "@excalidraw/math";
import { isCurve } from "@excalidraw/math/curve";
import React from "react";
import type { Curve } from "@excalidraw/math";
import type { DebugElement } from "@excalidraw/utils/visualdebug";
@ -113,10 +115,6 @@ const _debugRenderer = (
scale,
);
if (appState.height !== canvas.height || appState.width !== canvas.width) {
refresh();
}
const context = bootstrapCanvas({
canvas,
scale,
@ -314,35 +312,29 @@ export const DebugFooter = ({ onChange }: { onChange: () => void }) => {
interface DebugCanvasProps {
appState: AppState;
scale: number;
ref?: React.Ref<HTMLCanvasElement>;
}
const DebugCanvas = ({ appState, scale, ref }: DebugCanvasProps) => {
const { width, height } = appState;
const DebugCanvas = React.forwardRef<HTMLCanvasElement, DebugCanvasProps>(
({ appState, scale }, ref) => {
const { width, height } = appState;
const canvasRef = useRef<HTMLCanvasElement>(null);
useImperativeHandle<HTMLCanvasElement | null, HTMLCanvasElement | null>(
ref,
() => canvasRef.current,
[canvasRef],
);
return (
<canvas
style={{
width,
height,
position: "absolute",
zIndex: 2,
pointerEvents: "none",
}}
width={width * scale}
height={height * scale}
ref={canvasRef}
>
Debug Canvas
</canvas>
);
};
return (
<canvas
style={{
width,
height,
position: "absolute",
zIndex: 2,
pointerEvents: "none",
}}
width={width * scale}
height={height * scale}
ref={ref}
>
Debug Canvas
</canvas>
);
},
);
export default DebugCanvas;

View File

@ -2,6 +2,7 @@ import {
arrayToMap,
arrayToObject,
assertNever,
invariant,
isDevEnv,
isShallowEqual,
isTestEnv,
@ -548,7 +549,7 @@ export class AppStateDelta implements DeltaContainer<AppState> {
selectedElementIds: addedSelectedElementIds = {},
selectedGroupIds: addedSelectedGroupIds = {},
selectedLinearElementId,
editingLinearElementId,
selectedLinearElementIsEditing,
...directlyApplicablePartial
} = this.delta.inserted;
@ -564,39 +565,46 @@ export class AppStateDelta implements DeltaContainer<AppState> {
removedSelectedGroupIds,
);
const selectedLinearElement =
selectedLinearElementId && nextElements.has(selectedLinearElementId)
? new LinearElementEditor(
nextElements.get(
selectedLinearElementId,
) as NonDeleted<ExcalidrawLinearElement>,
nextElements,
)
: null;
let selectedLinearElement = appState.selectedLinearElement;
const editingLinearElement =
editingLinearElementId && nextElements.has(editingLinearElementId)
? new LinearElementEditor(
nextElements.get(
editingLinearElementId,
) as NonDeleted<ExcalidrawLinearElement>,
nextElements,
)
: null;
if (selectedLinearElementId === null) {
// Unselect linear element (visible change)
selectedLinearElement = null;
} else if (
selectedLinearElementId &&
nextElements.has(selectedLinearElementId)
) {
selectedLinearElement = new LinearElementEditor(
nextElements.get(
selectedLinearElementId,
) as NonDeleted<ExcalidrawLinearElement>,
nextElements,
selectedLinearElementIsEditing === true, // Can be unknown which is defaulted to false
);
}
if (
// Value being 'null' is equivaluent to unknown in this case because it only gets set
// to null when 'selectedLinearElementId' is set to null
selectedLinearElementIsEditing != null
) {
invariant(
selectedLinearElement,
`selectedLinearElement is null when selectedLinearElementIsEditing is set to ${selectedLinearElementIsEditing}`,
);
selectedLinearElement = {
...selectedLinearElement,
isEditing: selectedLinearElementIsEditing,
};
}
const nextAppState = {
...appState,
...directlyApplicablePartial,
selectedElementIds: mergedSelectedElementIds,
selectedGroupIds: mergedSelectedGroupIds,
selectedLinearElement:
typeof selectedLinearElementId !== "undefined"
? selectedLinearElement // element was either inserted or deleted
: appState.selectedLinearElement, // otherwise assign what we had before
editingLinearElement:
typeof editingLinearElementId !== "undefined"
? editingLinearElement // element was either inserted or deleted
: appState.editingLinearElement, // otherwise assign what we had before
selectedLinearElement,
};
const constainsVisibleChanges = this.filterInvisibleChanges(
@ -725,8 +733,7 @@ export class AppStateDelta implements DeltaContainer<AppState> {
}
break;
case "selectedLinearElementId":
case "editingLinearElementId":
case "selectedLinearElementId": {
const appStateKey = AppStateDelta.convertToAppStateKey(key);
const linearElement = nextAppState[appStateKey];
@ -746,6 +753,19 @@ export class AppStateDelta implements DeltaContainer<AppState> {
}
break;
}
case "selectedLinearElementIsEditing": {
// Changes in editing state are always visible
const prevIsEditing =
prevAppState.selectedLinearElement?.isEditing ?? false;
const nextIsEditing =
nextAppState.selectedLinearElement?.isEditing ?? false;
if (prevIsEditing !== nextIsEditing) {
visibleDifferenceFlag.value = true;
}
break;
}
case "lockedMultiSelections": {
const prevLockedUnits = prevAppState[key] || {};
const nextLockedUnits = nextAppState[key] || {};
@ -779,16 +799,11 @@ export class AppStateDelta implements DeltaContainer<AppState> {
}
private static convertToAppStateKey(
key: keyof Pick<
ObservedElementsAppState,
"selectedLinearElementId" | "editingLinearElementId"
>,
): keyof Pick<AppState, "selectedLinearElement" | "editingLinearElement"> {
key: keyof Pick<ObservedElementsAppState, "selectedLinearElementId">,
): keyof Pick<AppState, "selectedLinearElement"> {
switch (key) {
case "selectedLinearElementId":
return "selectedLinearElement";
case "editingLinearElementId":
return "editingLinearElement";
}
}
@ -856,8 +871,8 @@ export class AppStateDelta implements DeltaContainer<AppState> {
editingGroupId,
selectedGroupIds,
selectedElementIds,
editingLinearElementId,
selectedLinearElementId,
selectedLinearElementIsEditing,
croppingElementId,
lockedMultiSelections,
activeLockedId,

View File

@ -149,10 +149,12 @@ export class LinearElementEditor {
public readonly segmentMidPointHoveredCoords: GlobalPoint | null;
public readonly elbowed: boolean;
public readonly customLineAngle: number | null;
public readonly isEditing: boolean;
constructor(
element: NonDeleted<ExcalidrawLinearElement>,
elementsMap: ElementsMap,
isEditing: boolean = false,
) {
this.elementId = element.id as string & {
_brand: "excalidrawLinearElementId";
@ -187,6 +189,7 @@ export class LinearElementEditor {
this.segmentMidPointHoveredCoords = null;
this.elbowed = isElbowArrow(element) && element.elbowed;
this.customLineAngle = null;
this.isEditing = isEditing;
}
// ---------------------------------------------------------------------------
@ -194,6 +197,7 @@ export class LinearElementEditor {
// ---------------------------------------------------------------------------
static POINT_HANDLE_SIZE = 10;
/**
* @param id the `elementId` from the instance of this class (so that we can
* statically guarantee this method returns an ExcalidrawLinearElement)
@ -215,11 +219,14 @@ export class LinearElementEditor {
setState: React.Component<any, AppState>["setState"],
elementsMap: NonDeletedSceneElementsMap,
) {
if (!appState.editingLinearElement || !appState.selectionElement) {
if (
!appState.selectedLinearElement?.isEditing ||
!appState.selectionElement
) {
return false;
}
const { editingLinearElement } = appState;
const { selectedPointsIndices, elementId } = editingLinearElement;
const { selectedLinearElement } = appState;
const { selectedPointsIndices, elementId } = selectedLinearElement;
const element = LinearElementEditor.getElement(elementId, elementsMap);
if (!element) {
@ -260,8 +267,8 @@ export class LinearElementEditor {
});
setState({
editingLinearElement: {
...editingLinearElement,
selectedLinearElement: {
...selectedLinearElement,
selectedPointsIndices: nextSelectedPoints.length
? nextSelectedPoints
: null,
@ -479,9 +486,6 @@ export class LinearElementEditor {
return {
...app.state,
editingLinearElement: app.state.editingLinearElement
? newLinearElementEditor
: null,
selectedLinearElement: newLinearElementEditor,
suggestedBindings,
};
@ -618,7 +622,7 @@ export class LinearElementEditor {
// Since its not needed outside editor unless 2 pointer lines or bound text
if (
!isElbowArrow(element) &&
!appState.editingLinearElement &&
!appState.selectedLinearElement?.isEditing &&
element.points.length > 2 &&
!boundText
) {
@ -684,7 +688,7 @@ export class LinearElementEditor {
);
if (
points.length >= 3 &&
!appState.editingLinearElement &&
!appState.selectedLinearElement?.isEditing &&
!isElbowArrow(element)
) {
return null;
@ -881,7 +885,7 @@ export class LinearElementEditor {
segmentMidpoint,
elementsMap,
);
} else if (event.altKey && appState.editingLinearElement) {
} else if (event.altKey && appState.selectedLinearElement?.isEditing) {
if (linearElementEditor.lastUncommittedPoint == null) {
scene.mutateElement(element, {
points: [
@ -1023,14 +1027,14 @@ export class LinearElementEditor {
app: AppClassProperties,
): LinearElementEditor | null {
const appState = app.state;
if (!appState.editingLinearElement) {
if (!appState.selectedLinearElement?.isEditing) {
return null;
}
const { elementId, lastUncommittedPoint } = appState.editingLinearElement;
const { elementId, lastUncommittedPoint } = appState.selectedLinearElement;
const elementsMap = app.scene.getNonDeletedElementsMap();
const element = LinearElementEditor.getElement(elementId, elementsMap);
if (!element) {
return appState.editingLinearElement;
return appState.selectedLinearElement;
}
const { points } = element;
@ -1040,12 +1044,12 @@ export class LinearElementEditor {
if (lastPoint === lastUncommittedPoint) {
LinearElementEditor.deletePoints(element, app, [points.length - 1]);
}
return appState.editingLinearElement.lastUncommittedPoint
return appState.selectedLinearElement?.lastUncommittedPoint
? {
...appState.editingLinearElement,
...appState.selectedLinearElement,
lastUncommittedPoint: null,
}
: appState.editingLinearElement;
: appState.selectedLinearElement;
}
let newPoint: LocalPoint;
@ -1069,8 +1073,8 @@ export class LinearElementEditor {
newPoint = LinearElementEditor.createPointAt(
element,
elementsMap,
scenePointerX - appState.editingLinearElement.pointerOffset.x,
scenePointerY - appState.editingLinearElement.pointerOffset.y,
scenePointerX - appState.selectedLinearElement.pointerOffset.x,
scenePointerY - appState.selectedLinearElement.pointerOffset.y,
event[KEYS.CTRL_OR_CMD] || isElbowArrow(element)
? null
: app.getEffectiveGridSize(),
@ -1094,7 +1098,7 @@ export class LinearElementEditor {
LinearElementEditor.addPoints(element, app.scene, [newPoint]);
}
return {
...appState.editingLinearElement,
...appState.selectedLinearElement,
lastUncommittedPoint: element.points[element.points.length - 1],
};
}
@ -1253,12 +1257,12 @@ export class LinearElementEditor {
// ---------------------------------------------------------------------------
static duplicateSelectedPoints(appState: AppState, scene: Scene): AppState {
invariant(
appState.editingLinearElement,
appState.selectedLinearElement?.isEditing,
"Not currently editing a linear element",
);
const elementsMap = scene.getNonDeletedElementsMap();
const { selectedPointsIndices, elementId } = appState.editingLinearElement;
const { selectedPointsIndices, elementId } = appState.selectedLinearElement;
const element = LinearElementEditor.getElement(elementId, elementsMap);
invariant(
@ -1320,8 +1324,8 @@ export class LinearElementEditor {
return {
...appState,
editingLinearElement: {
...appState.editingLinearElement,
selectedLinearElement: {
...appState.selectedLinearElement,
selectedPointsIndices: nextSelectedIndices,
},
};
@ -1333,8 +1337,9 @@ export class LinearElementEditor {
pointIndices: readonly number[],
) {
const isUncommittedPoint =
app.state.editingLinearElement?.lastUncommittedPoint ===
element.points[element.points.length - 1];
app.state.selectedLinearElement?.isEditing &&
app.state.selectedLinearElement?.lastUncommittedPoint ===
element.points[element.points.length - 1];
const nextPoints = element.points.filter((_, idx) => {
return !pointIndices.includes(idx);
@ -1507,7 +1512,7 @@ export class LinearElementEditor {
pointFrom(pointerCoords.x, pointerCoords.y),
);
if (
!appState.editingLinearElement &&
!appState.selectedLinearElement?.isEditing &&
dist < DRAGGING_THRESHOLD / appState.zoom.value
) {
return false;

View File

@ -978,8 +978,8 @@ const getDefaultObservedAppState = (): ObservedAppState => {
viewBackgroundColor: COLOR_PALETTE.white,
selectedElementIds: {},
selectedGroupIds: {},
editingLinearElementId: null,
selectedLinearElementId: null,
selectedLinearElementIsEditing: null,
croppingElementId: null,
activeLockedId: null,
lockedMultiSelections: {},
@ -998,14 +998,14 @@ export const getObservedAppState = (
croppingElementId: appState.croppingElementId,
activeLockedId: appState.activeLockedId,
lockedMultiSelections: appState.lockedMultiSelections,
editingLinearElementId:
(appState as AppState).editingLinearElement?.elementId ?? // prefer app state, as it's likely newer
(appState as ObservedAppState).editingLinearElementId ?? // fallback to observed app state, as it's likely older coming from a previous snapshot
null,
selectedLinearElementId:
(appState as AppState).selectedLinearElement?.elementId ??
(appState as ObservedAppState).selectedLinearElementId ??
null,
selectedLinearElementIsEditing:
(appState as AppState).selectedLinearElement?.isEditing ??
(appState as ObservedAppState).selectedLinearElementIsEditing ??
null,
};
Reflect.defineProperty(observedAppState, hiddenObservedAppStateProp, {

View File

@ -330,7 +330,7 @@ export const shouldShowBoundingBox = (
elements: readonly NonDeletedExcalidrawElement[],
appState: InteractiveCanvasAppState,
) => {
if (appState.editingLinearElement) {
if (appState.selectedLinearElement?.isEditing) {
return false;
}
if (elements.length > 1) {

View File

@ -155,10 +155,10 @@ describe("element binding", () => {
// NOTE this mouse down/up + await needs to be done in order to repro
// the issue, due to https://github.com/excalidraw/excalidraw/blob/46bff3daceb602accf60c40a84610797260fca94/src/components/App.tsx#L740
mouse.reset();
expect(h.state.editingLinearElement).not.toBe(null);
expect(h.state.selectedLinearElement?.isEditing).toBe(true);
mouse.down(0, 0);
await new Promise((r) => setTimeout(r, 100));
expect(h.state.editingLinearElement).toBe(null);
expect(h.state.selectedLinearElement?.isEditing).toBe(false);
expect(API.getSelectedElement().type).toBe("rectangle");
mouse.up();
expect(API.getSelectedElement().type).toBe("rectangle");

View File

@ -16,6 +16,7 @@ describe("AppStateDelta", () => {
editingGroupId: null,
croppingElementId: null,
editingLinearElementId: null,
selectedLinearElementIsEditing: null,
lockedMultiSelections: {},
activeLockedId: null,
};
@ -58,6 +59,7 @@ describe("AppStateDelta", () => {
editingGroupId: null,
croppingElementId: null,
selectedLinearElementId: null,
selectedLinearElementIsEditing: null,
editingLinearElementId: null,
activeLockedId: null,
lockedMultiSelections: {},
@ -105,6 +107,7 @@ describe("AppStateDelta", () => {
editingGroupId: null,
croppingElementId: null,
selectedLinearElementId: null,
selectedLinearElementIsEditing: null,
editingLinearElementId: null,
activeLockedId: null,
lockedMultiSelections: {},

View File

@ -136,7 +136,8 @@ describe("Test Linear Elements", () => {
Keyboard.withModifierKeys({ ctrl: true }, () => {
Keyboard.keyPress(KEYS.ENTER);
});
expect(h.state.editingLinearElement?.elementId).toEqual(line.id);
expect(h.state.selectedLinearElement?.isEditing).toBe(true);
expect(h.state.selectedLinearElement?.elementId).toEqual(line.id);
};
const drag = (startPoint: GlobalPoint, endPoint: GlobalPoint) => {
@ -253,75 +254,82 @@ describe("Test Linear Elements", () => {
});
fireEvent.click(queryByText(contextMenu as HTMLElement, "Edit line")!);
expect(h.state.editingLinearElement?.elementId).toEqual(h.elements[0].id);
expect(h.state.selectedLinearElement?.isEditing).toBe(true);
expect(h.state.selectedLinearElement?.elementId).toEqual(h.elements[0].id);
});
it("should enter line editor via enter (line)", () => {
createTwoPointerLinearElement("line");
expect(h.state.editingLinearElement?.elementId).toBeUndefined();
expect(h.state.selectedLinearElement?.isEditing).toBe(false);
mouse.clickAt(midpoint[0], midpoint[1]);
Keyboard.keyPress(KEYS.ENTER);
expect(h.state.editingLinearElement?.elementId).toEqual(h.elements[0].id);
expect(h.state.selectedLinearElement?.isEditing).toBe(true);
expect(h.state.selectedLinearElement?.elementId).toEqual(h.elements[0].id);
});
// ctrl+enter alias (to align with arrows)
it("should enter line editor via ctrl+enter (line)", () => {
createTwoPointerLinearElement("line");
expect(h.state.editingLinearElement?.elementId).toBeUndefined();
expect(h.state.selectedLinearElement?.isEditing).toBe(false);
mouse.clickAt(midpoint[0], midpoint[1]);
Keyboard.withModifierKeys({ ctrl: true }, () => {
Keyboard.keyPress(KEYS.ENTER);
});
expect(h.state.editingLinearElement?.elementId).toEqual(h.elements[0].id);
expect(h.state.selectedLinearElement?.isEditing).toBe(true);
expect(h.state.selectedLinearElement?.elementId).toEqual(h.elements[0].id);
});
it("should enter line editor via ctrl+enter (arrow)", () => {
createTwoPointerLinearElement("arrow");
expect(h.state.editingLinearElement?.elementId).toBeUndefined();
expect(h.state.selectedLinearElement?.isEditing).toBe(false);
mouse.clickAt(midpoint[0], midpoint[1]);
Keyboard.withModifierKeys({ ctrl: true }, () => {
Keyboard.keyPress(KEYS.ENTER);
});
expect(h.state.editingLinearElement?.elementId).toEqual(h.elements[0].id);
expect(h.state.selectedLinearElement?.isEditing).toBe(true);
expect(h.state.selectedLinearElement?.elementId).toEqual(h.elements[0].id);
});
it("should enter line editor on ctrl+dblclick (simple arrow)", () => {
createTwoPointerLinearElement("arrow");
expect(h.state.editingLinearElement?.elementId).toBeUndefined();
expect(h.state.selectedLinearElement?.isEditing).toBe(false);
Keyboard.withModifierKeys({ ctrl: true }, () => {
mouse.doubleClick();
});
expect(h.state.editingLinearElement?.elementId).toEqual(h.elements[0].id);
expect(h.state.selectedLinearElement?.isEditing).toBe(true);
expect(h.state.selectedLinearElement?.elementId).toEqual(h.elements[0].id);
});
it("should enter line editor on ctrl+dblclick (line)", () => {
createTwoPointerLinearElement("line");
expect(h.state.editingLinearElement?.elementId).toBeUndefined();
expect(h.state.selectedLinearElement?.isEditing).toBe(false);
Keyboard.withModifierKeys({ ctrl: true }, () => {
mouse.doubleClick();
});
expect(h.state.editingLinearElement?.elementId).toEqual(h.elements[0].id);
expect(h.state.selectedLinearElement?.isEditing).toBe(true);
expect(h.state.selectedLinearElement?.elementId).toEqual(h.elements[0].id);
});
it("should enter line editor on dblclick (line)", () => {
createTwoPointerLinearElement("line");
expect(h.state.editingLinearElement?.elementId).toBeUndefined();
expect(h.state.selectedLinearElement?.isEditing).toBe(false);
mouse.doubleClick();
expect(h.state.editingLinearElement?.elementId).toEqual(h.elements[0].id);
expect(h.state.selectedLinearElement?.isEditing).toBe(true);
expect(h.state.selectedLinearElement?.elementId).toEqual(h.elements[0].id);
});
it("should not enter line editor on dblclick (arrow)", async () => {
createTwoPointerLinearElement("arrow");
expect(h.state.editingLinearElement?.elementId).toBeUndefined();
expect(h.state.selectedLinearElement?.isEditing).toBe(false);
mouse.doubleClick();
expect(h.state.editingLinearElement).toEqual(null);
expect(h.state.selectedLinearElement).toBe(null);
await getTextEditor();
});
@ -330,10 +338,12 @@ describe("Test Linear Elements", () => {
const arrow = h.elements[0] as ExcalidrawLinearElement;
enterLineEditingMode(arrow);
expect(h.state.editingLinearElement?.elementId).toEqual(arrow.id);
expect(h.state.selectedLinearElement?.isEditing).toBe(true);
expect(h.state.selectedLinearElement?.elementId).toEqual(arrow.id);
mouse.doubleClick();
expect(h.state.editingLinearElement?.elementId).toEqual(arrow.id);
expect(h.state.selectedLinearElement?.isEditing).toBe(true);
expect(h.state.selectedLinearElement?.elementId).toEqual(arrow.id);
expect(h.elements.length).toEqual(1);
expect(document.querySelector(TEXT_EDITOR_SELECTOR)).toBe(null);

View File

@ -205,16 +205,19 @@ export const actionDeleteSelected = register({
icon: TrashIcon,
trackEvent: { category: "element", action: "delete" },
perform: (elements, appState, formData, app) => {
if (appState.editingLinearElement) {
if (appState.selectedLinearElement?.isEditing) {
const {
elementId,
selectedPointsIndices,
startBindingElement,
endBindingElement,
} = appState.editingLinearElement;
} = appState.selectedLinearElement;
const elementsMap = app.scene.getNonDeletedElementsMap();
const element = LinearElementEditor.getElement(elementId, elementsMap);
if (!element) {
const linearElement = LinearElementEditor.getElement(
elementId,
elementsMap,
);
if (!linearElement) {
return false;
}
// case: no point selected → do nothing, as deleting the whole element
@ -226,12 +229,9 @@ export const actionDeleteSelected = register({
}
// case: deleting all points
if (
element.points.length < 2 ||
selectedPointsIndices.length === element.points.length
) {
if (selectedPointsIndices.length >= linearElement.points.length) {
const nextElements = elements.map((el) => {
if (el.id === element.id) {
if (el.id === linearElement.id) {
return newElementWith(el, { isDeleted: true });
}
return el;
@ -242,7 +242,7 @@ export const actionDeleteSelected = register({
elements: nextElements,
appState: {
...nextAppState,
editingLinearElement: null,
selectedLinearElement: null,
},
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
@ -255,20 +255,24 @@ export const actionDeleteSelected = register({
? null
: startBindingElement,
endBindingElement: selectedPointsIndices?.includes(
element.points.length - 1,
linearElement.points.length - 1,
)
? null
: endBindingElement,
};
LinearElementEditor.deletePoints(element, app, selectedPointsIndices);
LinearElementEditor.deletePoints(
linearElement,
app,
selectedPointsIndices,
);
return {
elements,
appState: {
...appState,
editingLinearElement: {
...appState.editingLinearElement,
selectedLinearElement: {
...appState.selectedLinearElement,
...binding,
selectedPointsIndices:
selectedPointsIndices?.[0] > 0

View File

@ -39,7 +39,7 @@ export const actionDuplicateSelection = register({
}
// duplicate selected point(s) if editing a line
if (appState.editingLinearElement) {
if (appState.selectedLinearElement?.isEditing) {
// TODO: Invariants should be checked here instead of duplicateSelectedPoints()
try {
const newAppState = LinearElementEditor.duplicateSelectedPoints(

View File

@ -94,9 +94,9 @@ export const actionFinalize = register({
}
}
if (appState.editingLinearElement) {
if (appState.selectedLinearElement?.isEditing) {
const { elementId, startBindingElement, endBindingElement } =
appState.editingLinearElement;
appState.selectedLinearElement;
const element = LinearElementEditor.getElement(elementId, elementsMap);
if (element) {
@ -122,7 +122,11 @@ export const actionFinalize = register({
appState: {
...appState,
cursorButton: "up",
editingLinearElement: null,
selectedLinearElement: new LinearElementEditor(
element,
arrayToMap(elementsMap),
false, // exit editing mode
),
},
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
@ -285,7 +289,7 @@ export const actionFinalize = register({
},
keyTest: (event, appState) =>
(event.key === KEYS.ESCAPE &&
(appState.editingLinearElement !== null ||
(appState.selectedLinearElement?.isEditing ||
(!appState.newElement && appState.multiElement === null))) ||
((event.key === KEYS.ESCAPE || event.key === KEYS.ENTER) &&
appState.multiElement !== null),

View File

@ -1,10 +1,9 @@
import { LinearElementEditor } from "@excalidraw/element";
import {
isElbowArrow,
isLinearElement,
isLineElement,
} from "@excalidraw/element";
import { arrayToMap } from "@excalidraw/common";
import { arrayToMap, invariant } from "@excalidraw/common";
import {
toggleLinePolygonState,
@ -46,7 +45,7 @@ export const actionToggleLinearEditor = register({
predicate: (elements, appState, _, app) => {
const selectedElements = app.scene.getSelectedElements(appState);
if (
!appState.editingLinearElement &&
!appState.selectedLinearElement?.isEditing &&
selectedElements.length === 1 &&
isLinearElement(selectedElements[0]) &&
!isElbowArrow(selectedElements[0])
@ -61,14 +60,25 @@ export const actionToggleLinearEditor = register({
includeBoundTextElement: true,
})[0] as ExcalidrawLinearElement;
const editingLinearElement =
appState.editingLinearElement?.elementId === selectedElement.id
? null
: new LinearElementEditor(selectedElement, arrayToMap(elements));
invariant(selectedElement, "No selected element found");
invariant(
appState.selectedLinearElement,
"No selected linear element found",
);
invariant(
selectedElement.id === appState.selectedLinearElement.elementId,
"Selected element ID and linear editor elementId does not match",
);
const selectedLinearElement = {
...appState.selectedLinearElement,
isEditing: !appState.selectedLinearElement.isEditing,
};
return {
appState: {
...appState,
editingLinearElement,
selectedLinearElement,
},
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};

View File

@ -21,7 +21,7 @@ export const actionSelectAll = register({
trackEvent: { category: "canvas" },
viewMode: false,
perform: (elements, appState, value, app) => {
if (appState.editingLinearElement) {
if (appState.selectedLinearElement?.isEditing) {
return false;
}

View File

@ -48,7 +48,6 @@ export const getDefaultAppState = (): Omit<
newElement: null,
editingTextElement: null,
editingGroupId: null,
editingLinearElement: null,
activeTool: {
type: "selection",
customType: null,
@ -175,7 +174,6 @@ const APP_STATE_STORAGE_CONF = (<
newElement: { browser: false, export: false, server: false },
editingTextElement: { browser: false, export: false, server: false },
editingGroupId: { browser: true, export: false, server: false },
editingLinearElement: { browser: false, export: false, server: false },
activeTool: { browser: true, export: false, server: false },
penMode: { browser: true, export: false, server: false },
penDetected: { browser: true, export: false, server: false },

View File

@ -140,7 +140,7 @@ export const SelectedShapeActions = ({
targetElements.length === 1 || isSingleElementBoundContainer;
const showLineEditorAction =
!appState.editingLinearElement &&
!appState.selectedLinearElement?.isEditing &&
targetElements.length === 1 &&
isLinearElement(targetElements[0]) &&
!isElbowArrow(targetElements[0]);

View File

@ -2158,9 +2158,14 @@ class App extends React.Component<AppProps, AppState> {
public dismissLinearEditor = () => {
setTimeout(() => {
this.setState({
editingLinearElement: null,
});
if (this.state.selectedLinearElement?.isEditing) {
this.setState({
selectedLinearElement: {
...this.state.selectedLinearElement,
isEditing: false,
},
});
}
});
};
@ -2856,15 +2861,15 @@ class App extends React.Component<AppProps, AppState> {
);
if (
this.state.editingLinearElement &&
!this.state.selectedElementIds[this.state.editingLinearElement.elementId]
this.state.selectedLinearElement?.isEditing &&
!this.state.selectedElementIds[this.state.selectedLinearElement.elementId]
) {
// defer so that the scheduleCapture flag isn't reset via current update
setTimeout(() => {
// execute only if the condition still holds when the deferred callback
// executes (it can be scheduled multiple times depending on how
// many times the component renders)
this.state.editingLinearElement &&
this.state.selectedLinearElement?.isEditing &&
this.actionManager.executeAction(actionFinalize);
});
}
@ -4419,17 +4424,13 @@ class App extends React.Component<AppProps, AppState> {
if (event[KEYS.CTRL_OR_CMD] || isLineElement(selectedElement)) {
if (isLinearElement(selectedElement)) {
if (
!this.state.editingLinearElement ||
this.state.editingLinearElement.elementId !== selectedElement.id
!this.state.selectedLinearElement?.isEditing ||
this.state.selectedLinearElement.elementId !==
selectedElement.id
) {
this.store.scheduleCapture();
if (!isElbowArrow(selectedElement)) {
this.setState({
editingLinearElement: new LinearElementEditor(
selectedElement,
this.scene.getNonDeletedElementsMap(),
),
});
this.actionManager.executeAction(actionToggleLinearEditor);
}
}
}
@ -5432,15 +5433,12 @@ class App extends React.Component<AppProps, AppState> {
if (
((event[KEYS.CTRL_OR_CMD] && isSimpleArrow(selectedLinearElement)) ||
isLineElement(selectedLinearElement)) &&
this.state.editingLinearElement?.elementId !== selectedLinearElement.id
(!this.state.selectedLinearElement?.isEditing ||
this.state.selectedLinearElement.elementId !==
selectedLinearElement.id)
) {
this.store.scheduleCapture();
this.setState({
editingLinearElement: new LinearElementEditor(
selectedLinearElement,
this.scene.getNonDeletedElementsMap(),
),
});
// Use the proper action to ensure immediate history capture
this.actionManager.executeAction(actionToggleLinearEditor);
return;
} else if (
this.state.selectedLinearElement &&
@ -5505,8 +5503,8 @@ class App extends React.Component<AppProps, AppState> {
return;
}
} else if (
this.state.editingLinearElement &&
this.state.editingLinearElement.elementId ===
this.state.selectedLinearElement?.isEditing &&
this.state.selectedLinearElement.elementId ===
selectedLinearElement.id &&
isLineElement(selectedLinearElement)
) {
@ -5561,7 +5559,7 @@ class App extends React.Component<AppProps, AppState> {
// shouldn't edit/create text when inside line editor (often false positive)
if (!this.state.editingLinearElement) {
if (!this.state.selectedLinearElement?.isEditing) {
const container = this.getTextBindableContainerAtPosition(
sceneX,
sceneY,
@ -5859,8 +5857,8 @@ class App extends React.Component<AppProps, AppState> {
}
if (
this.state.editingLinearElement &&
!this.state.editingLinearElement.isDragging
this.state.selectedLinearElement?.isEditing &&
!this.state.selectedLinearElement.isDragging
) {
const editingLinearElement = LinearElementEditor.handlePointerMove(
event,
@ -5874,14 +5872,14 @@ class App extends React.Component<AppProps, AppState> {
if (
editingLinearElement &&
editingLinearElement !== this.state.editingLinearElement
editingLinearElement !== this.state.selectedLinearElement
) {
// Since we are reading from previous state which is not possible with
// automatic batching in React 18 hence using flush sync to synchronously
// update the state. Check https://github.com/excalidraw/excalidraw/pull/5508 for more details.
flushSync(() => {
this.setState({
editingLinearElement,
selectedLinearElement: editingLinearElement,
});
});
}
@ -6041,7 +6039,7 @@ class App extends React.Component<AppProps, AppState> {
if (
selectedElements.length === 1 &&
!isOverScrollBar &&
!this.state.editingLinearElement
!this.state.selectedLinearElement?.isEditing
) {
// for linear elements, we'd like to prioritize point dragging over edge resizing
// therefore, we update and check hovered point index first
@ -7045,7 +7043,7 @@ class App extends React.Component<AppProps, AppState> {
if (
selectedElements.length === 1 &&
!this.state.editingLinearElement &&
!this.state.selectedLinearElement?.isEditing &&
!isElbowArrow(selectedElements[0]) &&
!(
this.state.selectedLinearElement &&
@ -7116,8 +7114,7 @@ class App extends React.Component<AppProps, AppState> {
}
} else {
if (this.state.selectedLinearElement) {
const linearElementEditor =
this.state.editingLinearElement || this.state.selectedLinearElement;
const linearElementEditor = this.state.selectedLinearElement;
const ret = LinearElementEditor.handlePointerDown(
event,
this,
@ -7131,10 +7128,6 @@ class App extends React.Component<AppProps, AppState> {
}
if (ret.linearElementEditor) {
this.setState({ selectedLinearElement: ret.linearElementEditor });
if (this.state.editingLinearElement) {
this.setState({ editingLinearElement: ret.linearElementEditor });
}
}
if (ret.didAddPoint) {
return true;
@ -7235,11 +7228,11 @@ class App extends React.Component<AppProps, AppState> {
this.clearSelection(hitElement);
}
if (this.state.editingLinearElement) {
if (this.state.selectedLinearElement?.isEditing) {
this.setState({
selectedElementIds: makeNextSelectedElementIds(
{
[this.state.editingLinearElement.elementId]: true,
[this.state.selectedLinearElement.elementId]: true,
},
this.state,
),
@ -8182,8 +8175,7 @@ class App extends React.Component<AppProps, AppState> {
const elementsMap = this.scene.getNonDeletedElementsMap();
if (this.state.selectedLinearElement) {
const linearElementEditor =
this.state.editingLinearElement || this.state.selectedLinearElement;
const linearElementEditor = this.state.selectedLinearElement;
if (
LinearElementEditor.shouldAddMidpoint(
@ -8219,16 +8211,6 @@ class App extends React.Component<AppProps, AppState> {
},
});
}
if (this.state.editingLinearElement) {
this.setState({
editingLinearElement: {
...this.state.editingLinearElement,
pointerDownState: ret.pointerDownState,
selectedPointsIndices: ret.selectedPointsIndices,
segmentMidPointHoveredCoords: null,
},
});
}
});
return;
@ -8262,9 +8244,9 @@ class App extends React.Component<AppProps, AppState> {
);
const isSelectingPointsInLineEditor =
this.state.editingLinearElement &&
this.state.selectedLinearElement?.isEditing &&
event.shiftKey &&
this.state.editingLinearElement.elementId ===
this.state.selectedLinearElement.elementId ===
pointerDownState.hit.element?.id;
if (
(hasHitASelectedElement ||
@ -8751,7 +8733,7 @@ class App extends React.Component<AppProps, AppState> {
const elements = this.scene.getNonDeletedElements();
// box-select line editor points
if (this.state.editingLinearElement) {
if (this.state.selectedLinearElement?.isEditing) {
LinearElementEditor.handleBoxSelection(
event,
this.state,
@ -8994,23 +8976,23 @@ class App extends React.Component<AppProps, AppState> {
// Handle end of dragging a point of a linear element, might close a loop
// and sets binding element
if (this.state.editingLinearElement) {
if (this.state.selectedLinearElement?.isEditing) {
if (
!pointerDownState.boxSelection.hasOccurred &&
pointerDownState.hit?.element?.id !==
this.state.editingLinearElement.elementId
this.state.selectedLinearElement.elementId
) {
this.actionManager.executeAction(actionFinalize);
} else {
const editingLinearElement = LinearElementEditor.handlePointerUp(
childEvent,
this.state.editingLinearElement,
this.state.selectedLinearElement,
this.state,
this.scene,
);
if (editingLinearElement !== this.state.editingLinearElement) {
if (editingLinearElement !== this.state.selectedLinearElement) {
this.setState({
editingLinearElement,
selectedLinearElement: editingLinearElement,
suggestedBindings: [],
});
}
@ -9523,14 +9505,17 @@ class App extends React.Component<AppProps, AppState> {
!pointerDownState.hit.wasAddedToSelection &&
// if we're editing a line, pointerup shouldn't switch selection if
// box selected
(!this.state.editingLinearElement ||
(!this.state.selectedLinearElement?.isEditing ||
!pointerDownState.boxSelection.hasOccurred) &&
// hitElement can be set when alt + ctrl to toggle lasso and we will
// just respect the selected elements from lasso instead
this.state.activeTool.type !== "lasso"
) {
// when inside line editor, shift selects points instead
if (childEvent.shiftKey && !this.state.editingLinearElement) {
if (
childEvent.shiftKey &&
!this.state.selectedLinearElement?.isEditing
) {
if (this.state.selectedElementIds[hitElement.id]) {
if (isSelectedViaGroup(this.state, hitElement)) {
this.setState((_prevState) => {
@ -9708,8 +9693,9 @@ class App extends React.Component<AppProps, AppState> {
(!hitElement &&
pointerDownState.hit.hasHitCommonBoundingBoxOfSelectedElements))
) {
if (this.state.editingLinearElement) {
this.setState({ editingLinearElement: null });
if (this.state.selectedLinearElement?.isEditing) {
// Exit editing mode but keep the element selected
this.actionManager.executeAction(actionToggleLinearEditor);
} else {
// Deselect selected elements
this.setState({

View File

@ -115,7 +115,7 @@ const getHints = ({
appState.selectionElement &&
!selectedElements.length &&
!appState.editingTextElement &&
!appState.editingLinearElement
!appState.selectedLinearElement?.isEditing
) {
return [t("hints.deepBoxSelect")];
}
@ -130,8 +130,8 @@ const getHints = ({
if (selectedElements.length === 1) {
if (isLinearElement(selectedElements[0])) {
if (appState.editingLinearElement) {
return appState.editingLinearElement.selectedPointsIndices
if (appState.selectedLinearElement?.isEditing) {
return appState.selectedLinearElement.selectedPointsIndices
? t("hints.lineEditor_pointSelected")
: t("hints.lineEditor_nothingSelected");
}

View File

@ -192,7 +192,6 @@ const getRelevantAppStateProps = (
viewModeEnabled: appState.viewModeEnabled,
openDialog: appState.openDialog,
editingGroupId: appState.editingGroupId,
editingLinearElement: appState.editingLinearElement,
selectedElementIds: appState.selectedElementIds,
frameToHighlight: appState.frameToHighlight,
offsetLeft: appState.offsetLeft,

View File

@ -118,7 +118,8 @@ const renderLinearElementPointHighlight = (
) => {
const { elementId, hoverPointIndex } = appState.selectedLinearElement!;
if (
appState.editingLinearElement?.selectedPointsIndices?.includes(
appState.selectedLinearElement?.isEditing &&
appState.selectedLinearElement?.selectedPointsIndices?.includes(
hoverPointIndex,
)
) {
@ -180,7 +181,7 @@ const renderSingleLinearPoint = <Point extends GlobalPoint | LocalPoint>(
point[0],
point[1],
(isOverlappingPoint
? radius * (appState.editingLinearElement ? 1.5 : 2)
? radius * (appState.selectedLinearElement?.isEditing ? 1.5 : 2)
: radius) / appState.zoom.value,
!isPhantomPoint,
!isOverlappingPoint || isSelected,
@ -448,7 +449,7 @@ const renderLinearPointHandles = (
);
const { POINT_HANDLE_SIZE } = LinearElementEditor;
const radius = appState.editingLinearElement
const radius = appState.selectedLinearElement?.isEditing
? POINT_HANDLE_SIZE
: POINT_HANDLE_SIZE / 2;
@ -470,7 +471,8 @@ const renderLinearPointHandles = (
);
let isSelected =
!!appState.editingLinearElement?.selectedPointsIndices?.includes(idx);
!!appState.selectedLinearElement?.isEditing &&
!!appState.selectedLinearElement?.selectedPointsIndices?.includes(idx);
// when element is a polygon, highlight the last point as well if first
// point is selected since they overlap and the last point tends to be
// rendered on top
@ -479,7 +481,8 @@ const renderLinearPointHandles = (
element.polygon &&
!isSelected &&
idx === element.points.length - 1 &&
!!appState.editingLinearElement?.selectedPointsIndices?.includes(0)
!!appState.selectedLinearElement?.isEditing &&
!!appState.selectedLinearElement?.selectedPointsIndices?.includes(0)
) {
isSelected = true;
}
@ -535,7 +538,7 @@ const renderLinearPointHandles = (
);
midPoints.forEach((segmentMidPoint) => {
if (appState.editingLinearElement || points.length === 2) {
if (appState.selectedLinearElement?.isEditing || points.length === 2) {
renderSingleLinearPoint(
context,
appState,
@ -760,7 +763,10 @@ const _renderInteractiveScene = ({
// Getting the element using LinearElementEditor during collab mismatches version - being one head of visible elements due to
// ShapeCache returns empty hence making sure that we get the
// correct element from visible elements
if (appState.editingLinearElement?.elementId === element.id) {
if (
appState.selectedLinearElement?.isEditing &&
appState.selectedLinearElement.elementId === element.id
) {
if (element) {
editingLinearElement = element as NonDeleted<ExcalidrawLinearElement>;
}
@ -853,7 +859,8 @@ const _renderInteractiveScene = ({
// correct element from visible elements
if (
selectedElements.length === 1 &&
appState.editingLinearElement?.elementId === selectedElements[0].id
appState.selectedLinearElement?.isEditing &&
appState.selectedLinearElement.elementId === selectedElements[0].id
) {
renderLinearPointHandles(
context,
@ -884,7 +891,7 @@ const _renderInteractiveScene = ({
}
// Paint selected elements
if (!appState.multiElement && !appState.editingLinearElement) {
if (!appState.multiElement && !appState.selectedLinearElement?.isEditing) {
const showBoundingBox = shouldShowBoundingBox(selectedElements, appState);
const isSingleLinearElementSelected =

View File

@ -908,7 +908,6 @@ exports[`contextMenu element > right-clicking on a group should select whole gro
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -1106,7 +1105,6 @@ exports[`contextMenu element > selecting 'Add to library' in context menu adds e
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -1319,7 +1317,6 @@ exports[`contextMenu element > selecting 'Bring forward' in context menu brings
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -1649,7 +1646,6 @@ exports[`contextMenu element > selecting 'Bring to front' in context menu brings
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -1979,7 +1975,6 @@ exports[`contextMenu element > selecting 'Copy styles' in context menu copies st
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -2192,7 +2187,6 @@ exports[`contextMenu element > selecting 'Delete' in context menu deletes elemen
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -2432,7 +2426,6 @@ exports[`contextMenu element > selecting 'Duplicate' in context menu duplicates
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -2729,7 +2722,6 @@ exports[`contextMenu element > selecting 'Group selection' in context menu group
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -3100,7 +3092,6 @@ exports[`contextMenu element > selecting 'Paste styles' in context menu pastes s
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -3592,7 +3583,6 @@ exports[`contextMenu element > selecting 'Send backward' in context menu sends e
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -3914,7 +3904,6 @@ exports[`contextMenu element > selecting 'Send to back' in context menu sends el
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -4236,7 +4225,6 @@ exports[`contextMenu element > selecting 'Ungroup selection' in context menu ung
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -5520,7 +5508,6 @@ exports[`contextMenu element > shows 'Group selection' in context menu for multi
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -6736,7 +6723,6 @@ exports[`contextMenu element > shows 'Ungroup selection' in context menu for gro
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -7670,7 +7656,6 @@ exports[`contextMenu element > shows context menu for canvas > [end of test] app
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -8669,7 +8654,6 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -9659,7 +9643,6 @@ exports[`contextMenu element > shows context menu for element > [end of test] ap
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,

View File

@ -34,7 +34,6 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -545,10 +544,12 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"id4": true,
},
"selectedLinearElementId": "id4",
"selectedLinearElementIsEditing": false,
},
"inserted": {
"selectedElementIds": {},
"selectedLinearElementId": null,
"selectedLinearElementIsEditing": null,
},
},
},
@ -646,7 +647,6 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -1027,10 +1027,12 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"id4": true,
},
"selectedLinearElementId": "id4",
"selectedLinearElementIsEditing": false,
},
"inserted": {
"selectedElementIds": {},
"selectedLinearElementId": null,
"selectedLinearElementIsEditing": null,
},
},
},
@ -1128,7 +1130,6 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -1491,7 +1492,6 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -1857,7 +1857,6 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -2119,7 +2118,6 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -2417,10 +2415,12 @@ exports[`history > multiplayer undo/redo > conflicts in arrows and their bindabl
"id4": true,
},
"selectedLinearElementId": "id4",
"selectedLinearElementIsEditing": false,
},
"inserted": {
"selectedElementIds": {},
"selectedLinearElementId": null,
"selectedLinearElementIsEditing": null,
},
},
},
@ -2557,7 +2557,6 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -2818,7 +2817,6 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -3083,7 +3081,6 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -3376,7 +3373,6 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -3661,7 +3657,6 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -3895,7 +3890,6 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -4151,7 +4145,6 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -4421,7 +4414,6 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -4649,7 +4641,6 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -4877,7 +4868,6 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -5103,7 +5093,6 @@ exports[`history > multiplayer undo/redo > conflicts in bound text elements and
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -5329,7 +5318,6 @@ exports[`history > multiplayer undo/redo > conflicts in frames and their childre
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -5584,7 +5572,6 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -5845,7 +5832,6 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -6207,7 +6193,6 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -6580,7 +6565,6 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -6891,7 +6875,6 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -7107,9 +7090,11 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
"delta": Delta {
"deleted": {
"selectedLinearElementId": "id0",
"selectedLinearElementIsEditing": false,
},
"inserted": {
"selectedLinearElementId": null,
"selectedLinearElementIsEditing": null,
},
},
},
@ -7118,16 +7103,16 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
"removed": {},
"updated": {},
},
"id": "id12",
"id": "id4",
},
{
"appState": AppStateDelta {
"delta": Delta {
"deleted": {
"editingLinearElementId": "id0",
"selectedLinearElementIsEditing": true,
},
"inserted": {
"editingLinearElementId": null,
"selectedLinearElementIsEditing": false,
},
},
},
@ -7136,16 +7121,16 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
"removed": {},
"updated": {},
},
"id": "id13",
"id": "id6",
},
{
"appState": AppStateDelta {
"delta": Delta {
"deleted": {
"editingLinearElementId": null,
"selectedLinearElementIsEditing": false,
},
"inserted": {
"editingLinearElementId": "id0",
"selectedLinearElementIsEditing": true,
},
},
},
@ -7154,7 +7139,7 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
"removed": {},
"updated": {},
},
"id": "id14",
"id": "id10",
},
]
`;
@ -7193,7 +7178,6 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -7390,7 +7374,6 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -7741,7 +7724,6 @@ exports[`history > multiplayer undo/redo > should iterate through the history wh
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -8092,7 +8074,6 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -8497,7 +8478,6 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -8783,7 +8763,6 @@ exports[`history > multiplayer undo/redo > should not let remote changes to inte
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -9046,7 +9025,6 @@ exports[`history > multiplayer undo/redo > should not override remote changes on
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -9310,7 +9288,6 @@ exports[`history > multiplayer undo/redo > should not override remote changes on
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -9541,7 +9518,6 @@ exports[`history > multiplayer undo/redo > should override remotely added groups
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -9837,7 +9813,6 @@ exports[`history > multiplayer undo/redo > should override remotely added points
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -10132,9 +10107,11 @@ exports[`history > multiplayer undo/redo > should override remotely added points
"delta": Delta {
"deleted": {
"selectedLinearElementId": "id0",
"selectedLinearElementIsEditing": false,
},
"inserted": {
"selectedLinearElementId": null,
"selectedLinearElementIsEditing": null,
},
},
},
@ -10182,7 +10159,6 @@ exports[`history > multiplayer undo/redo > should redistribute deltas when eleme
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -10406,7 +10382,6 @@ exports[`history > multiplayer undo/redo > should redraw arrows on undo > [end o
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -10853,7 +10828,6 @@ exports[`history > multiplayer undo/redo > should update history entries after r
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -11112,7 +11086,6 @@ exports[`history > singleplayer undo/redo > remounting undo/redo buttons should
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -11346,7 +11319,6 @@ exports[`history > singleplayer undo/redo > should clear the redo stack on eleme
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -11582,7 +11554,6 @@ exports[`history > singleplayer undo/redo > should create entry when selecting f
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -11984,7 +11955,6 @@ exports[`history > singleplayer undo/redo > should create new history entry on e
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": "Couldn't load invalid file",
@ -12193,7 +12163,6 @@ exports[`history > singleplayer undo/redo > should create new history entry on e
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -12402,7 +12371,6 @@ exports[`history > singleplayer undo/redo > should create new history entry on i
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -12625,7 +12593,6 @@ exports[`history > singleplayer undo/redo > should create new history entry on i
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -12848,7 +12815,6 @@ exports[`history > singleplayer undo/redo > should create new history entry on s
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -13092,7 +13058,6 @@ exports[`history > singleplayer undo/redo > should disable undo/redo buttons whe
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -13328,7 +13293,6 @@ exports[`history > singleplayer undo/redo > should end up with no history entry
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -13564,7 +13528,6 @@ exports[`history > singleplayer undo/redo > should iterate through the history w
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -13810,7 +13773,6 @@ exports[`history > singleplayer undo/redo > should not clear the redo stack on s
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -14140,7 +14102,6 @@ exports[`history > singleplayer undo/redo > should not collapse when applying co
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -14309,7 +14270,6 @@ exports[`history > singleplayer undo/redo > should not end up with history entry
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -14592,7 +14552,6 @@ exports[`history > singleplayer undo/redo > should not end up with history entry
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -14854,7 +14813,6 @@ exports[`history > singleplayer undo/redo > should not modify anything on unrela
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -15006,7 +14964,6 @@ exports[`history > singleplayer undo/redo > should not override appstate changes
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -15287,7 +15244,6 @@ exports[`history > singleplayer undo/redo > should support appstate name or view
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -15448,7 +15404,6 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -15712,10 +15667,12 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"id13": true,
},
"selectedLinearElementId": "id13",
"selectedLinearElementIsEditing": false,
},
"inserted": {
"selectedElementIds": {},
"selectedLinearElementId": null,
"selectedLinearElementIsEditing": null,
},
},
},
@ -16004,12 +15961,14 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"id13": true,
},
"selectedLinearElementId": "id13",
"selectedLinearElementIsEditing": false,
},
"inserted": {
"selectedElementIds": {
"id0": true,
},
"selectedLinearElementId": null,
"selectedLinearElementIsEditing": null,
},
},
},
@ -16146,7 +16105,6 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -16627,12 +16585,14 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"id13": true,
},
"selectedLinearElementId": "id13",
"selectedLinearElementIsEditing": false,
},
"inserted": {
"selectedElementIds": {
"id0": true,
},
"selectedLinearElementId": null,
"selectedLinearElementIsEditing": null,
},
},
},
@ -16777,7 +16737,6 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -17258,12 +17217,14 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"id13": true,
},
"selectedLinearElementId": "id13",
"selectedLinearElementIsEditing": false,
},
"inserted": {
"selectedElementIds": {
"id0": true,
},
"selectedLinearElementId": null,
"selectedLinearElementIsEditing": null,
},
},
},
@ -17408,7 +17369,6 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -17954,12 +17914,14 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"id13": true,
},
"selectedLinearElementId": "id13",
"selectedLinearElementIsEditing": false,
},
"inserted": {
"selectedElementIds": {
"id0": true,
},
"selectedLinearElementId": null,
"selectedLinearElementIsEditing": null,
},
},
},
@ -18067,12 +18029,14 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"id0": true,
},
"selectedLinearElementId": null,
"selectedLinearElementIsEditing": null,
},
"inserted": {
"selectedElementIds": {
"id13": true,
},
"selectedLinearElementId": "id13",
"selectedLinearElementIsEditing": false,
},
},
},
@ -18120,7 +18084,6 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -18678,12 +18641,14 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"id13": true,
},
"selectedLinearElementId": "id13",
"selectedLinearElementIsEditing": false,
},
"inserted": {
"selectedElementIds": {
"id0": true,
},
"selectedLinearElementId": null,
"selectedLinearElementIsEditing": null,
},
},
},
@ -18791,12 +18756,14 @@ exports[`history > singleplayer undo/redo > should support bidirectional binding
"id0": true,
},
"selectedLinearElementId": null,
"selectedLinearElementIsEditing": null,
},
"inserted": {
"selectedElementIds": {
"id13": true,
},
"selectedLinearElementId": "id13",
"selectedLinearElementIsEditing": false,
},
},
},
@ -18864,7 +18831,6 @@ exports[`history > singleplayer undo/redo > should support changes in elements'
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -19343,7 +19309,6 @@ exports[`history > singleplayer undo/redo > should support duplication of groups
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -19853,7 +19818,6 @@ exports[`history > singleplayer undo/redo > should support element creation, del
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -20311,7 +20275,6 @@ exports[`history > singleplayer undo/redo > should support linear element creati
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -20590,9 +20553,11 @@ exports[`history > singleplayer undo/redo > should support linear element creati
"delta": Delta {
"deleted": {
"selectedLinearElementId": "id0",
"selectedLinearElementIsEditing": false,
},
"inserted": {
"selectedLinearElementId": null,
"selectedLinearElementIsEditing": null,
},
},
},
@ -20607,10 +20572,10 @@ exports[`history > singleplayer undo/redo > should support linear element creati
"appState": AppStateDelta {
"delta": Delta {
"deleted": {
"editingLinearElementId": "id0",
"selectedLinearElementIsEditing": true,
},
"inserted": {
"editingLinearElementId": null,
"selectedLinearElementIsEditing": false,
},
},
},
@ -20678,10 +20643,10 @@ exports[`history > singleplayer undo/redo > should support linear element creati
"appState": AppStateDelta {
"delta": Delta {
"deleted": {
"editingLinearElementId": null,
"selectedLinearElementIsEditing": false,
},
"inserted": {
"editingLinearElementId": "id0",
"selectedLinearElementIsEditing": true,
},
},
},

View File

@ -34,7 +34,6 @@ exports[`given element A and group of elements B and given both are selected whe
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -459,7 +458,6 @@ exports[`given element A and group of elements B and given both are selected whe
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -874,7 +872,6 @@ exports[`regression tests > Cmd/Ctrl-click exclusively select element under poin
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": "id28",
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -1439,7 +1436,6 @@ exports[`regression tests > Drags selected element when hitting only bounding bo
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -1645,7 +1641,6 @@ exports[`regression tests > adjusts z order when grouping > [end of test] appSta
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -2028,7 +2023,6 @@ exports[`regression tests > alt-drag duplicates an element > [end of test] appSt
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -2272,7 +2266,6 @@ exports[`regression tests > arrow keys > [end of test] appState 1`] = `
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -2451,7 +2444,6 @@ exports[`regression tests > can drag element that covers another element, while
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -2775,7 +2767,6 @@ exports[`regression tests > change the properties of a shape > [end of test] app
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -3029,7 +3020,6 @@ exports[`regression tests > click on an element and drag it > [dragged] appState
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -3269,7 +3259,6 @@ exports[`regression tests > click on an element and drag it > [end of test] appS
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -3504,7 +3493,6 @@ exports[`regression tests > click to select a shape > [end of test] appState 1`]
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -3761,7 +3749,6 @@ exports[`regression tests > click-drag to select a group > [end of test] appStat
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -4074,7 +4061,6 @@ exports[`regression tests > deleting last but one element in editing group shoul
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -4509,7 +4495,6 @@ exports[`regression tests > deselects group of selected elements on pointer down
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -4791,7 +4776,6 @@ exports[`regression tests > deselects group of selected elements on pointer up w
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -5066,7 +5050,6 @@ exports[`regression tests > deselects selected element on pointer down when poin
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -5273,7 +5256,6 @@ exports[`regression tests > deselects selected element, on pointer up, when clic
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -5472,7 +5454,6 @@ exports[`regression tests > double click to edit a group > [end of test] appStat
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": "id11",
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -5864,7 +5845,6 @@ exports[`regression tests > drags selected elements from point inside common bou
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -6160,7 +6140,6 @@ exports[`regression tests > draw every type of shape > [end of test] appState 1`
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -6416,12 +6395,14 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
"id9": true,
},
"selectedLinearElementId": "id9",
"selectedLinearElementIsEditing": false,
},
"inserted": {
"selectedElementIds": {
"id6": true,
},
"selectedLinearElementId": null,
"selectedLinearElementIsEditing": null,
},
},
},
@ -6562,12 +6543,14 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
"id15": true,
},
"selectedLinearElementId": null,
"selectedLinearElementIsEditing": null,
},
"inserted": {
"selectedElementIds": {
"id12": true,
},
"selectedLinearElementId": "id12",
"selectedLinearElementIsEditing": false,
},
},
},
@ -6695,9 +6678,11 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
"delta": Delta {
"deleted": {
"selectedLinearElementId": "id15",
"selectedLinearElementIsEditing": false,
},
"inserted": {
"selectedLinearElementId": null,
"selectedLinearElementIsEditing": null,
},
},
},
@ -6716,12 +6701,14 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
"id22": true,
},
"selectedLinearElementId": null,
"selectedLinearElementIsEditing": null,
},
"inserted": {
"selectedElementIds": {
"id15": true,
},
"selectedLinearElementId": "id15",
"selectedLinearElementIsEditing": false,
},
},
},
@ -6847,9 +6834,11 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
"delta": Delta {
"deleted": {
"selectedLinearElementId": "id22",
"selectedLinearElementIsEditing": false,
},
"inserted": {
"selectedLinearElementId": null,
"selectedLinearElementIsEditing": null,
},
},
},
@ -6885,9 +6874,11 @@ exports[`regression tests > draw every type of shape > [end of test] undo stack
"delta": Delta {
"deleted": {
"selectedLinearElementId": null,
"selectedLinearElementIsEditing": null,
},
"inserted": {
"selectedLinearElementId": "id22",
"selectedLinearElementIsEditing": false,
},
},
},
@ -6991,7 +6982,6 @@ exports[`regression tests > given a group of selected elements with an element t
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -7324,7 +7314,6 @@ exports[`regression tests > given a selected element A and a not selected elemen
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -7602,7 +7591,6 @@ exports[`regression tests > given selected element A with lower z-index than uns
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -7836,7 +7824,6 @@ exports[`regression tests > given selected element A with lower z-index than uns
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -8075,7 +8062,6 @@ exports[`regression tests > key 2 selects rectangle tool > [end of test] appStat
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -8254,7 +8240,6 @@ exports[`regression tests > key 3 selects diamond tool > [end of test] appState
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -8433,7 +8418,6 @@ exports[`regression tests > key 4 selects ellipse tool > [end of test] appState
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -8612,7 +8596,6 @@ exports[`regression tests > key 5 selects arrow tool > [end of test] appState 1`
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -8676,6 +8659,7 @@ exports[`regression tests > key 5 selects arrow tool > [end of test] appState 1`
"endBindingElement": "keep",
"hoverPointIndex": -1,
"isDragging": false,
"isEditing": false,
"lastUncommittedPoint": null,
"pointerDownState": {
"lastClickedIsEndPoint": false,
@ -8736,10 +8720,12 @@ exports[`regression tests > key 5 selects arrow tool > [end of test] undo stack
"id0": true,
},
"selectedLinearElementId": "id0",
"selectedLinearElementIsEditing": false,
},
"inserted": {
"selectedElementIds": {},
"selectedLinearElementId": null,
"selectedLinearElementIsEditing": null,
},
},
},
@ -8837,7 +8823,6 @@ exports[`regression tests > key 6 selects line tool > [end of test] appState 1`]
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -8901,6 +8886,7 @@ exports[`regression tests > key 6 selects line tool > [end of test] appState 1`]
"endBindingElement": "keep",
"hoverPointIndex": -1,
"isDragging": false,
"isEditing": false,
"lastUncommittedPoint": null,
"pointerDownState": {
"lastClickedIsEndPoint": false,
@ -8961,10 +8947,12 @@ exports[`regression tests > key 6 selects line tool > [end of test] undo stack 1
"id0": true,
},
"selectedLinearElementId": "id0",
"selectedLinearElementIsEditing": false,
},
"inserted": {
"selectedElementIds": {},
"selectedLinearElementId": null,
"selectedLinearElementIsEditing": null,
},
},
},
@ -9060,7 +9048,6 @@ exports[`regression tests > key 7 selects freedraw tool > [end of test] appState
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -9255,7 +9242,6 @@ exports[`regression tests > key a selects arrow tool > [end of test] appState 1`
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -9319,6 +9305,7 @@ exports[`regression tests > key a selects arrow tool > [end of test] appState 1`
"endBindingElement": "keep",
"hoverPointIndex": -1,
"isDragging": false,
"isEditing": false,
"lastUncommittedPoint": null,
"pointerDownState": {
"lastClickedIsEndPoint": false,
@ -9379,10 +9366,12 @@ exports[`regression tests > key a selects arrow tool > [end of test] undo stack
"id0": true,
},
"selectedLinearElementId": "id0",
"selectedLinearElementIsEditing": false,
},
"inserted": {
"selectedElementIds": {},
"selectedLinearElementId": null,
"selectedLinearElementIsEditing": null,
},
},
},
@ -9480,7 +9469,6 @@ exports[`regression tests > key d selects diamond tool > [end of test] appState
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -9659,7 +9647,6 @@ exports[`regression tests > key l selects line tool > [end of test] appState 1`]
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -9723,6 +9710,7 @@ exports[`regression tests > key l selects line tool > [end of test] appState 1`]
"endBindingElement": "keep",
"hoverPointIndex": -1,
"isDragging": false,
"isEditing": false,
"lastUncommittedPoint": null,
"pointerDownState": {
"lastClickedIsEndPoint": false,
@ -9783,10 +9771,12 @@ exports[`regression tests > key l selects line tool > [end of test] undo stack 1
"id0": true,
},
"selectedLinearElementId": "id0",
"selectedLinearElementIsEditing": false,
},
"inserted": {
"selectedElementIds": {},
"selectedLinearElementId": null,
"selectedLinearElementIsEditing": null,
},
},
},
@ -9882,7 +9872,6 @@ exports[`regression tests > key o selects ellipse tool > [end of test] appState
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -10061,7 +10050,6 @@ exports[`regression tests > key p selects freedraw tool > [end of test] appState
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -10256,7 +10244,6 @@ exports[`regression tests > key r selects rectangle tool > [end of test] appStat
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -10435,7 +10422,6 @@ exports[`regression tests > make a group and duplicate it > [end of test] appSta
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -10965,7 +10951,6 @@ exports[`regression tests > noop interaction after undo shouldn't create history
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -11244,7 +11229,6 @@ exports[`regression tests > pinch-to-zoom works > [end of test] appState 1`] = `
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -11366,7 +11350,6 @@ exports[`regression tests > shift click on selected element should deselect it o
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -11565,7 +11548,6 @@ exports[`regression tests > shift-click to multiselect, then drag > [end of test
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -11883,7 +11865,6 @@ exports[`regression tests > should group elements and ungroup them > [end of tes
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -12311,7 +12292,6 @@ exports[`regression tests > single-clicking on a subgroup of a selected group sh
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -12950,7 +12930,6 @@ exports[`regression tests > spacebar + drag scrolls the canvas > [end of test] a
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -13075,7 +13054,6 @@ exports[`regression tests > supports nested groups > [end of test] appState 1`]
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": "id11",
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -13705,7 +13683,6 @@ exports[`regression tests > switches from group of selected elements to another
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -14043,7 +14020,6 @@ exports[`regression tests > switches selected element on pointer down > [end of
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -14306,7 +14282,6 @@ exports[`regression tests > two-finger scroll works > [end of test] appState 1`]
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -14428,7 +14403,6 @@ exports[`regression tests > undo/redo drawing an element > [end of test] appStat
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -14521,9 +14495,11 @@ exports[`regression tests > undo/redo drawing an element > [end of test] redo st
"delta": Delta {
"deleted": {
"selectedLinearElementId": null,
"selectedLinearElementIsEditing": null,
},
"inserted": {
"selectedLinearElementId": "id6",
"selectedLinearElementIsEditing": false,
},
},
},
@ -14816,7 +14792,6 @@ exports[`regression tests > updates fontSize & fontFamily appState > [end of tes
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,
@ -14938,7 +14913,6 @@ exports[`regression tests > zoom hotkeys > [end of test] appState 1`] = `
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,

View File

@ -1073,7 +1073,7 @@ describe("history", () => {
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?.isEditing ?? false).toBe(false);
expect(h.state.selectedLinearElement).not.toBeNull();
expect(h.elements).toEqual([
expect.objectContaining({
@ -1090,7 +1090,7 @@ describe("history", () => {
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?.isEditing).toBe(true);
expect(h.state.selectedLinearElement?.elementId).toBe(h.elements[0].id);
expect(h.elements).toEqual([
expect.objectContaining({
@ -1114,7 +1114,7 @@ describe("history", () => {
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?.isEditing).toBe(true);
expect(h.state.selectedLinearElement?.elementId).toBe(h.elements[0].id);
expect(h.elements).toEqual([
expect.objectContaining({
@ -1131,7 +1131,7 @@ describe("history", () => {
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?.isEditing ?? false).toBe(false); // undo `open editor`
expect(h.state.selectedLinearElement?.elementId).toBe(h.elements[0].id);
expect(h.elements).toEqual([
expect.objectContaining({
@ -1148,7 +1148,7 @@ describe("history", () => {
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?.isEditing ?? false).toBe(false);
expect(h.state.selectedLinearElement).toBeNull(); // undo `actionFinalize`
expect(h.elements).toEqual([
expect.objectContaining({
@ -1165,7 +1165,7 @@ describe("history", () => {
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?.isEditing ?? false).toBe(false);
expect(h.state.selectedLinearElement).toBeNull();
expect(h.elements).toEqual([
expect.objectContaining({
@ -1181,7 +1181,7 @@ describe("history", () => {
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?.isEditing ?? false).toBe(false);
expect(h.state.selectedLinearElement).toBeNull();
expect(h.elements).toEqual([
expect.objectContaining({
@ -1197,7 +1197,7 @@ describe("history", () => {
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?.isEditing ?? false).toBe(false);
expect(h.state.selectedLinearElement).toBeNull();
expect(h.elements).toEqual([
expect.objectContaining({
@ -1213,7 +1213,7 @@ describe("history", () => {
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?.isEditing ?? false).toBe(false);
expect(h.state.selectedLinearElement).toBeNull(); // undo `actionFinalize`
expect(h.elements).toEqual([
expect.objectContaining({
@ -1230,7 +1230,7 @@ describe("history", () => {
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?.isEditing ?? false).toBe(false); // undo `open editor`
expect(h.state.selectedLinearElement?.elementId).toBe(h.elements[0].id);
expect(h.elements).toEqual([
expect.objectContaining({
@ -1247,7 +1247,7 @@ describe("history", () => {
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?.isEditing).toBe(true);
expect(h.state.selectedLinearElement?.elementId).toBe(h.elements[0].id);
expect(h.elements).toEqual([
expect.objectContaining({
@ -1264,7 +1264,7 @@ describe("history", () => {
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?.isEditing).toBe(true);
expect(h.state.selectedLinearElement?.elementId).toBe(h.elements[0].id);
expect(h.elements).toEqual([
expect.objectContaining({
@ -1281,7 +1281,7 @@ describe("history", () => {
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?.isEditing ?? false).toBe(false);
expect(h.state.selectedLinearElement).not.toBeNull();
expect(h.elements).toEqual([
expect.objectContaining({
@ -3029,8 +3029,8 @@ describe("history", () => {
expect(API.getUndoStack().length).toBe(4);
expect(API.getRedoStack().length).toBe(0);
expect(h.state.editingLinearElement).toBeNull();
expect(h.state.selectedLinearElement).not.toBeNull();
expect(h.state.selectedLinearElement?.isEditing).toBe(false);
// Simulate remote update
API.updateScene({
@ -3043,16 +3043,16 @@ describe("history", () => {
});
Keyboard.undo();
expect(API.getUndoStack().length).toBe(1);
expect(API.getRedoStack().length).toBe(3);
expect(h.state.editingLinearElement).toBeNull();
expect(h.state.selectedLinearElement).toBeNull();
expect(API.getUndoStack().length).toBe(3);
expect(API.getRedoStack().length).toBe(1);
expect(h.state.selectedLinearElement).not.toBeNull();
expect(h.state.selectedLinearElement?.isEditing).toBe(true);
Keyboard.redo();
expect(API.getUndoStack().length).toBe(4);
expect(API.getRedoStack().length).toBe(0);
expect(h.state.editingLinearElement).toBeNull();
expect(h.state.selectedLinearElement).toBeNull();
expect(h.state.selectedLinearElement).not.toBeNull();
expect(h.state.selectedLinearElement?.isEditing ?? false).toBe(false);
});
it("should iterate through the history when z-index changes do not produce visible change and we synced changed indices", async () => {

View File

@ -213,7 +213,6 @@ export type InteractiveCanvasAppState = Readonly<
_CommonCanvasAppState & {
// renderInteractiveScene
activeEmbeddable: AppState["activeEmbeddable"];
editingLinearElement: AppState["editingLinearElement"];
selectionElement: AppState["selectionElement"];
selectedGroupIds: AppState["selectedGroupIds"];
selectedLinearElement: AppState["selectedLinearElement"];
@ -249,10 +248,8 @@ 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;
selectedLinearElementIsEditing: boolean | null;
croppingElementId: AppState["croppingElementId"];
lockedMultiSelections: AppState["lockedMultiSelections"];
activeLockedId: AppState["activeLockedId"];
@ -307,7 +304,6 @@ export interface AppState {
* set when a new text is created or when an existing text is being edited
*/
editingTextElement: NonDeletedExcalidrawElement | null;
editingLinearElement: LinearElementEditor | null;
activeTool: {
/**
* indicates a previous tool we should revert back to if we deselect the

View File

@ -34,7 +34,6 @@ exports[`exportToSvg > with default arguments 1`] = `
"defaultSidebarDockedPreference": false,
"editingFrame": null,
"editingGroupId": null,
"editingLinearElement": null,
"editingTextElement": null,
"elementsToHighlight": null,
"errorMessage": null,