Allow switch between selection modes with keyboard keys

This commit is contained in:
Guilhem
2025-11-12 09:51:24 +01:00
parent c66bdd306f
commit 5d0796603f
3 changed files with 52 additions and 15 deletions
@@ -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() {
@@ -59,7 +59,7 @@
{#if bounds() && selectedNodes.length > 1}
{@const currentBounds = bounds()!}
<div
class="absolute border-2 border-dashed border-accent bg-accent/5 rounded cursor-pointer"
class={'absolute rounded cursor-pointer bg-surface-selected/30 border-2 border-dashed border-accent '}
style="
left: {currentBounds.x}px;
top: {currentBounds.y}px;
@@ -68,10 +68,5 @@
z-index: 10;
"
>
<div
class="absolute -top-6 left-0 text-xs text-accent font-medium bg-surface px-2 py-1 rounded shadow pointer-events-none"
>
{selectedNodes.length} nodes selected
</div>
</div>
{/if}
@@ -10,6 +10,9 @@ export interface SelectionState {
export class SelectionManager {
public selectedIds = $state<string[]>([])
#selectionMode = $state<'normal' | 'rect-select'>('normal')
#modeSource = $state<'button' | 'keyboard' | 'temporary'>('button')
#previousMode = $state<'normal' | 'rect-select'>('normal')
#cmdKeyPressed = $state<boolean>(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()
}
}
}