Skip to content

Commit b71cfa1

Browse files
committed
Handle keyboard focus
Signed-off-by: Christopher Ng <[email protected]>
1 parent 8577536 commit b71cfa1

File tree

1 file changed

+41
-1
lines changed

1 file changed

+41
-1
lines changed

src/components/Select.vue

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,10 +107,11 @@
107107
isOptionDeselectable(option) && index === typeAheadPointer,
108108
'vs__dropdown-option--selected': isOptionSelected(option),
109109
'vs__dropdown-option--highlight': index === typeAheadPointer,
110+
'vs__dropdown-option--kb-focus': hasKeyboardFocusBorder(index),
110111
'vs__dropdown-option--disabled': !selectable(option),
111112
}"
112113
:aria-selected="index === typeAheadPointer ? true : null"
113-
@mouseover="selectable(option) ? (typeAheadPointer = index) : null"
114+
@mousemove="onMouseMove(option, index)"
114115
@click.prevent.stop="selectable(option) ? select(option) : null"
115116
>
116117
<slot name="option" v-bind="normalizeOptionForSlot(option)">
@@ -660,6 +661,15 @@ export default {
660661
},
661662
},
662663
664+
/**
665+
* Display a visible border around dropdown options
666+
* which have keyboard focus.
667+
*/
668+
keyboardFocusBorder: {
669+
type: Boolean,
670+
default: false,
671+
},
672+
663673
/**
664674
* A unique identifier used to generate IDs in HTML.
665675
* Must be unique for every instance of the component.
@@ -675,6 +685,7 @@ export default {
675685
search: '',
676686
open: false,
677687
isComposing: false,
688+
isKeyboardNavigation: false,
678689
pushedTags: [],
679690
// eslint-disable-next-line vue/no-reserved-keys
680691
_value: [], // Internal value managed by Vue Select if no `value` prop is passed
@@ -1134,6 +1145,19 @@ export default {
11341145
return this.isOptionSelected(option) && this.deselectFromDropdown
11351146
},
11361147
1148+
/**
1149+
* Check if the option at the given index should display a
1150+
* keyboard focus border.
1151+
* @param {Number} index
1152+
* @return {Boolean}
1153+
*/
1154+
hasKeyboardFocusBorder(index) {
1155+
if (this.keyboardFocusBorder && this.isKeyboardNavigation) {
1156+
return index === this.typeAheadPointer
1157+
}
1158+
return false
1159+
},
1160+
11371161
/**
11381162
* Determine if two option objects are matching.
11391163
*
@@ -1309,6 +1333,20 @@ export default {
13091333
this.mousedown = false
13101334
},
13111335
1336+
/**
1337+
* Event-Handler for option mousemove
1338+
* @param {Object|String} option
1339+
* @param {Number} index
1340+
* @return {void}
1341+
*/
1342+
onMouseMove(option, index) {
1343+
this.isKeyboardNavigation = false
1344+
if (!this.selectable(option)) {
1345+
return
1346+
}
1347+
this.typeAheadPointer = index
1348+
},
1349+
13121350
/**
13131351
* Search <input> KeyBoardEvent handler.
13141352
* @param {KeyboardEvent} e
@@ -1330,6 +1368,7 @@ export default {
13301368
// up.prevent
13311369
38: (e) => {
13321370
e.preventDefault()
1371+
this.isKeyboardNavigation = true
13331372
if (!this.open) {
13341373
this.open = true
13351374
return
@@ -1339,6 +1378,7 @@ export default {
13391378
// down.prevent
13401379
40: (e) => {
13411380
e.preventDefault()
1381+
this.isKeyboardNavigation = true
13421382
if (!this.open) {
13431383
this.open = true
13441384
return

0 commit comments

Comments
 (0)