Enhance MarketFuzzySearch component with improved suggestion display and input focus handling

- Added focus and blur event handlers to manage input focus state.
- Updated suggestion display to show both search suggestions and recent searches in a unified dropdown.
- Improved styling for suggestion buttons to enhance user interaction.
- Ensured input field is focused after clearing search, improving usability.

These changes enhance the search experience by providing clearer suggestions and better input management.
This commit is contained in:
padreug 2025-09-26 10:17:14 +02:00
parent 06d4cc4d4a
commit f2a432b6df

View file

@ -11,6 +11,8 @@
:model-value="searchQuery"
@update:model-value="handleSearchChange"
@keydown="handleKeydown"
@focus="handleFocus"
@blur="handleBlur"
:placeholder="enhancedPlaceholder"
:disabled="disabled"
class="pl-10 pr-20"
@ -56,9 +58,14 @@
</div>
</div>
<!-- Search Suggestions (when no input but focused) -->
<div v-if="showSuggestions && !searchQuery && isFocused" class="mt-2 p-3 border rounded-lg bg-muted/50">
<div class="text-sm font-medium mb-2">Try searching for:</div>
<!-- Floating Search Suggestions & Recent Searches -->
<div
v-if="(showSuggestions || showRecentSearches) && !searchQuery && isFocused"
class="absolute top-full left-0 right-0 z-50 mt-1 max-h-80 overflow-y-auto bg-popover border border-border rounded-md shadow-lg"
>
<!-- Search Suggestions -->
<div v-if="showSuggestions && searchSuggestions.length > 0" class="p-3 border-b border-border">
<div class="text-sm font-medium mb-2 text-foreground">Try searching for:</div>
<div class="flex flex-wrap gap-1">
<Button
v-for="suggestion in searchSuggestions"
@ -66,7 +73,7 @@
variant="ghost"
size="sm"
@click="applySuggestion(suggestion)"
class="h-6 px-2 text-xs"
class="h-6 px-2 text-xs hover:bg-accent hover:text-accent-foreground"
>
{{ suggestion }}
</Button>
@ -74,14 +81,14 @@
</div>
<!-- Recent Searches -->
<div v-if="showRecentSearches && recentSearches.length > 0 && !searchQuery && isFocused" class="mt-2 p-3 border rounded-lg bg-muted/50">
<div v-if="showRecentSearches && recentSearches.length > 0" class="p-3">
<div class="flex items-center justify-between mb-2">
<div class="text-sm font-medium">Recent searches:</div>
<div class="text-sm font-medium text-foreground">Recent searches:</div>
<Button
variant="ghost"
size="sm"
@click="clearRecentSearches"
class="h-5 px-1 text-xs"
class="h-5 px-1 text-xs hover:bg-destructive hover:text-destructive-foreground"
>
Clear
</Button>
@ -93,7 +100,7 @@
variant="ghost"
size="sm"
@click="applyRecentSearch(recent)"
class="h-6 px-2 text-xs"
class="h-6 px-2 text-xs hover:bg-accent hover:text-accent-foreground"
>
<History class="w-3 h-3 mr-1" />
{{ recent }}
@ -101,6 +108,7 @@
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
@ -267,7 +275,14 @@ const handleClear = () => {
emit('search', '')
emit('results', filteredItems.value)
emit('clear')
searchInputRef.value?.focus()
// Focus the input after clearing
if (searchInputRef.value) {
const inputElement = searchInputRef.value.$el?.querySelector('input') || searchInputRef.value.$el
if (inputElement && typeof inputElement.focus === 'function') {
inputElement.focus()
}
}
}
const handleKeydown = (event: KeyboardEvent) => {
@ -275,8 +290,11 @@ const handleKeydown = (event: KeyboardEvent) => {
if (event.key === 'Escape') {
if (searchQuery.value) {
handleClear()
} else {
searchInputRef.value?.blur()
} else if (searchInputRef.value) {
const inputElement = searchInputRef.value.$el?.querySelector('input') || searchInputRef.value.$el
if (inputElement && typeof inputElement.blur === 'function') {
inputElement.blur()
}
}
event.preventDefault()
}
@ -323,7 +341,14 @@ const handleGlobalKeydown = (event: KeyboardEvent) => {
// K or Ctrl+K to focus search
if ((event.metaKey || event.ctrlKey) && event.key === 'k') {
event.preventDefault()
searchInputRef.value?.focus()
console.log('⌘K/Ctrl+K pressed, focusing search input', !!searchInputRef.value)
if (searchInputRef.value) {
// Access the underlying HTML input element from the Shadcn Input component
const inputElement = searchInputRef.value.$el?.querySelector('input') || searchInputRef.value.$el
if (inputElement && typeof inputElement.focus === 'function') {
inputElement.focus()
}
}
}
}
@ -335,20 +360,10 @@ watch(filteredItems, (items) => {
// Setup and cleanup
onMounted(() => {
document.addEventListener('keydown', handleGlobalKeydown)
if (searchInputRef.value) {
searchInputRef.value.addEventListener('focus', handleFocus)
searchInputRef.value.addEventListener('blur', handleBlur)
}
})
onUnmounted(() => {
document.removeEventListener('keydown', handleGlobalKeydown)
if (searchInputRef.value) {
searchInputRef.value.removeEventListener('focus', handleFocus)
searchInputRef.value.removeEventListener('blur', handleBlur)
}
})
</script>