diff --git a/src/multiselect_controls.js b/src/multiselect_controls.js index b67192a..0b19411 100644 --- a/src/multiselect_controls.js +++ b/src/multiselect_controls.js @@ -491,15 +491,37 @@ export class MultiselectControls { } return toRemove; }; + // Filter out shadow blocks from selection + const filterShadows = (list) => { + const toRemove = []; + for (const [element] of list.entries()) { + const elementParent = element.parentElement; + if (elementParent && elementParent.dataset && elementParent.dataset.id) { + const block = getByID(this.workspace_, elementParent.dataset.id); + if (block && block?.isShadow?.()) { + toRemove.push(element); + } + } + } + return toRemove; + }; + this.dragSelect_.Selection.filterSelected = ( {selectorRect, select: _select, unselect: _unselect}) => { const select = _select; const unselect = _unselect; - const toRemove = filterParent(select, selectorRect); - toRemove.forEach((el) => { + + const shadowsToRemove = filterShadows(select); + shadowsToRemove.forEach((el) => { + select.delete(el); + }); + + const parentsToRemove = filterParent(select, selectorRect); + parentsToRemove.forEach((el) => { const rect = select.get(el); select.delete(el); unselect.set(el, rect); }); + return {select, unselect}; }; diff --git a/test-e2e/selection/multiselect/block.spec.ts b/test-e2e/selection/multiselect/block.spec.ts index 408d13e..c4e366d 100644 --- a/test-e2e/selection/multiselect/block.spec.ts +++ b/test-e2e/selection/multiselect/block.spec.ts @@ -420,3 +420,83 @@ test("shift clicking child inside parent bounds selects child", async ({ expect(await getHighlightedBlockIds(page)).toEqual(["child"]); expect(await getSelectedId(page)).toBe("child"); }); + +test("shift clicking block's shadow block input selects main block", async ({ + page, + act, +}) => { + await act( + loadBlocks(page, [ + { + type: "controls_repeat_ext", + id: "block", + inputs: { + TIMES: { + shadow: { + type: "math_number", + id: "shadow", + fields: { + NUM: 10, + }, + }, + }, + }, + }, + ]), + ); + + await act(page.keyboard.down("Shift")); + + await act( + page.mouse.click(...(await getBlock(page, { id: "shadow" })).centerTop), + ); + + await act(page.keyboard.up("Shift")); + + expect(await getHighlightedBlockIds(page)).toEqual(["block"]); + expect(await getSelectedId(page)).toBe("block"); +}); + +test("shift clicking block's shadow block input adds main block into existing multiselection", async ({ + page, + act, +}) => { + await act( + loadBlocks(page, [ + { type: "math_number", id: "block1" }, + { type: "math_number", id: "block2" }, + { + type: "controls_repeat_ext", + id: "block3", + inputs: { + TIMES: { + shadow: { + type: "math_number", + id: "shadow", + fields: { + NUM: 10, + }, + }, + }, + }, + }, + ]), + ); + + await act(page.keyboard.down("Shift")); + + await act( + page.mouse.click(...(await getBlock(page, { id: "block1" })).centerTop), + ); + await act( + page.mouse.click(...(await getBlock(page, { id: "block2" })).centerTop), + ); + await act( + page.mouse.click(...(await getBlock(page, { id: "shadow" })).centerTop), + ); + + await act(page.keyboard.up("Shift")); + + expect(await getHighlightedBlockIds(page)).toEqual(["block1", "block2", "block3"]); + expect(await getSelectedId(page)).toBe(await getMultiselectDraggableId(page)); +}); \ No newline at end of file