diff --git a/src/ui/src/builder/BuilderApp.vue b/src/ui/src/builder/BuilderApp.vue index cf474e87..502d592a 100644 --- a/src/ui/src/builder/BuilderApp.vue +++ b/src/ui/src/builder/BuilderApp.vue @@ -251,15 +251,7 @@ function handleRendererClick(ev: PointerEvent): void { ev.preventDefault(); ev.stopPropagation(); - if (!ev.shiftKey && !ev.ctrlKey) { - return ssbm.setSelection(targetId, targetInstancePath, "click"); - } - - if (ssbm.isComponentIdSelected(targetId)) { - ssbm.removeSelectedComponentId(targetId); - } else { - ssbm.appendSelection(targetId, targetInstancePath, "click"); - } + ssbm.handleSelectionFromEvent(ev, targetId, targetInstancePath, "click"); } const handleRendererDragStart = (ev: DragEvent) => { diff --git a/src/ui/src/builder/builderManager.spec.ts b/src/ui/src/builder/builderManager.spec.ts index c2cae734..8e70cab4 100644 --- a/src/ui/src/builder/builderManager.spec.ts +++ b/src/ui/src/builder/builderManager.spec.ts @@ -51,5 +51,30 @@ describe(generateBuilderManager.name, () => { expect(isComponentIdSelected("componentId")).toBeFalsy(); expect(selectionStatus.value).toBe(SelectionStatus.None); }); + + it("should handle click events", () => { + const { + handleSelectionFromEvent, + isComponentIdSelected, + selectionStatus, + } = generateBuilderManager(); + + handleSelectionFromEvent({ ctrlKey: true } as KeyboardEvent, "1"); + + expect(selectionStatus.value).toBe(SelectionStatus.Single); + expect(isComponentIdSelected("1")).toBeTruthy(); + + handleSelectionFromEvent({ ctrlKey: true } as KeyboardEvent, "2"); + + expect(selectionStatus.value).toBe(SelectionStatus.Multiple); + expect(isComponentIdSelected("1")).toBeTruthy(); + expect(isComponentIdSelected("2")).toBeTruthy(); + + handleSelectionFromEvent({ ctrlKey: true } as KeyboardEvent, "2"); + + expect(selectionStatus.value).toBe(SelectionStatus.Single); + expect(isComponentIdSelected("1")).toBeTruthy(); + expect(isComponentIdSelected("2")).toBeFalsy(); + }); }); }); diff --git a/src/ui/src/builder/builderManager.ts b/src/ui/src/builder/builderManager.ts index 9e096723..ead8f7ec 100644 --- a/src/ui/src/builder/builderManager.ts +++ b/src/ui/src/builder/builderManager.ts @@ -148,6 +148,23 @@ export function generateBuilderManager() { }); }; + const handleSelectionFromEvent = ( + ev: MouseEvent | KeyboardEvent, + componentId: Component["id"], + instancePath?: string, + source?: SelectionSource, + ) => { + if (!ev.shiftKey && !ev.ctrlKey) { + return setSelection(componentId, instancePath, source); + } + + if (isComponentIdSelected(componentId)) { + removeSelectedComponentId(componentId); + } else { + appendSelection(componentId, instancePath, source); + } + }; + const isComponentIdSelected = (componentId: string) => { return state.value.selection.some((s) => s.componentId === componentId); }; @@ -369,6 +386,7 @@ export function generateBuilderManager() { removeSelectedComponentId, setSelection, appendSelection, + handleSelectionFromEvent, getSelection, getSelectedId, setClipboard, diff --git a/src/ui/src/builder/sidebar/BuilderSidebarComponentTreeBranch.vue b/src/ui/src/builder/sidebar/BuilderSidebarComponentTreeBranch.vue index bb83b98a..bdb0a5af 100644 --- a/src/ui/src/builder/sidebar/BuilderSidebarComponentTreeBranch.vue +++ b/src/ui/src/builder/sidebar/BuilderSidebarComponentTreeBranch.vue @@ -149,17 +149,7 @@ const name = computed(() => { async function select(ev: MouseEvent | KeyboardEvent) { goToComponentParentPage(props.componentId); await nextTick(); - - if (!ev.shiftKey && !ev.ctrlKey) { - return wfbm.setSelection(props.componentId, undefined, "tree"); - } - - if (wfbm.isComponentIdSelected(props.componentId)) { - wfbm.removeSelectedComponentId(props.componentId); - } else { - wfbm.appendSelection(props.componentId, undefined, "tree"); - } - + wfbm.handleSelectionFromEvent(ev, props.componentId, undefined, "tree"); expand(); }