Skip to content

Commit d410bec

Browse files
author
Milan Poliak
committed
select using arrow keys
alexurquhart#44
1 parent d0bc765 commit d410bec

File tree

3 files changed

+61
-0
lines changed

3 files changed

+61
-0
lines changed

src/components/VueBootstrapTypeahead.vue

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
@focus="isFocused = true"
1717
@blur="handleBlur"
1818
@input="handleInput($event.target.value)"
19+
@keydown="handleKeyDown"
1920
autocomplete="off"
2021
/>
2122
<div v-if="$slots.append || append" class="input-group-append">
@@ -35,6 +36,7 @@
3536
:maxMatches="maxMatches"
3637
:minMatchingChars="minMatchingChars"
3738
@hit="handleHit"
39+
@keydown="handleKeyDown"
3840
>
3941
<!-- pass down all scoped slots -->
4042
<template v-for="(slot, slotName) in $scopedSlots" :slot="slotName" slot-scope="{ data, htmlText }">
@@ -158,6 +160,18 @@ export default {
158160
if (typeof this.value !== 'undefined') {
159161
this.$emit('input', newValue)
160162
}
163+
},
164+
165+
handleKeyDown(evt) {
166+
if (! this.isFocused || this.data.length < 1) return
167+
switch (evt.code) {
168+
case 'ArrowUp':
169+
case 'ArrowDown':
170+
case 'Enter':
171+
evt.preventDefault()
172+
this.$emit('selectionKeyPressed', evt)
173+
break
174+
}
161175
}
162176
},
163177

src/components/VueBootstrapTypeaheadList.vue

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
:background-variant="backgroundVariant"
88
:text-variant="textVariant"
99
@click.native="handleHit(item, $event)"
10+
@keydown="$listeners.keydown"
1011
>
1112
<template v-if="$scopedSlots.suggestion" slot="suggestion" slot-scope="{ data, htmlText }">
1213
<slot name="suggestion" v-bind="{ data, htmlText }" />
@@ -96,8 +97,53 @@ export default {
9697
}).slice(0, this.maxMatches)
9798
}
9899
},
100+
mounted() {
101+
this.$parent.$on('selectionKeyPressed', this.handleSelectionKey.bind(this))
102+
},
99103
100104
methods: {
105+
handleSelectionKey(evt) {
106+
if (this.data.length < 1) return
107+
let active = this.findActiveItemIndex()
108+
let ch = this.$children
109+
switch (evt.code) {
110+
case 'ArrowUp':
111+
this.setActiveItem((active > 0) ? (active - 1) : (ch.length - 1))
112+
break
113+
case 'ArrowDown':
114+
this.setActiveItem((active + 1) % ch.length)
115+
break
116+
case 'Enter':
117+
this.$emit('hit', this.findActiveItem())
118+
break
119+
}
120+
},
121+
findActiveItem() {
122+
let idx = this.findActiveItemIndex()
123+
return (idx < 0) ? null : this.matchedItems[idx]
124+
},
125+
findActiveItemIndex() {
126+
let ch = this.$children
127+
for (let i = 0; i < ch.length; i++) {
128+
let item = ch[i]
129+
if (item.active) {
130+
return i
131+
}
132+
}
133+
return -1
134+
},
135+
setActiveItem(idx) {
136+
this.$children.forEach((item, i) => {
137+
if (i === idx) {
138+
item.active = true
139+
item.$el.scrollIntoView(false)
140+
}
141+
else {
142+
item.active = false
143+
}
144+
})
145+
},
146+
101147
handleHit(item, evt) {
102148
this.$emit('hit', item)
103149
evt.preventDefault()

src/components/VueBootstrapTypeaheadListItem.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
:class="textClasses"
66
@mouseover="active = true"
77
@mouseout="active = false"
8+
@keydown="$listeners.keydown"
89
>
910
<slot name="suggestion" v-bind="{ data: data, htmlText: htmlText }">
1011
<span v-html="htmlText"></span>

0 commit comments

Comments
 (0)