<AutocompleteSelect> support keyboard control

This commit is contained in:
Andrea Vos 2023-01-05 20:34:37 +01:00
parent 6781244940
commit a5dbd7c044

View File

@ -1,10 +1,12 @@
<template> <template>
<div class="select flex-grow-1"> <div class="select flex-grow-1">
<input type="text" v-model="filter" class="form-control" @focus="show" @blur="hide" :placeholder="$t('profile.timezone.placeholder')"/> <input type="text" v-model="filter" class="form-control" :placeholder="$t('profile.timezone.placeholder')"
ref="filter"
@focus="show" @blur="hide" @keydown="filterKeydown"
/>
<div class="list-group shadow" v-show="shown"> <div class="list-group shadow" v-show="shown">
<a v-for="(display, option) in options" <a v-for="(display, option) in visibleOptions"
v-if="!filter || option.toLowerCase().includes(filter.toLowerCase()) || display.toLowerCase().includes(filter.toLowerCase())" :class="['list-group-item', 'list-group-item-action', highlightedOption === option ? 'active' : '']" href="#"
class="list-group-item list-group-item-action" href="#"
@click.prevent="select(option)"> @click.prevent="select(option)">
{{ display }} {{ display }}
</a> </a>
@ -23,17 +25,20 @@ export default {
return { return {
filter: this.options[this.value] || this.value || '', filter: this.options[this.value] || this.value || '',
shown: false, shown: false,
highlighted: -1,
} }
}, },
watch: { watch: {
value() { value() {
this.filter = this.options[this.value] || this.value; this.filter = this.options[this.value] || this.value;
this.highlighted = -1;
}, },
}, },
methods: { methods: {
select(option) { select(option) {
this.$emit('input', option); this.$emit('input', option);
this.hide(); this.hide();
this.highlighted = -1;
}, },
show() { show() {
this.shown = true; this.shown = true;
@ -41,6 +46,42 @@ export default {
hide() { hide() {
setTimeout(() => { this.shown = false; }, 100) setTimeout(() => { this.shown = false; }, 100)
}, },
filterKeydown(e) {
if (!this.shown) {
this.show();
}
switch (e.key) {
case 'ArrowUp':
this.highlighted--;
break;
case 'ArrowDown':
this.highlighted++;
break;
case 'Enter':
if (this.highlightedOption) {
this.select(this.highlightedOption);
}
break;
default:
return;
}
e.preventDefault();
e.stopPropagation();
}
},
computed: {
visibleOptions() {
return Object.fromEntries(Object.entries(this.options).filter(([option, display]) => {
return !this.filter
|| option.toLowerCase().includes(this.filter.toLowerCase())
|| display.toLowerCase().includes(this.filter.toLowerCase())
}));
},
highlightedOption() {
return Object.keys(this.visibleOptions)[this.highlighted];
},
} }
} }
</script> </script>