gitlab-org--gitlab-foss/app/assets/javascripts/vue_shared/components/dropdown_keyboard_navigatio...

82 lines
1.9 KiB
Vue

<script>
import { UP_KEY_CODE, DOWN_KEY_CODE, TAB_KEY_CODE } from '~/lib/utils/keycodes';
export default {
model: {
prop: 'index',
event: 'change',
},
props: {
/* v-model property to manage location in list */
index: {
type: Number,
required: true,
},
/* Highest index that can be navigated to */
max: {
type: Number,
required: true,
},
/* Lowest index that can be navigated to */
min: {
type: Number,
required: true,
},
/* Which index to set v-model to on init */
defaultIndex: {
type: Number,
required: true,
},
},
watch: {
max() {
// If the max index (list length) changes, reset the index
this.$emit('change', this.defaultIndex);
},
},
created() {
this.$emit('change', this.defaultIndex);
document.addEventListener('keydown', this.handleKeydown);
},
beforeDestroy() {
document.removeEventListener('keydown', this.handleKeydown);
},
methods: {
handleKeydown(event) {
if (event.keyCode === DOWN_KEY_CODE) {
// Prevents moving scrollbar
event.preventDefault();
event.stopPropagation();
// Moves to next index
this.increment(1);
} else if (event.keyCode === UP_KEY_CODE) {
// Prevents moving scrollbar
event.preventDefault();
event.stopPropagation();
// Moves to previous index
this.increment(-1);
} else if (event.keyCode === TAB_KEY_CODE) {
this.$emit('tab');
}
},
increment(val) {
if (this.max === 0) {
return;
}
const nextIndex = Math.max(this.min, Math.min(this.index + val, this.max));
// Return if the index didn't change
if (nextIndex === this.index) {
return;
}
this.$emit('change', nextIndex);
},
},
render() {
return this.$slots.default;
},
};
</script>