diff --git a/src/client/src/components/ActionPalette.ts b/src/client/src/components/ActionPalette.ts index 473b05e..72c6627 100644 --- a/src/client/src/components/ActionPalette.ts +++ b/src/client/src/components/ActionPalette.ts @@ -53,9 +53,15 @@ export class ActionPalette extends LitElement { } protected override updated(changed: PropertyValues) { - if (!changed.has("actions") && !changed.has("queryText")) return; - const maxIndex = Math.max(0, this.filteredActions().length - 1); - if (this.selectedIndex > maxIndex) this.selectedIndex = maxIndex; + if (changed.has("actions") || changed.has("queryText")) { + const maxIndex = Math.max(0, this.filteredActions().length - 1); + if (this.selectedIndex > maxIndex) this.selectedIndex = maxIndex; + } + if (changed.has("selectedIndex") || changed.has("actions") || changed.has("queryText")) this.scrollSelectedIntoView(); + } + + private scrollSelectedIntoView() { + this.renderRoot.querySelector(".options button.selected")?.scrollIntoView({ block: "nearest" }); } private filteredActions(): AppAction[] { diff --git a/src/client/src/components/AutocompleteMenu.ts b/src/client/src/components/AutocompleteMenu.ts index 0fa52c2..3462a19 100644 --- a/src/client/src/components/AutocompleteMenu.ts +++ b/src/client/src/components/AutocompleteMenu.ts @@ -1,4 +1,4 @@ -import { LitElement, html } from "lit"; +import { LitElement, html, type PropertyValues } from "lit"; import { customElement, property } from "lit/decorators.js"; import { autocompleteStyles, type CompletionItem } from "./shared"; @@ -23,5 +23,13 @@ export class AutocompleteMenu extends LitElement { `; } + protected override updated(changed: PropertyValues) { + if (changed.has("selectedIndex") || changed.has("items")) this.scrollSelectedIntoView(); + } + + private scrollSelectedIntoView() { + this.renderRoot.querySelector("button.selected")?.scrollIntoView({ block: "nearest" }); + } + static override styles = autocompleteStyles; } diff --git a/src/client/src/components/CommandPicker.ts b/src/client/src/components/CommandPicker.ts index ff72209..3e99afc 100644 --- a/src/client/src/components/CommandPicker.ts +++ b/src/client/src/components/CommandPicker.ts @@ -1,4 +1,4 @@ -import { LitElement, html } from "lit"; +import { LitElement, html, type PropertyValues } from "lit"; import { customElement, property, state } from "lit/decorators.js"; import type { CommandOption } from "../api"; import { commandPickerStyles } from "./shared"; @@ -36,16 +36,24 @@ export class CommandPicker extends LitElement { this.renderRoot.querySelector(".options")?.focus(); } + protected override updated(changed: PropertyValues) { + if (changed.has("selectedIndex") || changed.has("options")) this.scrollSelectedIntoView(); + } + + private scrollSelectedIntoView() { + this.renderRoot.querySelector(".options button.selected")?.scrollIntoView({ block: "nearest" }); + } + private handleKeyDown(event: KeyboardEvent) { if (event.key === "Escape") { event.preventDefault(); this.onCancel?.(); } else if (event.key === "ArrowDown") { event.preventDefault(); - this.selectedIndex = (this.selectedIndex + 1) % this.options.length; + if (this.options.length > 0) this.selectedIndex = (this.selectedIndex + 1) % this.options.length; } else if (event.key === "ArrowUp") { event.preventDefault(); - this.selectedIndex = (this.selectedIndex - 1 + this.options.length) % this.options.length; + if (this.options.length > 0) this.selectedIndex = (this.selectedIndex - 1 + this.options.length) % this.options.length; } else if (event.key === "Enter") { event.preventDefault(); const option = this.options[this.selectedIndex];