mirror of
https://github.com/tenrok/vue-select.git
synced 2026-06-07 07:12:23 +03:00
fix: Keep focus on input after select to improve accessibility (#1727)
Co-authored-by: Jeff Sagal <sagalbot@gmail.com> Huge thanks to @Pytal for the great work!
This commit is contained in:
@@ -571,7 +571,12 @@ export default {
|
||||
*/
|
||||
selectOnKeyCodes: {
|
||||
type: Array,
|
||||
default: () => [13],
|
||||
default: () => [
|
||||
// enter
|
||||
13,
|
||||
// space
|
||||
32,
|
||||
],
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -953,6 +958,12 @@ export default {
|
||||
open(isOpen) {
|
||||
this.$emit(isOpen ? 'open' : 'close')
|
||||
},
|
||||
|
||||
search(search) {
|
||||
if (search.length) {
|
||||
this.open = true
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
created() {
|
||||
@@ -1035,7 +1046,6 @@ export default {
|
||||
onAfterSelect(option) {
|
||||
if (this.closeOnSelect) {
|
||||
this.open = !this.open
|
||||
this.searchEl.blur()
|
||||
}
|
||||
|
||||
if (this.clearSearchOnSelect) {
|
||||
@@ -1240,7 +1250,7 @@ export default {
|
||||
*/
|
||||
onEscape() {
|
||||
if (!this.search.length) {
|
||||
this.searchEl.blur()
|
||||
this.open = false
|
||||
} else {
|
||||
this.search = ''
|
||||
}
|
||||
@@ -1302,7 +1312,7 @@ export default {
|
||||
|
||||
/**
|
||||
* Search <input> KeyBoardEvent handler.
|
||||
* @param e {KeyboardEvent}
|
||||
* @param {KeyboardEvent} e
|
||||
* @return {Function}
|
||||
*/
|
||||
onSearchKeyDown(e) {
|
||||
@@ -1321,11 +1331,19 @@ export default {
|
||||
// up.prevent
|
||||
38: (e) => {
|
||||
e.preventDefault()
|
||||
if (!this.open) {
|
||||
this.open = true
|
||||
return
|
||||
}
|
||||
return this.typeAheadUp()
|
||||
},
|
||||
// down.prevent
|
||||
40: (e) => {
|
||||
e.preventDefault()
|
||||
if (!this.open) {
|
||||
this.open = true
|
||||
return
|
||||
}
|
||||
return this.typeAheadDown()
|
||||
},
|
||||
}
|
||||
|
||||
@@ -76,12 +76,16 @@ export default {
|
||||
* Moves the pointer to the last selected option.
|
||||
*/
|
||||
typeAheadToLastSelected() {
|
||||
this.typeAheadPointer =
|
||||
const indexOfLastSelected =
|
||||
this.selectedValue.length !== 0
|
||||
? this.filteredOptions.indexOf(
|
||||
this.selectedValue[this.selectedValue.length - 1]
|
||||
)
|
||||
: -1
|
||||
|
||||
if (indexOfLastSelected !== -1) {
|
||||
this.typeAheadPointer = indexOfLastSelected
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -120,12 +120,11 @@ describe('Toggling Dropdown', () => {
|
||||
|
||||
it('will close the dropdown on escape, if search is empty', () => {
|
||||
const Select = selectWithProps()
|
||||
const spy = jest.spyOn(Select.vm.$refs.search, 'blur')
|
||||
|
||||
Select.vm.open = true
|
||||
Select.vm.onEscape()
|
||||
|
||||
expect(spy).toHaveBeenCalled()
|
||||
expect(Select.vm.open).toEqual(false)
|
||||
})
|
||||
|
||||
it('should remove existing search text on escape keydown', () => {
|
||||
|
||||
@@ -83,4 +83,26 @@ describe('Filtering Options', () => {
|
||||
Select.vm.search = '1'
|
||||
expect(Select.vm.filteredOptions).toEqual([1, 10])
|
||||
})
|
||||
|
||||
it('should open dropdown on alphabetic input', async () => {
|
||||
const Select = shallowMount(VueSelect)
|
||||
|
||||
const input = Select.find('.vs__search')
|
||||
input.element.value = 'a'
|
||||
input.trigger('input')
|
||||
await Select.vm.$nextTick()
|
||||
|
||||
expect(Select.vm.open).toEqual(true)
|
||||
})
|
||||
|
||||
it('should open dropdown on numeric input', async () => {
|
||||
const Select = shallowMount(VueSelect)
|
||||
|
||||
const input = Select.find('.vs__search')
|
||||
input.element.value = 1
|
||||
input.trigger('input')
|
||||
await Select.vm.$nextTick()
|
||||
|
||||
expect(Select.vm.open).toEqual(true)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -37,6 +37,7 @@ describe('Selectable prop', () => {
|
||||
selectable: (option) => option !== 'two',
|
||||
})
|
||||
|
||||
Select.vm.open = true
|
||||
Select.vm.typeAheadPointer = 1
|
||||
|
||||
Select.findComponent({ ref: 'search' }).trigger('keydown.down')
|
||||
@@ -50,6 +51,7 @@ describe('Selectable prop', () => {
|
||||
selectable: (option) => option !== 'two',
|
||||
})
|
||||
|
||||
Select.vm.open = true
|
||||
Select.vm.typeAheadPointer = 2
|
||||
|
||||
Select.findComponent({ ref: 'search' }).trigger('keydown.up')
|
||||
|
||||
@@ -20,6 +20,7 @@ describe('Moving the Typeahead Pointer', () => {
|
||||
it('should move the pointer visually up the list on up arrow keyUp', () => {
|
||||
const Select = mountDefault()
|
||||
|
||||
Select.vm.open = true
|
||||
Select.vm.typeAheadPointer = 1
|
||||
|
||||
Select.findComponent({ ref: 'search' }).trigger('keydown.up')
|
||||
@@ -30,6 +31,7 @@ describe('Moving the Typeahead Pointer', () => {
|
||||
it('should move the pointer visually down the list on down arrow keyUp', () => {
|
||||
const Select = mountDefault()
|
||||
|
||||
Select.vm.open = true
|
||||
Select.vm.typeAheadPointer = 1
|
||||
|
||||
Select.findComponent({ ref: 'search' }).trigger('keydown.down')
|
||||
@@ -78,3 +80,23 @@ describe('Moving the Typeahead Pointer', () => {
|
||||
expect(Select.vm.typeAheadPointer).toEqual(2)
|
||||
})
|
||||
})
|
||||
|
||||
it('should not move the pointer visually up the list on up arrow keyUp when dropdown is not open', () => {
|
||||
const Select = mountDefault()
|
||||
|
||||
Select.vm.typeAheadPointer = 1
|
||||
|
||||
Select.findComponent({ ref: 'search' }).trigger('keydown.up')
|
||||
|
||||
expect(Select.vm.typeAheadPointer).toEqual(1)
|
||||
})
|
||||
|
||||
it('should not move the pointer visually down the list on down arrow keyUp when dropdown is not open', () => {
|
||||
const Select = mountDefault()
|
||||
|
||||
Select.vm.typeAheadPointer = 1
|
||||
|
||||
Select.findComponent({ ref: 'search' }).trigger('keydown.down')
|
||||
|
||||
expect(Select.vm.typeAheadPointer).toEqual(1)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user