diff --git a/frontend/src/lib/components/graph/FlowGraphV2.svelte b/frontend/src/lib/components/graph/FlowGraphV2.svelte
index 16788a4054..052df58d63 100644
--- a/frontend/src/lib/components/graph/FlowGraphV2.svelte
+++ b/frontend/src/lib/components/graph/FlowGraphV2.svelte
@@ -472,8 +472,8 @@
selectionManager.handleKeyDown(event, nodes)
}
- function handleKeyUp(_event: KeyboardEvent) {
- // Keep for potential future use
+ function handleKeyUp(event: KeyboardEvent) {
+ selectionManager.handleKeyUp(event)
}
async function updateStores() {
diff --git a/frontend/src/lib/components/graph/SelectionBoundingBox.svelte b/frontend/src/lib/components/graph/SelectionBoundingBox.svelte
index ef0e708913..dfacad05e8 100644
--- a/frontend/src/lib/components/graph/SelectionBoundingBox.svelte
+++ b/frontend/src/lib/components/graph/SelectionBoundingBox.svelte
@@ -59,7 +59,7 @@
{#if bounds() && selectedNodes.length > 1}
{@const currentBounds = bounds()!}
-
- {selectedNodes.length} nodes selected
-
{/if}
diff --git a/frontend/src/lib/components/graph/selectionUtils.svelte.ts b/frontend/src/lib/components/graph/selectionUtils.svelte.ts
index ce22d47e29..3b408f1385 100644
--- a/frontend/src/lib/components/graph/selectionUtils.svelte.ts
+++ b/frontend/src/lib/components/graph/selectionUtils.svelte.ts
@@ -10,6 +10,9 @@ export interface SelectionState {
export class SelectionManager {
public selectedIds = $state([])
#selectionMode = $state<'normal' | 'rect-select'>('normal')
+ #modeSource = $state<'button' | 'keyboard' | 'temporary'>('button')
+ #previousMode = $state<'normal' | 'rect-select'>('normal')
+ #cmdKeyPressed = $state(false)
constructor() {}
@@ -26,11 +29,36 @@ export class SelectionManager {
}
set mode(mode: 'normal' | 'rect-select') {
+ this.#previousMode = this.#selectionMode
this.#selectionMode = mode
- if (mode === 'normal') {
- // When exiting rect mode, preserve the first item if there are selections
- const firstSelected = this.selectedIds[0]
- this.selectId(firstSelected ?? 'settings')
+ // Default to button source when mode is set directly (for backward compatibility)
+ if (this.#modeSource !== 'temporary') {
+ this.#modeSource = 'button'
+ }
+ // Note: No automatic selection clearing when changing modes - preserve current selection
+ }
+
+ // Toggle mode temporarily (for cmd key hold behavior)
+ toggleModeTemporary() {
+ this.#previousMode = this.#selectionMode
+ this.#modeSource = 'temporary'
+ this.#selectionMode = this.#selectionMode === 'normal' ? 'rect-select' : 'normal'
+ }
+
+ // Toggle mode persistently (for cmd key tap behavior)
+ toggleModePersistent() {
+ this.#previousMode = this.#selectionMode
+ this.#modeSource = 'keyboard'
+ this.#selectionMode = this.#selectionMode === 'normal' ? 'rect-select' : 'normal'
+ // Note: Preserve current selection when toggling modes
+ }
+
+ // Revert temporary mode change
+ revertTemporaryMode() {
+ if (this.#modeSource === 'temporary') {
+ this.#selectionMode = this.#previousMode
+ this.#modeSource = 'button' // Reset to default button source
+ // Note: Preserve current selection when reverting temporary mode changes
}
}
@@ -173,9 +201,14 @@ export class SelectionManager {
// Handle keyboard shortcuts
handleKeyDown(event: KeyboardEvent, nodes?: Node[]) {
if (event.key === 'Escape') {
- if (this.#selectionMode === 'rect-select') {
- // Exit rect mode (this will preserve first item via mode setter)
- this.mode = 'normal'
+ // Escape key clears selection regardless of mode
+ this.clearSelection()
+ } else if (event.key === 'Meta' || event.key === 'Cmd') {
+ // Cmd/Meta key pressed - temporarily toggle mode
+ if (!this.#cmdKeyPressed) {
+ this.#cmdKeyPressed = true
+ event.preventDefault()
+ this.toggleModeTemporary()
}
} else if ((event.ctrlKey || event.metaKey) && event.key === 'a') {
event.preventDefault()
@@ -186,4 +219,13 @@ export class SelectionManager {
}
}
}
+
+ // Handle keyboard releases
+ handleKeyUp(event: KeyboardEvent) {
+ if (event.key === 'Meta' || event.key === 'Cmd') {
+ // Cmd/Meta key released - revert temporary mode change
+ this.#cmdKeyPressed = false
+ this.revertTemporaryMode()
+ }
+ }
}