Improve search autocomplete UX
- Tab key accepts autocomplete suggestion (like right arrow) - Prevent search from firing while autocomplete suggestion is visible
This commit is contained in:
@@ -160,7 +160,6 @@ class SearchPanel(Widget):
|
|||||||
width: auto;
|
width: auto;
|
||||||
padding: 0 1;
|
padding: 0 1;
|
||||||
color: $primary;
|
color: $primary;
|
||||||
height: 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SearchPanel Input {
|
SearchPanel Input {
|
||||||
@@ -178,7 +177,6 @@ class SearchPanel(Widget):
|
|||||||
width: auto;
|
width: auto;
|
||||||
padding: 0 1;
|
padding: 0 1;
|
||||||
color: $text-muted;
|
color: $text-muted;
|
||||||
height: 1;
|
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -231,6 +229,34 @@ class SearchPanel(Widget):
|
|||||||
yield Button("?", variant="default", id="help-btn")
|
yield Button("?", variant="default", id="help-btn")
|
||||||
yield Button("Cancel", variant="warning", id="cancel-btn")
|
yield Button("Cancel", variant="warning", id="cancel-btn")
|
||||||
|
|
||||||
|
def _has_suggestion(self) -> bool:
|
||||||
|
"""Check if the search input currently has an autocomplete suggestion."""
|
||||||
|
try:
|
||||||
|
input_widget = self.query_one("#search-input", Input)
|
||||||
|
return bool(input_widget._suggestion and input_widget._cursor_at_end)
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _accept_suggestion(self) -> bool:
|
||||||
|
"""Accept the current autocomplete suggestion if present. Returns True if accepted."""
|
||||||
|
try:
|
||||||
|
input_widget = self.query_one("#search-input", Input)
|
||||||
|
if input_widget._suggestion and input_widget._cursor_at_end:
|
||||||
|
input_widget.value = input_widget._suggestion
|
||||||
|
input_widget.cursor_position = len(input_widget.value)
|
||||||
|
return True
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return False
|
||||||
|
|
||||||
|
def on_key(self, event) -> None:
|
||||||
|
"""Handle key events to intercept Tab for autocomplete."""
|
||||||
|
if event.key == "tab":
|
||||||
|
# Try to accept suggestion; if successful, prevent default tab behavior
|
||||||
|
if self._accept_suggestion():
|
||||||
|
event.prevent_default()
|
||||||
|
event.stop()
|
||||||
|
|
||||||
def show(self, initial_query: str = "") -> None:
|
def show(self, initial_query: str = "") -> None:
|
||||||
"""Show the search panel and focus the input."""
|
"""Show the search panel and focus the input."""
|
||||||
self.add_class("visible")
|
self.add_class("visible")
|
||||||
@@ -268,6 +294,10 @@ class SearchPanel(Widget):
|
|||||||
|
|
||||||
def _trigger_search(self) -> None:
|
def _trigger_search(self) -> None:
|
||||||
"""Trigger the actual search after debounce."""
|
"""Trigger the actual search after debounce."""
|
||||||
|
# Don't search if an autocomplete suggestion is visible
|
||||||
|
if self._has_suggestion():
|
||||||
|
return
|
||||||
|
|
||||||
query = self.query_one("#search-input", Input).value.strip()
|
query = self.query_one("#search-input", Input).value.strip()
|
||||||
if query and query != self._last_query:
|
if query and query != self._last_query:
|
||||||
self._last_query = query
|
self._last_query = query
|
||||||
|
|||||||
Reference in New Issue
Block a user