47 lines
1.4 KiB
Vue
47 lines
1.4 KiB
Vue
<script setup lang="ts">
|
|
import {watchDebounced} from '@vueuse/core';
|
|
import {ref, watch} from 'vue';
|
|
import {SelectInput} from '@/components';
|
|
import {isDefaultHub, MarketLocation, searchMarketLocations} from './MarketLocation';
|
|
|
|
const modelValue = defineModel<MarketLocation>();
|
|
|
|
const search = ref(modelValue.value?.name ?? '');
|
|
const suggestions = ref<MarketLocation[]>([]);
|
|
|
|
watch(() => modelValue.value, v => {
|
|
search.value = v?.name ?? '';
|
|
});
|
|
|
|
watchDebounced(search, async value => {
|
|
const term = value.trim();
|
|
|
|
if (term.length < 3 || term === modelValue.value?.name) {
|
|
suggestions.value = [];
|
|
} else {
|
|
suggestions.value = await searchMarketLocations(term);
|
|
}
|
|
}, {debounce: 300});
|
|
</script>
|
|
|
|
<template>
|
|
<SelectInput v-model="modelValue" :items="suggestions" class="w-96">
|
|
<template #input>
|
|
<input type="text" v-model="search" placeholder="Search a market location…" />
|
|
</template>
|
|
<template #item="{ item }">
|
|
<div class="px-1 whitespace-nowrap overflow-hidden text-ellipsis" :class="{'text-emerald-400': isDefaultHub(item.id)}">
|
|
{{ item.name }} <span class="text-slate-300">({{ item.regionName }})</span>
|
|
</div>
|
|
</template>
|
|
</SelectInput>
|
|
</template>
|
|
|
|
<style scoped>
|
|
@reference "@/style.css";
|
|
input {
|
|
@apply w-full border-none bg-transparent block focus-visible:outline-none;
|
|
box-sizing: border-box;
|
|
}
|
|
</style>
|