82 lines
1.9 KiB
Vue
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>
|