diff --git a/frontend/src/views/dashboard/canvas/CanvasCore.vue b/frontend/src/views/dashboard/canvas/CanvasCore.vue index 7fe3a84a..6a58d220 100644 --- a/frontend/src/views/dashboard/canvas/CanvasCore.vue +++ b/frontend/src/views/dashboard/canvas/CanvasCore.vue @@ -727,7 +727,11 @@ function startResize(e: MouseEvent, point: string, item: CanvasItem, index: numb infoBox.value.point = point } -function containerClick() { +function containerClick(e?: MouseEvent) { + // Ignore clicks that originate inside a component so interacting with component + // content (e.g. selecting/copying cells in an S2 table) does not clear the + // current selection. Only blank-canvas clicks deselect. + if ((e?.target as HTMLElement)?.closest?.('.item')) return // remove current component info dashboardStore.setCurComponent(null) } diff --git a/frontend/src/views/dashboard/canvas/CanvasShape.vue b/frontend/src/views/dashboard/canvas/CanvasShape.vue index f49de87f..a498b359 100644 --- a/frontend/src/views/dashboard/canvas/CanvasShape.vue +++ b/frontend/src/views/dashboard/canvas/CanvasShape.vue @@ -52,7 +52,11 @@ const props = defineProps({ const { draggable } = toRefs(props) const shapeClick = (e: MouseEvent) => { - e.stopPropagation() + // Do not stopPropagation here: the click must reach window so components that + // rely on a window-level click listener (e.g. the S2 table copy interaction, + // which only enables Cmd/Ctrl+C when the last click landed on its canvas) work + // inside the editor. Deselection is handled by containerClick ignoring clicks + // that originate inside a component. e.preventDefault() }