fix group selection (#2092)

This commit is contained in:
David Luzar 2020-08-27 20:32:10 +02:00 committed by GitHub
parent 546e13571d
commit b8f8bc2e32
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 936 additions and 112 deletions

View File

@ -3384,33 +3384,15 @@ class App extends React.Component<ExcalidrawProps, AppState> {
})); }));
} }
} else { } else {
if (isSelectedViaGroup(this.state, hitElement)) { this.setState((prevState) => ({
/* ...selectGroupsForSelectedElements(
We want to select the group(s) the hit element is in not the particular element. {
That means we have to deselect elements that are not part of the groups of the ...prevState,
hit element, while keeping the elements that are. selectedElementIds: { [hitElement.id]: true },
*/
const idsOfSelectedElementsThatAreInGroups = hitElement.groupIds
.flatMap((groupId) =>
getElementsInGroup(this.scene.getElements(), groupId),
)
.map((element) => ({ [element.id]: true }))
.reduce((prevId, acc) => ({ ...prevId, ...acc }), {});
this.setState((_prevState) => ({
selectedGroupIds: {
...hitElement.groupIds
.map((gId) => ({ [gId]: true }))
.reduce((prevId, acc) => ({ ...prevId, ...acc }), {}),
}, },
selectedElementIds: { ...idsOfSelectedElementsThatAreInGroups }, this.scene.getElements(),
})); ),
} else { }));
this.setState((_prevState) => ({
selectedGroupIds: {},
selectedElementIds: { [hitElement!.id]: true },
}));
}
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -23,6 +23,33 @@ const clickTool = (toolName: ToolName) => {
fireEvent.click(getByToolName(toolName)); fireEvent.click(getByToolName(toolName));
}; };
const createElement = (
type: ToolName,
{
x = 0,
y = x,
size = 10,
}: {
x?: number;
y?: number;
size?: number;
},
) => {
clickTool(type);
mouse.reset();
mouse.down(x, y);
mouse.reset();
mouse.up(x + size, y + size);
return h.elements[h.elements.length - 1];
};
const group = (elements: ExcalidrawElement[]) => {
mouse.select(elements);
withModifierKeys({ ctrl: true }, () => {
keyPress("g");
});
};
let altKey = false; let altKey = false;
let shiftKey = false; let shiftKey = false;
let ctrlKey = false; let ctrlKey = false;
@ -159,6 +186,28 @@ class Pointer {
this.move(dx, dy); this.move(dx, dy);
fireEvent.doubleClick(canvas, this.getEvent()); fireEvent.doubleClick(canvas, this.getEvent());
} }
select(
/** if multiple elements supplied, they're shift-selected */
elements: ExcalidrawElement | ExcalidrawElement[],
) {
// @ts-ignore
h.app.clearSelection(null);
withModifierKeys({ shift: true }, () => {
elements = Array.isArray(elements) ? elements : [elements];
elements.forEach((element) => {
mouse.reset();
mouse.click(element.x, element.y);
});
});
mouse.reset();
}
clickOn(element: ExcalidrawElement) {
mouse.reset();
mouse.click(element.x, element.y);
mouse.reset();
}
} }
const mouse = new Pointer("mouse"); const mouse = new Pointer("mouse");
@ -1579,6 +1628,27 @@ describe("regression tests", () => {
}); });
expect(getSelectedElements().length).toBe(0); expect(getSelectedElements().length).toBe(0);
}); });
it("single-clicking on a subgroup of a selected group should not alter selection", () => {
const rect1 = createElement("rectangle", { x: 10 });
const rect2 = createElement("rectangle", { x: 50 });
group([rect1, rect2]);
const rect3 = createElement("rectangle", { x: 10, y: 50 });
const rect4 = createElement("rectangle", { x: 50, y: 50 });
group([rect3, rect4]);
withModifierKeys({ ctrl: true }, () => {
keyPress("a");
keyPress("g");
});
const selectedGroupIds_prev = h.state.selectedGroupIds;
const selectedElements_prev = getSelectedElements();
mouse.clickOn(rect3);
expect(h.state.selectedGroupIds).toEqual(selectedGroupIds_prev);
expect(getSelectedElements()).toEqual(selectedElements_prev);
});
}); });
it( it(
@ -1586,52 +1656,26 @@ it(
"when user clicks on B, on pointer up " + "when user clicks on B, on pointer up " +
"only elements from B should be selected", "only elements from B should be selected",
() => { () => {
clickTool("rectangle"); const rect1 = createElement("rectangle", { y: 0 });
mouse.down(); const rect2 = createElement("rectangle", { y: 30 });
mouse.up(100, 100); const rect3 = createElement("rectangle", { y: 60 });
clickTool("rectangle"); group([rect1, rect3]);
mouse.down(10, 10);
mouse.up(100, 100);
clickTool("rectangle");
mouse.down(10, 10);
mouse.up(100, 100);
// Select first rectangle while keeping third one selected.
// Third rectangle is selected because it was the last element
// to be created.
mouse.reset();
withModifierKeys({ shift: true }, () => {
mouse.click();
});
// Create group with first and third rectangle
withModifierKeys({ ctrl: true }, () => {
keyPress("g");
});
expect(getSelectedElements().length).toBe(2); expect(getSelectedElements().length).toBe(2);
const selectedGroupIds = Object.keys(h.state.selectedGroupIds); expect(Object.keys(h.state.selectedGroupIds).length).toBe(1);
expect(selectedGroupIds.length).toBe(1);
// Select second rectangle without deselecting group // Select second rectangle without deselecting group
withModifierKeys({ shift: true }, () => { withModifierKeys({ shift: true }, () => {
mouse.click(110, 110); mouse.clickOn(rect2);
}); });
expect(getSelectedElements().length).toBe(3); expect(getSelectedElements().length).toBe(3);
// pointer down on first rectangle that is // clicking on first rectangle that is part of the group should select
// part of the group // that group (exclusively)
mouse.reset(); mouse.clickOn(rect1);
mouse.down();
expect(getSelectedElements().length).toBe(3);
// should only deselect on pointer up
mouse.up();
expect(getSelectedElements().length).toBe(2); expect(getSelectedElements().length).toBe(2);
const newSelectedGroupIds = Object.keys(h.state.selectedGroupIds); expect(Object.keys(h.state.selectedGroupIds).length).toBe(1);
expect(newSelectedGroupIds.length).toBe(1);
}, },
); );