autocomplete
With search results
With search results
Загрузка превью…
src/autocomplete/c-autocomplete-9.vue
<!--
Кейс проверяет только закрытое состояние (см. docs/PORTING.md §5):
попап монтируется только когда `searchValue !== ""`, изначально пусто.
`IconPlaceholder` (спиннер загрузки) заменён инлайновым `<svg>`
(lucide "loader-circle") — виден только в статусе при непустом
запросе, но адаптирован для полноты. Датасет разработчиков сокращён
(3 записи вместо 25) и сетевые аватары (randomuser.me) заменены
статичным 1x1 data-URI (PIXEL) — на закрытое состояние не влияет.
-->
<script setup lang="ts">
import { ref, watch } from "vue"
import { Autocomplete, AutocompleteContent, AutocompleteInput, AutocompleteItem, AutocompleteList, AutocompleteStatus } from "@/components/reui/autocomplete"
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
const PIXEL =
"data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs="
interface Developer {
id: string
name: string
role: string
location: string
avatar: string
}
const topDevelopers: Developer[] = [
{ id: "1", name: "Alex Chen", role: "Senior Full-Stack Developer", location: "San Francisco, CA", avatar: PIXEL },
{ id: "2", name: "Sarah Johnson", role: "Frontend Architect", location: "New York, NY", avatar: PIXEL },
{ id: "3", name: "Michael Rodriguez", role: "Backend Engineer", location: "Austin, TX", avatar: PIXEL },
]
const searchValue = ref("")
const isLoading = ref(false)
const searchResults = ref<Developer[]>([])
const error = ref<string | null>(null)
let timeoutId: ReturnType<typeof setTimeout> | undefined
function search(query: string) {
const q = query.toLowerCase()
return topDevelopers.filter(
(d) => d.name.toLowerCase().includes(q) || d.role.toLowerCase().includes(q) || d.location.toLowerCase().includes(q)
)
}
watch(searchValue, (v) => {
clearTimeout(timeoutId)
if (!v) {
searchResults.value = []
isLoading.value = false
return
}
isLoading.value = true
error.value = null
timeoutId = setTimeout(() => {
try {
searchResults.value = search(v)
} catch {
error.value = "Failed to fetch developers. Please try again."
searchResults.value = []
} finally {
isLoading.value = false
}
}, 300)
})
const shouldRenderPopup = () => searchValue.value !== ""
</script>
<template>
<div class="w-full max-w-xs">
<Autocomplete v-model="searchValue">
<AutocompleteInput placeholder="e.g. John Smith, React, San Francisco" show-trigger show-clear />
<AutocompleteContent v-if="shouldRenderPopup()">
<AutocompleteStatus>
<div v-if="isLoading" class="flex items-center gap-2">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true"
class="lucide lucide-loader-circle size-4 animate-spin"
>
<path d="M21 12a9 9 0 1 1-6.219-8.56" />
</svg>
Searching developers...
</div>
<template v-else-if="error">{{ error }}</template>
<template v-else-if="searchResults.length === 0 && searchValue">{{ `No developers found for "${searchValue}"` }}</template>
<template v-else-if="searchResults.length > 0">{{ `${searchResults.length} developer${searchResults.length === 1 ? "" : "s"} found` }}</template>
<template v-else-if="!searchValue">Start typing to search developers...</template>
</AutocompleteStatus>
<AutocompleteList>
<AutocompleteItem v-for="developer in searchResults" :key="developer.id" :value="developer.name" class="rounded-lg">
<div class="flex items-center gap-2.5 truncate">
<Avatar class="size-9">
<AvatarImage :src="developer.avatar" :alt="developer.name" />
<AvatarFallback>{{ developer.name.split(" ").map((n) => n[0]).join("") }}</AvatarFallback>
</Avatar>
<div class="min-w-0 flex-1">
<div class="truncate font-medium">{{ developer.name }}</div>
<div class="text-muted-foreground truncate text-sm">{{ `${developer.role} • ${developer.location}` }}</div>
</div>
</div>
</AutocompleteItem>
</AutocompleteList>
</AutocompleteContent>
</Autocomplete>
</div>
</template>
Установка
npx shadcn-vue@latest add https://revueui.rootapi.dev/r/c-autocomplete-9.jsonЗависимости реестра
Источник: порт из ReUI (Keenthemes, MIT)