
* change lock label * feat: add unlock logic for single units on pointer up * feat: add unlock popup * fix: linting errors * style: padding tweaks * style: remove redundant line * feat: lock multiple units together * style: tweak color & position * feat: add highlight for locked elements * feat: select groups correctly after unlocking * test: update snapshots * fix: lasso from selecting locked elements * fix: should prevent selecting unlocked elements and setting locked id at the same time * fix: reset hit locked id immediately when appropriate * feat: capture locked units in delta * test: update locking test * feat: show lock highlight when locking (including undo/redo) * feat: make locked highlighting consistent * feat: show correct cursor type when moving over locked elements * fix history * remove `lockedUnits.singleUnits` * tweak button * do not render UnlockPopup if not locked element selected * tweak actions * refactor: simplify type * refactor: rename type * refactor: simplify hit element setting & checking * fix: prefer locked over link * rename to `activeLockedId` * refactor: getElementAtPosition takes an optional hitelments array * fix: avoid setting active locked id after resizing --------- Co-authored-by: dwelle <5153846+dwelle@users.noreply.github.com>
150 lines
4.1 KiB
TypeScript
150 lines
4.1 KiB
TypeScript
import type { ObservedAppState } from "@excalidraw/excalidraw/types";
|
|
import type { LinearElementEditor } from "@excalidraw/element";
|
|
|
|
import { AppStateDelta } from "../src/delta";
|
|
|
|
describe("AppStateDelta", () => {
|
|
describe("ensure stable delta properties order", () => {
|
|
it("should maintain stable order for root properties", () => {
|
|
const name = "untitled scene";
|
|
const selectedLinearElementId = "id1" as LinearElementEditor["elementId"];
|
|
|
|
const commonAppState = {
|
|
viewBackgroundColor: "#ffffff",
|
|
selectedElementIds: {},
|
|
selectedGroupIds: {},
|
|
editingGroupId: null,
|
|
croppingElementId: null,
|
|
editingLinearElementId: null,
|
|
lockedMultiSelections: {},
|
|
activeLockedId: null,
|
|
};
|
|
|
|
const prevAppState1: ObservedAppState = {
|
|
...commonAppState,
|
|
name: "",
|
|
selectedLinearElementId: null,
|
|
};
|
|
|
|
const nextAppState1: ObservedAppState = {
|
|
...commonAppState,
|
|
name,
|
|
selectedLinearElementId,
|
|
};
|
|
|
|
const prevAppState2: ObservedAppState = {
|
|
selectedLinearElementId: null,
|
|
name: "",
|
|
...commonAppState,
|
|
};
|
|
|
|
const nextAppState2: ObservedAppState = {
|
|
selectedLinearElementId,
|
|
name,
|
|
...commonAppState,
|
|
};
|
|
|
|
const delta1 = AppStateDelta.calculate(prevAppState1, nextAppState1);
|
|
const delta2 = AppStateDelta.calculate(prevAppState2, nextAppState2);
|
|
|
|
expect(JSON.stringify(delta1)).toBe(JSON.stringify(delta2));
|
|
});
|
|
|
|
it("should maintain stable order for selectedElementIds", () => {
|
|
const commonAppState = {
|
|
name: "",
|
|
viewBackgroundColor: "#ffffff",
|
|
selectedGroupIds: {},
|
|
editingGroupId: null,
|
|
croppingElementId: null,
|
|
selectedLinearElementId: null,
|
|
editingLinearElementId: null,
|
|
activeLockedId: null,
|
|
lockedMultiSelections: {},
|
|
};
|
|
|
|
const prevAppState1: ObservedAppState = {
|
|
...commonAppState,
|
|
selectedElementIds: { id5: true, id2: true, id4: true },
|
|
};
|
|
|
|
const nextAppState1: ObservedAppState = {
|
|
...commonAppState,
|
|
selectedElementIds: {
|
|
id1: true,
|
|
id2: true,
|
|
id3: true,
|
|
},
|
|
};
|
|
|
|
const prevAppState2: ObservedAppState = {
|
|
...commonAppState,
|
|
selectedElementIds: { id4: true, id2: true, id5: true },
|
|
};
|
|
|
|
const nextAppState2: ObservedAppState = {
|
|
...commonAppState,
|
|
selectedElementIds: {
|
|
id3: true,
|
|
id2: true,
|
|
id1: true,
|
|
},
|
|
};
|
|
|
|
const delta1 = AppStateDelta.calculate(prevAppState1, nextAppState1);
|
|
const delta2 = AppStateDelta.calculate(prevAppState2, nextAppState2);
|
|
|
|
expect(JSON.stringify(delta1)).toBe(JSON.stringify(delta2));
|
|
});
|
|
|
|
it("should maintain stable order for selectedGroupIds", () => {
|
|
const commonAppState = {
|
|
name: "",
|
|
viewBackgroundColor: "#ffffff",
|
|
selectedElementIds: {},
|
|
editingGroupId: null,
|
|
croppingElementId: null,
|
|
selectedLinearElementId: null,
|
|
editingLinearElementId: null,
|
|
activeLockedId: null,
|
|
lockedMultiSelections: {},
|
|
};
|
|
|
|
const prevAppState1: ObservedAppState = {
|
|
...commonAppState,
|
|
selectedGroupIds: { id5: false, id2: true, id4: true, id0: true },
|
|
};
|
|
|
|
const nextAppState1: ObservedAppState = {
|
|
...commonAppState,
|
|
selectedGroupIds: {
|
|
id0: true,
|
|
id1: true,
|
|
id2: false,
|
|
id3: true,
|
|
},
|
|
};
|
|
|
|
const prevAppState2: ObservedAppState = {
|
|
...commonAppState,
|
|
selectedGroupIds: { id0: true, id4: true, id2: true, id5: false },
|
|
};
|
|
|
|
const nextAppState2: ObservedAppState = {
|
|
...commonAppState,
|
|
selectedGroupIds: {
|
|
id3: true,
|
|
id2: false,
|
|
id1: true,
|
|
id0: true,
|
|
},
|
|
};
|
|
|
|
const delta1 = AppStateDelta.calculate(prevAppState1, nextAppState1);
|
|
const delta2 = AppStateDelta.calculate(prevAppState2, nextAppState2);
|
|
|
|
expect(JSON.stringify(delta1)).toBe(JSON.stringify(delta2));
|
|
});
|
|
});
|
|
});
|