This commit is contained in:
Andrew Aquino 2025-04-29 06:12:44 +00:00 committed by GitHub
commit d55c677721
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 126 additions and 7 deletions

View file

@ -4300,6 +4300,27 @@ class App extends React.Component<AppProps, AppState> {
}, 100); }, 100);
} }
// remove selections on escape press
if (
event.key === KEYS.ESCAPE &&
// unless we're dragging or finalizing an action
!(
this.state.newElement ||
isWritableElement(event.target) ||
this.state.editingTextElement ||
this.state.editingLinearElement ||
["freedraw", "eraser"].includes(this.state.activeTool.type)
)
) {
this.setState({
selectedElementIds: {},
selectedGroupIds: {},
editingGroupId: null,
});
event.preventDefault();
return;
}
// prevent browser zoom in input fields // prevent browser zoom in input fields
if (event[KEYS.CTRL_OR_CMD] && isWritableElement(event.target)) { if (event[KEYS.CTRL_OR_CMD] && isWritableElement(event.target)) {
if (event.code === CODES.MINUS || event.code === CODES.EQUAL) { if (event.code === CODES.MINUS || event.code === CODES.EQUAL) {

View file

@ -107,6 +107,104 @@ describe("box-selection", () => {
}); });
}); });
describe("deselect when pressing escape", () => {
beforeEach(async () => {
await render(<Excalidraw handleKeyboardGlobally={true} />);
});
it("deselects elements", async () => {
const rect1 = API.createElement({
type: "rectangle",
x: 0,
y: 0,
width: 50,
height: 50,
});
const rect2 = API.createElement({
type: "rectangle",
x: 100,
y: 0,
width: 50,
height: 50,
});
API.setElements([rect1, rect2]);
mouse.clickAt(0, 0);
assertSelectedElements([rect1.id]);
Keyboard.keyDown(KEYS.ESCAPE);
assertSelectedElements([]);
mouse.downAt(-10, -10);
mouse.moveTo(160, 60);
mouse.up();
assertSelectedElements([rect1.id, rect2.id]);
Keyboard.keyDown(KEYS.ESCAPE);
assertSelectedElements([]);
});
it("deselects groups", async () => {
const rect1 = API.createElement({
type: "rectangle",
x: 0,
y: 0,
width: 50,
height: 50,
});
const rect2 = API.createElement({
type: "rectangle",
x: 100,
y: 0,
width: 50,
height: 50,
});
const rect3 = API.createElement({
type: "rectangle",
x: 200,
y: 0,
width: 50,
height: 50,
});
API.setElements([rect1, rect2, rect3]);
mouse.downAt(-10, -10);
mouse.moveTo(160, 60);
mouse.up();
Keyboard.withModifierKeys({ ctrl: true }, () => {
Keyboard.keyDown(KEYS.G);
});
expect(Object.keys(h.state.selectedGroupIds).length).toBe(1);
assertSelectedElements([rect1.id, rect2.id]);
Keyboard.keyDown(KEYS.ESCAPE);
expect(Object.keys(h.state.selectedGroupIds).length).toBe(0);
assertSelectedElements([]);
mouse.clickAt(100, 0);
Keyboard.withModifierKeys({ shift: true }, () => {
mouse.clickAt(200, 0);
});
expect(Object.keys(h.state.selectedGroupIds).length).toBe(1);
assertSelectedElements([rect1.id, rect2.id, rect3.id]);
Keyboard.keyDown(KEYS.ESCAPE);
expect(Object.keys(h.state.selectedGroupIds).length).toBe(0);
assertSelectedElements([]);
});
});
describe("inner box-selection", () => { describe("inner box-selection", () => {
beforeEach(async () => { beforeEach(async () => {
await render(<Excalidraw />); await render(<Excalidraw />);
@ -317,7 +415,7 @@ describe("select single element on the scene", () => {
fireEvent.pointerUp(canvas); fireEvent.pointerUp(canvas);
expect(renderInteractiveScene).toHaveBeenCalledTimes(8); expect(renderInteractiveScene).toHaveBeenCalledTimes(8);
expect(renderStaticScene).toHaveBeenCalledTimes(6); expect(renderStaticScene).toHaveBeenCalledTimes(7);
expect(h.state.selectionElement).toBeNull(); expect(h.state.selectionElement).toBeNull();
expect(h.elements.length).toEqual(1); expect(h.elements.length).toEqual(1);
expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy(); expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy();
@ -349,7 +447,7 @@ describe("select single element on the scene", () => {
fireEvent.pointerUp(canvas); fireEvent.pointerUp(canvas);
expect(renderInteractiveScene).toHaveBeenCalledTimes(8); expect(renderInteractiveScene).toHaveBeenCalledTimes(8);
expect(renderStaticScene).toHaveBeenCalledTimes(6); expect(renderStaticScene).toHaveBeenCalledTimes(7);
expect(h.state.selectionElement).toBeNull(); expect(h.state.selectionElement).toBeNull();
expect(h.elements.length).toEqual(1); expect(h.elements.length).toEqual(1);
expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy(); expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy();
@ -381,7 +479,7 @@ describe("select single element on the scene", () => {
fireEvent.pointerUp(canvas); fireEvent.pointerUp(canvas);
expect(renderInteractiveScene).toHaveBeenCalledTimes(8); expect(renderInteractiveScene).toHaveBeenCalledTimes(8);
expect(renderStaticScene).toHaveBeenCalledTimes(6); expect(renderStaticScene).toHaveBeenCalledTimes(7);
expect(h.state.selectionElement).toBeNull(); expect(h.state.selectionElement).toBeNull();
expect(h.elements.length).toEqual(1); expect(h.elements.length).toEqual(1);
expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy(); expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy();
@ -425,8 +523,8 @@ describe("select single element on the scene", () => {
fireEvent.pointerDown(canvas, { clientX: 40, clientY: 40 }); fireEvent.pointerDown(canvas, { clientX: 40, clientY: 40 });
fireEvent.pointerUp(canvas); fireEvent.pointerUp(canvas);
expect(renderInteractiveScene).toHaveBeenCalledTimes(8); expect(renderInteractiveScene).toHaveBeenCalledTimes(9);
expect(renderStaticScene).toHaveBeenCalledTimes(6); expect(renderStaticScene).toHaveBeenCalledTimes(7);
expect(h.state.selectionElement).toBeNull(); expect(h.state.selectionElement).toBeNull();
expect(h.elements.length).toEqual(1); expect(h.elements.length).toEqual(1);
expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy(); expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy();
@ -469,8 +567,8 @@ describe("select single element on the scene", () => {
fireEvent.pointerDown(canvas, { clientX: 40, clientY: 40 }); fireEvent.pointerDown(canvas, { clientX: 40, clientY: 40 });
fireEvent.pointerUp(canvas); fireEvent.pointerUp(canvas);
expect(renderInteractiveScene).toHaveBeenCalledTimes(8); expect(renderInteractiveScene).toHaveBeenCalledTimes(9);
expect(renderStaticScene).toHaveBeenCalledTimes(6); expect(renderStaticScene).toHaveBeenCalledTimes(7);
expect(h.state.selectionElement).toBeNull(); expect(h.state.selectionElement).toBeNull();
expect(h.elements.length).toEqual(1); expect(h.elements.length).toEqual(1);
expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy(); expect(h.state.selectedElementIds[h.elements[0].id]).toBeTruthy();