2
0
mirror of https://github.com/tenrok/vue-select.git synced 2026-06-10 07:52:23 +03:00
Updates the root $el to be a focusable button instead of a div. Allows for separating focusing of the component from opening the dropdown
This commit is contained in:
Jeff
2020-02-15 11:27:40 -08:00
parent b7c0d539c4
commit b36267373e
4 changed files with 110 additions and 22 deletions
+46 -7
View File
@@ -1,19 +1,42 @@
<template>
<div id="app">
<sandbox hide-help v-slot="config">
<v-select v-bind="config"/>
</sandbox>
</div>
<!-- <div id="app">-->
<!-- <sandbox hide-help v-slot="config">-->
<!-- <v-select v-bind="config"/>-->
<!-- </sandbox>-->
<!-- </div>-->
<form>
<label for="name">Name</label>
<input type="text" id="name" autofocus>
<label for="email">eMail</label>
<input type="email" id="email">
<label for="emails">eMail</label>
<select id="emails">
<option value="one">one</option>
<option value="two">two</option>
</select>
<label for="country">Country</label>
<v-select :options="countries" id="country" :filterable="false" />
<label for="hello">Hello</label>
<input type="text" id="hello">
</form>
</template>
<script>
import vSelect from '../src/components/Select';
import Sandbox from '../docs/.vuepress/components/Sandbox';
// import countries from '../docs/.vuepress/data/countryCodes';
// import books from '../docs/.vuepress/data/books';
import countries from '../docs/.vuepress/data/countryCodes';
import books from '../docs/.vuepress/data/books';
export default {
components: {Sandbox, vSelect},
computed: {
countries: () => countries,
books: () => books,
}
};
</script>
@@ -36,4 +59,20 @@ export default {
padding-top: 1em;
width: 90%;
}
form {
width: 500px;
margin: 0 auto;
padding-top: 5rem;
}
label {
width:100%;
display: block;
margin-top:1rem;
}
input {
width: 100%;
}
</style>
+42 -9
View File
@@ -3,8 +3,7 @@
</style>
<template>
<div :dir="dir" class="v-select" :class="stateClasses">
<div ref="toggle" @mousedown.prevent="toggleDropdown" class="vs__dropdown-toggle">
<button :tabindex="tabindex" type="button" @keydown="keypressWhileToggleIsFocused" ref="toggle" @mousedown.prevent="maybeToggleDropdown" class="v-select vs__dropdown-toggle" :dir="dir" :class="stateClasses">
<div class="vs__selected-options" ref="selectedOptions">
<slot v-for="option in selectedValue"
@@ -49,8 +48,6 @@
<div class="vs__spinner" v-show="mutableLoading">Loading...</div>
</slot>
</div>
</div>
<transition :name="transition">
<ul ref="dropdownMenu" v-if="dropdownOpen" class="vs__dropdown-menu" role="listbox" @mousedown.prevent="onMousedown" @mouseup="onMouseUp">
<li
@@ -71,7 +68,8 @@
</li>
</ul>
</transition>
</div>
</button>
</template>
<script type="text/babel">
@@ -508,6 +506,7 @@
search: '',
open: false,
isComposing: false,
shouldDisplaySearch: true,
pushedTags: [],
_value: [] // Internal value managed by Vue Select if no `value` prop is passed
}
@@ -666,7 +665,7 @@
* @param {Event} e
* @return {void}
*/
toggleDropdown ({target}) {
maybeToggleDropdown ({target}) {
// don't react to click on deselect/clear buttons,
// they dropdown state will be set in their click handlers
const ignoredButtons = [
@@ -678,7 +677,11 @@
return;
}
if (this.open) {
this.toggleDropdown(true);
},
toggleDropdown(toggle = true) {
if (this.open || ! toggle) {
this.searchEl.blur();
} else if (!this.disabled) {
this.open = true;
@@ -829,7 +832,8 @@
if (this.clearSearchOnBlur) {
this.search = ''
}
this.closeSearchOptions()
this.closeSearchOptions();
this.$refs.toggle.focus();
return
}
// Fixed bug where no-options message could not be closed
@@ -907,6 +911,31 @@
if (typeof handlers[e.keyCode] === 'function') {
return handlers[e.keyCode](e);
}
},
/**
* @param e {KeyboardEvent}
*/
keypressWhileToggleIsFocused(e) {
// if( e.target === this.searchEl ) {
// return;
// }
//
// if( 'Tab' === e.code ) {
// e.preventDefault();
// return
// }
//
// if( ['Space', 'Return'].includes(e.code) ) {
// return this.toggleDropdown();
// }
//
// if( ['ShiftLeft', 'ShiftRight'].includes(e.code)) {
// e.preventDefault();
// return;
// }
//
// return this.toggleDropdown()
}
},
@@ -970,7 +999,7 @@
attributes: {
'disabled': this.disabled,
'placeholder': this.searchPlaceholder,
'tabindex': this.tabindex,
'tabindex': '-1',
'readonly': !this.searchable,
'id': this.inputId,
'aria-expanded': this.dropdownOpen,
@@ -1106,6 +1135,10 @@
*/
showClearButton() {
return !this.multiple && this.clearable && !this.open && !this.isValueEmpty
},
buttonIsFocused() {
return this.$el === this.$root.$el.querySelector(':focus');
}
},
+1
View File
@@ -18,6 +18,7 @@ $border-radius: $vs-border-radius;
.vs__dropdown-toggle {
appearance: none;
display: flex;
width: 100%;
padding: 0 0 4px 0;
background: none;
border: $border-width $border-style $border-color;
+21 -6
View File
@@ -1,10 +1,25 @@
import { selectWithProps } from "../helpers";
import { mountDefault, selectWithProps } from '../helpers';
import OpenIndicator from "../../src/components/OpenIndicator";
describe("Toggling Dropdown", () => {
fdescribe('focusing on the button wrapper', () => {
test('when the search is focused buttonIsFocused is false', () => {
const Select = mountDefault();
Select.vm.$refs.search.focus();
expect(Select.vm.buttonIsFocused).toBeFalsy();
})
test('when the button is focused, buttonIsFocused is true', async () => {
const Select = mountDefault();
Select.vm.$refs.toggle.focus();
await Select.vm.$nextTick();
expect(Select.vm.buttonIsFocused).toBeTruthy();
})
});
it("should not open the dropdown when the el is clicked but the component is disabled", () => {
const Select = selectWithProps({ disabled: true });
Select.vm.toggleDropdown({ target: Select.vm.$refs.search });
Select.vm.maybeToggleDropdown({ target: Select.vm.$refs.search });
expect(Select.vm.open).toEqual(false);
});
@@ -14,7 +29,7 @@ describe("Toggling Dropdown", () => {
options: [{ label: "one" }]
});
Select.vm.toggleDropdown({ target: Select.vm.$refs.search });
Select.vm.maybeToggleDropdown({ target: Select.vm.$refs.search });
expect(Select.vm.open).toEqual(true);
});
@@ -26,7 +41,7 @@ describe("Toggling Dropdown", () => {
const selectedTag = Select.find(".vs__selected").element;
Select.vm.toggleDropdown({ target: selectedTag });
Select.vm.maybeToggleDropdown({ target: selectedTag });
expect(Select.vm.open).toEqual(true);
});
@@ -35,7 +50,7 @@ describe("Toggling Dropdown", () => {
const spy = jest.spyOn(Select.vm.$refs.search, "blur");
Select.vm.open = true;
Select.vm.toggleDropdown({ target: Select.vm.$el });
Select.vm.maybeToggleDropdown({ target: Select.vm.$el });
expect(spy).toHaveBeenCalled();
});
@@ -134,7 +149,7 @@ describe("Toggling Dropdown", () => {
noDrop: true,
});
Select.vm.toggleDropdown({ target: Select.vm.$refs.search });
Select.vm.maybeToggleDropdown({ target: Select.vm.$refs.search });
expect(Select.vm.open).toEqual(true);
expect(Select.contains('.vs__dropdown-menu')).toBeFalsy();
expect(Select.vm.stateClasses['vs--open']).toBeFalsy();