fix: adding to selection via shift box-select (#6815)

This commit is contained in:
David Luzar 2023-07-27 12:50:08 +02:00 committed by GitHub
parent cbd908097f
commit 8af9ea3cf3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 108 additions and 29 deletions

View File

@ -6068,28 +6068,7 @@ class App extends React.Component<AppProps, AppState> {
pointerDownState.boxSelection.hasOccurred = true; pointerDownState.boxSelection.hasOccurred = true;
const elements = this.scene.getNonDeletedElements(); const elements = this.scene.getNonDeletedElements();
if (
!event.shiftKey &&
// allows for box-selecting points (without shift)
!this.state.editingLinearElement &&
isSomeElementSelected(elements, this.state)
) {
if (pointerDownState.withCmdOrCtrl && pointerDownState.hit.element) {
this.setState((prevState) =>
selectGroupsForSelectedElements(
{
...prevState,
selectedElementIds: {
[pointerDownState.hit.element!.id]: true,
},
},
this.scene.getNonDeletedElements(),
prevState,
this,
),
);
}
}
// box-select line editor points // box-select line editor points
if (this.state.editingLinearElement) { if (this.state.editingLinearElement) {
LinearElementEditor.handleBoxSelection( LinearElementEditor.handleBoxSelection(
@ -6099,18 +6078,46 @@ class App extends React.Component<AppProps, AppState> {
); );
// regular box-select // regular box-select
} else { } else {
let shouldReuseSelection = true;
if (!event.shiftKey && isSomeElementSelected(elements, this.state)) {
if (
pointerDownState.withCmdOrCtrl &&
pointerDownState.hit.element
) {
this.setState((prevState) =>
selectGroupsForSelectedElements(
{
...prevState,
selectedElementIds: {
[pointerDownState.hit.element!.id]: true,
},
},
this.scene.getNonDeletedElements(),
prevState,
this,
),
);
} else {
shouldReuseSelection = false;
}
}
const elementsWithinSelection = getElementsWithinSelection( const elementsWithinSelection = getElementsWithinSelection(
elements, elements,
draggingElement, draggingElement,
); );
this.setState((prevState) => { this.setState((prevState) => {
const nextSelectedElementIds = elementsWithinSelection.reduce( const nextSelectedElementIds = {
(acc: Record<ExcalidrawElement["id"], true>, element) => { ...(shouldReuseSelection && prevState.selectedElementIds),
acc[element.id] = true; ...elementsWithinSelection.reduce(
return acc; (acc: Record<ExcalidrawElement["id"], true>, element) => {
}, acc[element.id] = true;
{}, return acc;
); },
{},
),
};
if (pointerDownState.hit.element) { if (pointerDownState.hit.element) {
// if using ctrl/cmd, select the hitElement only if we // if using ctrl/cmd, select the hitElement only if we
@ -6125,6 +6132,10 @@ class App extends React.Component<AppProps, AppState> {
return selectGroupsForSelectedElements( return selectGroupsForSelectedElements(
{ {
...prevState, ...prevState,
...(!shouldReuseSelection && {
selectedGroupIds: {},
editingGroupId: null,
}),
selectedElementIds: nextSelectedElementIds, selectedElementIds: nextSelectedElementIds,
showHyperlinkPopup: showHyperlinkPopup:
elementsWithinSelection.length === 1 && elementsWithinSelection.length === 1 &&

View File

@ -28,6 +28,74 @@ const { h } = window;
const mouse = new Pointer("mouse"); const mouse = new Pointer("mouse");
describe("box-selection", () => {
beforeEach(async () => {
await render(<ExcalidrawApp />);
});
it("should allow adding to selection via box-select when holding shift", async () => {
const rect1 = API.createElement({
type: "rectangle",
x: 0,
y: 0,
width: 50,
height: 50,
backgroundColor: "red",
fillStyle: "solid",
});
const rect2 = API.createElement({
type: "rectangle",
x: 100,
y: 0,
width: 50,
height: 50,
});
h.elements = [rect1, rect2];
mouse.downAt(175, -20);
mouse.moveTo(85, 70);
mouse.up();
assertSelectedElements([rect2.id]);
Keyboard.withModifierKeys({ shift: true }, () => {
mouse.downAt(75, -20);
mouse.moveTo(-15, 70);
mouse.up();
});
assertSelectedElements([rect2.id, rect1.id]);
});
it("should (de)select element when box-selecting over and out while not holding shift", async () => {
const rect1 = API.createElement({
type: "rectangle",
x: 0,
y: 0,
width: 50,
height: 50,
backgroundColor: "red",
fillStyle: "solid",
});
h.elements = [rect1];
mouse.downAt(75, -20);
mouse.moveTo(-15, 70);
assertSelectedElements([rect1.id]);
mouse.moveTo(100, -100);
assertSelectedElements([]);
mouse.up();
assertSelectedElements([]);
});
});
describe("inner box-selection", () => { describe("inner box-selection", () => {
beforeEach(async () => { beforeEach(async () => {
await render(<ExcalidrawApp />); await render(<ExcalidrawApp />);