Skip to content

Commit 5ed4be9

Browse files
Merge pull request #1 from mattzollinhofer/a11y-improvements
Various Improvements
2 parents d0bc765 + dafc5b9 commit 5ed4be9

File tree

3 files changed

+97
-19
lines changed

3 files changed

+97
-19
lines changed

src/components/VueBootstrapTypeahead.vue

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
@focus="isFocused = true"
1717
@blur="handleBlur"
1818
@input="handleInput($event.target.value)"
19+
@keyup.down="$emit('keyup.down', $event.target.value)"
20+
@keyup.up="$emit('keyup.up', $event.target.value)"
21+
@keyup.enter="$emit('keyup.enter', $event.target.value)"
1922
autocomplete="off"
2023
/>
2124
<div v-if="$slots.append || append" class="input-group-append">
@@ -34,6 +37,8 @@
3437
:text-variant="textVariant"
3538
:maxMatches="maxMatches"
3639
:minMatchingChars="minMatchingChars"
40+
:showOnFocus="showOnFocus"
41+
:showAllResults="showAllResults"
3742
@hit="handleHit"
3843
>
3944
<!-- pass down all scoped slots -->
@@ -92,6 +97,14 @@ export default {
9297
type: Number,
9398
default: 2
9499
},
100+
showOnFocus: {
101+
type: Boolean,
102+
default: false
103+
},
104+
showAllResults: {
105+
type: Boolean,
106+
default: false
107+
},
95108
placeholder: String,
96109
prepend: String,
97110
append: String
@@ -164,7 +177,7 @@ export default {
164177
data() {
165178
return {
166179
isFocused: false,
167-
inputValue: ''
180+
inputValue: this.value || ''
168181
}
169182
},
170183
@@ -178,6 +191,12 @@ export default {
178191
179192
beforeDestroy() {
180193
this.$_ro.disconnect()
194+
},
195+
196+
watch: {
197+
value: function(val) {
198+
this.inputValue = val;
199+
}
181200
}
182201
}
183202
</script>

src/components/VueBootstrapTypeaheadList.vue

Lines changed: 68 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
<template>
2-
<div class="list-group shadow">
2+
<div class="list-group shadow" ref="suggestionList">
33
<vue-bootstrap-typeahead-list-item
44
v-for="(item, id) in matchedItems" :key="id"
5+
:active="isListItemActive(id)"
56
:data="item.data"
67
:html-text="highlight(item.text)"
78
:background-variant="backgroundVariant"
@@ -56,12 +57,32 @@ export default {
5657
minMatchingChars: {
5758
type: Number,
5859
default: 2
60+
},
61+
showOnFocus: {
62+
type: Boolean,
63+
default: false
64+
},
65+
showAllResults: {
66+
type: Boolean,
67+
default: false
68+
}
69+
},
70+
71+
created() {
72+
this.$parent.$on('input', this.resetActiveListItem)
73+
this.$parent.$on('keyup.down', this.selectNextListItem)
74+
this.$parent.$on('keyup.up', this.selectPreviousListItem)
75+
this.$parent.$on('keyup.enter', this.hitActiveListItem)
76+
},
77+
data() {
78+
return {
79+
activeListItem: -1
5980
}
6081
},
6182
6283
computed: {
6384
highlight() {
64-
return (text) => {
85+
return text => {
6586
text = sanitize(text)
6687
if (this.query.length === 0) {
6788
return text
@@ -77,11 +98,11 @@ export default {
7798
},
7899
79100
matchedItems() {
80-
if (this.query.length === 0 || this.query.length < this.minMatchingChars) {
101+
if (!this.showOnFocus && (this.query.length === 0 || this.query.length < this.minMatchingChars)) {
81102
return []
82103
}
83104
84-
const re = new RegExp(this.escapedQuery, 'gi')
105+
const re = new RegExp(this.showAllResults ? "" : this.escapedQuery, 'gi')
85106
86107
// Filter, sort, and concat
87108
return this.data
@@ -101,6 +122,49 @@ export default {
101122
handleHit(item, evt) {
102123
this.$emit('hit', item)
103124
evt.preventDefault()
125+
},
126+
hitActiveListItem() {
127+
if (this.activeListItem >= 0) {
128+
this.$emit('hit', this.matchedItems[this.activeListItem])
129+
}
130+
},
131+
isListItemActive(id) {
132+
return this.activeListItem === id
133+
},
134+
resetActiveListItem() {
135+
this.activeListItem = -1
136+
},
137+
selectNextListItem() {
138+
if (this.activeListItem < this.matchedItems.length - 1) {
139+
this.activeListItem++
140+
} else {
141+
this.activeListItem = -1
142+
}
143+
},
144+
selectPreviousListItem() {
145+
if (this.activeListItem < 0) {
146+
this.activeListItem = this.matchedItems.length - 1
147+
} else {
148+
this.activeListItem--
149+
}
150+
}
151+
},
152+
watch: {
153+
activeListItem(newValue, oldValue) {
154+
if (newValue >= 0) {
155+
const scrollContainer = this.$refs.suggestionList
156+
const listItem = scrollContainer.children[this.activeListItem]
157+
const scrollContainerlHeight = scrollContainer.clientHeight
158+
const listItemHeight = listItem.clientHeight
159+
const visibleItems = Math.floor(
160+
scrollContainerlHeight / (listItemHeight + 20)
161+
)
162+
if (newValue >= visibleItems) {
163+
scrollContainer.scrollTop = listItemHeight * this.activeListItem
164+
} else {
165+
scrollContainer.scrollTop = 0
166+
}
167+
}
104168
}
105169
}
106170
}

src/components/VueBootstrapTypeaheadListItem.vue

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
tabindex="0"
44
href="#"
55
:class="textClasses"
6-
@mouseover="active = true"
7-
@mouseout="active = false"
86
>
97
<slot name="suggestion" v-bind="{ data: data, htmlText: htmlText }">
108
<span v-html="htmlText"></span>
@@ -16,7 +14,10 @@
1614
export default {
1715
name: 'VueBootstrapTypeaheadListItem',
1816
19-
props: {
17+
props: {
18+
active: {
19+
type: Boolean
20+
},
2021
data: {},
2122
htmlText: {
2223
type: String
@@ -29,19 +30,13 @@ export default {
2930
}
3031
},
3132
32-
data() {
33-
return {
34-
active: false
35-
}
36-
},
37-
3833
computed: {
3934
textClasses() {
40-
let classes = ''
41-
classes += this.active ? 'active' : ''
42-
classes += this.backgroundVariant ? ` bg-${this.backgroundVariant}` : ''
43-
classes += this.textVariant ? ` text-${this.textVariant}` : ''
44-
return `vbst-item list-group-item list-group-item-action ${classes}`
35+
const classes = ['vbst-item', 'list-group-item', 'list-group-item-action']
36+
if (this.active) classes.push('active')
37+
if (this.backgroundVariant) classes.push(`bg-${this.backgroundVariant}`)
38+
if (this.textVariant) classes.push(`text-${this.textVariant}`)
39+
return classes.join(' ')
4540
}
4641
}
4742
}

0 commit comments

Comments
 (0)