mirror of
https://github.com/tenrok/vue-select.git
synced 2026-06-22 10:30:34 +03:00
Merge branch 'master' into customizable-text
This commit is contained in:
@@ -19,6 +19,7 @@ export default {
|
|||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
height: {
|
height: {
|
||||||
|
type: [String, Number],
|
||||||
default: 250,
|
default: 250,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<ul>
|
<ul>
|
||||||
<li v-for="{ login, avatar_url, html_url, contributions } in contributors">
|
<li
|
||||||
|
v-for="{ login, avatar_url, html_url, contributions } in contributors"
|
||||||
|
:key="login"
|
||||||
|
>
|
||||||
<img :src="`${avatar_url}&s=75`" :alt="`${login}'s Avatar`" />
|
<img :src="`${avatar_url}&s=75`" :alt="`${login}'s Avatar`" />
|
||||||
<div>
|
<div>
|
||||||
<a :href="html_url">@{{ login }}</a>
|
<a :href="html_url">@{{ login }}</a>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
<th>Country</th>
|
<th>Country</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-for="person in people">
|
<tr v-for="person in people" :key="person.name">
|
||||||
<td>{{ person.name }}</td>
|
<td>{{ person.name }}</td>
|
||||||
<td>
|
<td>
|
||||||
<v-select
|
<v-select
|
||||||
|
|||||||
@@ -188,11 +188,11 @@
|
|||||||
v-bind="configuration"
|
v-bind="configuration"
|
||||||
placeholder="country objects, using option scoped slots"
|
placeholder="country objects, using option scoped slots"
|
||||||
>
|
>
|
||||||
<template slot="selected-option" slot-scope="{ label, value }">
|
<template slot="selected-option" slot-scope="option">
|
||||||
{{ label }} -- {{ value }}
|
{{ option.label }} -- {{ option.value }}
|
||||||
</template>
|
</template>
|
||||||
<template slot="option" slot-scope="{ label, value }">
|
<template slot="option" slot-scope="option">
|
||||||
{{ label }} ({{ value }})
|
{{ option.label }} ({{ option.value }})
|
||||||
</template>
|
</template>
|
||||||
</v-select>
|
</v-select>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-select>
|
<v-select>
|
||||||
|
<!-- eslint-disable-next-line vue/no-unused-vars -->
|
||||||
<template #no-options="{ search, searching, loading }">
|
<template #no-options="{ search, searching, loading }">
|
||||||
This is the no options slot.
|
This is the no options slot.
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
|
<!-- eslint-disable vue/no-unused-vars -->
|
||||||
<v-select :options="books" label="title">
|
<v-select :options="books" label="title">
|
||||||
<template
|
<template
|
||||||
#selected-option-container="{ option, deselect, multiple, disabled }"
|
#selected-option-container="{ option, deselect, multiple, disabled }"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<ul>
|
<ul>
|
||||||
<li v-for="{ createdAt, login, avatarUrl } in sponsors">
|
<li v-for="{ createdAt, login, avatarUrl } in sponsors" :key="login">
|
||||||
<img :src="avatarUrl + '&s=150'" :alt="`@${login}'s avatar`" />
|
<img :src="avatarUrl + '&s=150'" :alt="`@${login}'s avatar`" />
|
||||||
<p>
|
<p>
|
||||||
<a :href="`https://github.com/${login}`">@{{ login }}</a> <br />
|
<a :href="`https://github.com/${login}`">@{{ login }}</a> <br />
|
||||||
|
|||||||
+184
-149
@@ -8,12 +8,12 @@
|
|||||||
<div
|
<div
|
||||||
:id="`vs${uid}__combobox`"
|
:id="`vs${uid}__combobox`"
|
||||||
ref="toggle"
|
ref="toggle"
|
||||||
@mousedown="toggleDropdown($event)"
|
|
||||||
class="vs__dropdown-toggle"
|
class="vs__dropdown-toggle"
|
||||||
role="combobox"
|
role="combobox"
|
||||||
:aria-expanded="dropdownOpen.toString()"
|
:aria-expanded="dropdownOpen.toString()"
|
||||||
:aria-owns="`vs${uid}__listbox`"
|
:aria-owns="`vs${uid}__listbox`"
|
||||||
:aria-label="i18n.search.ariaLabel"
|
aria-label="Search for option"
|
||||||
|
@mousedown="toggleDropdown($event)"
|
||||||
>
|
>
|
||||||
<div ref="selectedOptions" class="vs__selected-options">
|
<div ref="selectedOptions" class="vs__selected-options">
|
||||||
<slot
|
<slot
|
||||||
@@ -33,15 +33,13 @@
|
|||||||
</slot>
|
</slot>
|
||||||
<button
|
<button
|
||||||
v-if="multiple"
|
v-if="multiple"
|
||||||
|
ref="deselectButtons"
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
@click="deselect(option)"
|
|
||||||
type="button"
|
type="button"
|
||||||
class="vs__deselect"
|
class="vs__deselect"
|
||||||
:title="i18n.deselectButton.ariaLabel(getOptionLabel(option))"
|
:title="`Deselect ${getOptionLabel(option)}`"
|
||||||
:aria-label="
|
:aria-label="`Deselect ${getOptionLabel(option)}`"
|
||||||
i18n.deselectButton.ariaLabel(getOptionLabel(option))
|
@click="deselect(option)"
|
||||||
"
|
|
||||||
ref="deselectButtons"
|
|
||||||
>
|
>
|
||||||
<component :is="childComponents.Deselect" />
|
<component :is="childComponents.Deselect" />
|
||||||
</button>
|
</button>
|
||||||
@@ -60,13 +58,13 @@
|
|||||||
<div ref="actions" class="vs__actions">
|
<div ref="actions" class="vs__actions">
|
||||||
<button
|
<button
|
||||||
v-show="showClearButton"
|
v-show="showClearButton"
|
||||||
|
ref="clearButton"
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
type="button"
|
type="button"
|
||||||
@click="clearSelection"
|
|
||||||
class="vs__clear"
|
class="vs__clear"
|
||||||
title="i18n.clearButton.ariaLabel"
|
title="Clear Selected"
|
||||||
aria-label="i18n.clearButton.ariaLabel"
|
aria-label="Clear Selected"
|
||||||
ref="clearButton"
|
@click="clearSelection"
|
||||||
>
|
>
|
||||||
<component :is="childComponents.Deselect" />
|
<component :is="childComponents.Deselect" />
|
||||||
</button>
|
</button>
|
||||||
@@ -80,31 +78,29 @@
|
|||||||
</slot>
|
</slot>
|
||||||
|
|
||||||
<slot name="spinner" v-bind="scope.spinner">
|
<slot name="spinner" v-bind="scope.spinner">
|
||||||
<div v-show="mutableLoading" class="vs__spinner">
|
<div v-show="mutableLoading" class="vs__spinner">Loading...</div>
|
||||||
{{ i18n.spinner.text }}
|
|
||||||
</div>
|
|
||||||
</slot>
|
</slot>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<transition :name="transition">
|
<transition :name="transition">
|
||||||
<ul
|
<ul
|
||||||
ref="dropdownMenu"
|
|
||||||
v-if="dropdownOpen"
|
v-if="dropdownOpen"
|
||||||
:id="`vs${uid}__listbox`"
|
:id="`vs${uid}__listbox`"
|
||||||
|
ref="dropdownMenu"
|
||||||
:key="`vs${uid}__listbox`"
|
:key="`vs${uid}__listbox`"
|
||||||
|
v-append-to-body
|
||||||
class="vs__dropdown-menu"
|
class="vs__dropdown-menu"
|
||||||
role="listbox"
|
role="listbox"
|
||||||
|
tabindex="-1"
|
||||||
@mousedown.prevent="onMousedown"
|
@mousedown.prevent="onMousedown"
|
||||||
@mouseup="onMouseUp"
|
@mouseup="onMouseUp"
|
||||||
tabindex="-1"
|
|
||||||
v-append-to-body
|
|
||||||
>
|
>
|
||||||
<slot name="list-header" v-bind="scope.listHeader" />
|
<slot name="list-header" v-bind="scope.listHeader" />
|
||||||
<li
|
<li
|
||||||
v-for="(option, index) in filteredOptions"
|
v-for="(option, index) in filteredOptions"
|
||||||
role="option"
|
|
||||||
:key="getOptionKey(option)"
|
|
||||||
:id="`vs${uid}__option-${index}`"
|
:id="`vs${uid}__option-${index}`"
|
||||||
|
:key="getOptionKey(option)"
|
||||||
|
role="option"
|
||||||
class="vs__dropdown-option"
|
class="vs__dropdown-option"
|
||||||
:class="{
|
:class="{
|
||||||
'vs__dropdown-option--selected': isOptionSelected(option),
|
'vs__dropdown-option--selected': isOptionSelected(option),
|
||||||
@@ -120,9 +116,9 @@
|
|||||||
</slot>
|
</slot>
|
||||||
</li>
|
</li>
|
||||||
<li v-if="filteredOptions.length === 0" class="vs__no-options">
|
<li v-if="filteredOptions.length === 0" class="vs__no-options">
|
||||||
<slot name="no-options" v-bind="scope.noOptions">{{
|
<slot name="no-options" v-bind="scope.noOptions"
|
||||||
i18n.noOptions.text
|
>Sorry, no matching options.</slot
|
||||||
}}</slot>
|
>
|
||||||
</li>
|
</li>
|
||||||
<slot name="list-footer" v-bind="scope.listFooter" />
|
<slot name="list-footer" v-bind="scope.listFooter" />
|
||||||
</ul>
|
</ul>
|
||||||
@@ -137,13 +133,10 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script type="text/babel">
|
<script>
|
||||||
import {
|
import pointerScroll from '../mixins/pointerScroll'
|
||||||
ajax,
|
import typeAheadPointer from '../mixins/typeAheadPointer'
|
||||||
pointerScroll,
|
import ajax from '../mixins/ajax'
|
||||||
i18n,
|
|
||||||
pointer as typeAheadPointer,
|
|
||||||
} from '../mixins'
|
|
||||||
import childComponents from './childComponents'
|
import childComponents from './childComponents'
|
||||||
import appendToBody from '../directives/appendToBody'
|
import appendToBody from '../directives/appendToBody'
|
||||||
import sortAndStringify from '../utility/sortAndStringify'
|
import sortAndStringify from '../utility/sortAndStringify'
|
||||||
@@ -157,7 +150,7 @@ export default {
|
|||||||
|
|
||||||
directives: { appendToBody },
|
directives: { appendToBody },
|
||||||
|
|
||||||
mixins: [pointerScroll, typeAheadPointer, ajax, i18n],
|
mixins: [pointerScroll, typeAheadPointer, ajax],
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
/**
|
/**
|
||||||
@@ -166,6 +159,7 @@ export default {
|
|||||||
* using 'change' event using v-on
|
* using 'change' event using v-on
|
||||||
* @type {Object||String||null}
|
* @type {Object||String||null}
|
||||||
*/
|
*/
|
||||||
|
// eslint-disable-next-line vue/require-default-prop,vue/require-prop-types
|
||||||
value: {},
|
value: {},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -529,6 +523,7 @@ export default {
|
|||||||
* @type {String}
|
* @type {String}
|
||||||
* @default {null}
|
* @default {null}
|
||||||
*/
|
*/
|
||||||
|
// eslint-disable-next-line vue/require-default-prop
|
||||||
inputId: {
|
inputId: {
|
||||||
type: String,
|
type: String,
|
||||||
},
|
},
|
||||||
@@ -582,6 +577,7 @@ export default {
|
|||||||
* for the search input. Can be used to implement
|
* for the search input. Can be used to implement
|
||||||
* custom behaviour for key presses.
|
* custom behaviour for key presses.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
mapKeydown: {
|
mapKeydown: {
|
||||||
type: Function,
|
type: Function,
|
||||||
/**
|
/**
|
||||||
@@ -653,6 +649,7 @@ export default {
|
|||||||
open: false,
|
open: false,
|
||||||
isComposing: false,
|
isComposing: false,
|
||||||
pushedTags: [],
|
pushedTags: [],
|
||||||
|
// eslint-disable-next-line vue/no-reserved-keys
|
||||||
_value: [], // Internal value managed by Vue Select if no `value` prop is passed
|
_value: [], // Internal value managed by Vue Select if no `value` prop is passed
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -664,7 +661,10 @@ export default {
|
|||||||
* @return {boolean}
|
* @return {boolean}
|
||||||
*/
|
*/
|
||||||
isTrackingValues() {
|
isTrackingValues() {
|
||||||
return typeof this.value === 'undefined' || this.$options.propsData.hasOwnProperty('reduce');
|
return (
|
||||||
|
typeof this.value === 'undefined' ||
|
||||||
|
this.$options.propsData.hasOwnProperty('reduce')
|
||||||
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -672,17 +672,17 @@ export default {
|
|||||||
* @return {Array}
|
* @return {Array}
|
||||||
*/
|
*/
|
||||||
selectedValue() {
|
selectedValue() {
|
||||||
let value = this.value;
|
let value = this.value
|
||||||
if (this.isTrackingValues) {
|
if (this.isTrackingValues) {
|
||||||
// Vue select has to manage value internally
|
// Vue select has to manage value internally
|
||||||
value = this.$data._value;
|
value = this.$data._value
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value) {
|
if (value) {
|
||||||
return [].concat(value);
|
return [].concat(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
return [];
|
return []
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -693,7 +693,7 @@ export default {
|
|||||||
* @return {Array}
|
* @return {Array}
|
||||||
*/
|
*/
|
||||||
optionList() {
|
optionList() {
|
||||||
return this.options.concat(this.pushTags ? this.pushedTags : []);
|
return this.options.concat(this.pushTags ? this.pushedTags : [])
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -702,8 +702,10 @@ export default {
|
|||||||
*/
|
*/
|
||||||
searchEl() {
|
searchEl() {
|
||||||
return !!this.$scopedSlots['search']
|
return !!this.$scopedSlots['search']
|
||||||
? this.$refs.selectedOptions.querySelector(this.searchInputQuerySelector)
|
? this.$refs.selectedOptions.querySelector(
|
||||||
: this.$refs.search;
|
this.searchInputQuerySelector
|
||||||
|
)
|
||||||
|
: this.$refs.search
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -715,38 +717,40 @@ export default {
|
|||||||
search: this.search,
|
search: this.search,
|
||||||
loading: this.loading,
|
loading: this.loading,
|
||||||
searching: this.searching,
|
searching: this.searching,
|
||||||
filteredOptions: this.filteredOptions
|
filteredOptions: this.filteredOptions,
|
||||||
};
|
}
|
||||||
return {
|
return {
|
||||||
search: {
|
search: {
|
||||||
attributes: {
|
attributes: {
|
||||||
'disabled': this.disabled,
|
disabled: this.disabled,
|
||||||
'placeholder': this.searchPlaceholder,
|
placeholder: this.searchPlaceholder,
|
||||||
'tabindex': this.tabindex,
|
tabindex: this.tabindex,
|
||||||
'readonly': !this.searchable,
|
readonly: !this.searchable,
|
||||||
'id': this.inputId,
|
id: this.inputId,
|
||||||
'aria-autocomplete': 'list',
|
'aria-autocomplete': 'list',
|
||||||
'aria-labelledby': `vs${this.uid}__combobox`,
|
'aria-labelledby': `vs${this.uid}__combobox`,
|
||||||
'aria-controls': `vs${this.uid}__listbox`,
|
'aria-controls': `vs${this.uid}__listbox`,
|
||||||
'ref': 'search',
|
ref: 'search',
|
||||||
'type': 'search',
|
type: 'search',
|
||||||
'autocomplete': this.autocomplete,
|
autocomplete: this.autocomplete,
|
||||||
'value': this.search,
|
value: this.search,
|
||||||
...(this.dropdownOpen && this.filteredOptions[this.typeAheadPointer] ? {
|
...(this.dropdownOpen && this.filteredOptions[this.typeAheadPointer]
|
||||||
'aria-activedescendant': `vs${this.uid}__option-${this.typeAheadPointer}`
|
? {
|
||||||
} : {}),
|
'aria-activedescendant': `vs${this.uid}__option-${this.typeAheadPointer}`,
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
},
|
},
|
||||||
events: {
|
events: {
|
||||||
'compositionstart': () => this.isComposing = true,
|
compositionstart: () => (this.isComposing = true),
|
||||||
'compositionend': () => this.isComposing = false,
|
compositionend: () => (this.isComposing = false),
|
||||||
'keydown': this.onSearchKeyDown,
|
keydown: this.onSearchKeyDown,
|
||||||
'blur': this.onSearchBlur,
|
blur: this.onSearchBlur,
|
||||||
'focus': this.onSearchFocus,
|
focus: this.onSearchFocus,
|
||||||
'input': (e) => this.search = e.target.value,
|
input: (e) => (this.search = e.target.value),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
spinner: {
|
spinner: {
|
||||||
loading: this.mutableLoading
|
loading: this.mutableLoading,
|
||||||
},
|
},
|
||||||
noOptions: {
|
noOptions: {
|
||||||
search: this.search,
|
search: this.search,
|
||||||
@@ -755,16 +759,16 @@ export default {
|
|||||||
},
|
},
|
||||||
openIndicator: {
|
openIndicator: {
|
||||||
attributes: {
|
attributes: {
|
||||||
'ref': 'openIndicator',
|
ref: 'openIndicator',
|
||||||
'role': 'presentation',
|
role: 'presentation',
|
||||||
'class': 'vs__open-indicator',
|
class: 'vs__open-indicator',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
listHeader: listSlot,
|
listHeader: listSlot,
|
||||||
listFooter: listSlot,
|
listFooter: listSlot,
|
||||||
header: { ...listSlot, deselect: this.deselect },
|
header: { ...listSlot, deselect: this.deselect },
|
||||||
footer: { ...listSlot, deselect: this.deselect }
|
footer: { ...listSlot, deselect: this.deselect },
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -777,8 +781,8 @@ export default {
|
|||||||
childComponents() {
|
childComponents() {
|
||||||
return {
|
return {
|
||||||
...childComponents,
|
...childComponents,
|
||||||
...this.components
|
...this.components,
|
||||||
};
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -793,7 +797,7 @@ export default {
|
|||||||
'vs--searchable': this.searchable && !this.noDrop,
|
'vs--searchable': this.searchable && !this.noDrop,
|
||||||
'vs--unsearchable': !this.searchable,
|
'vs--unsearchable': !this.searchable,
|
||||||
'vs--loading': this.mutableLoading,
|
'vs--loading': this.mutableLoading,
|
||||||
'vs--disabled': this.disabled
|
'vs--disabled': this.disabled,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -812,7 +816,7 @@ export default {
|
|||||||
* @return {Boolean} True if open
|
* @return {Boolean} True if open
|
||||||
*/
|
*/
|
||||||
dropdownOpen() {
|
dropdownOpen() {
|
||||||
return this.dropdownShouldOpen(this);
|
return this.dropdownShouldOpen(this)
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -821,9 +825,9 @@ export default {
|
|||||||
* @return {String} Placeholder text
|
* @return {String} Placeholder text
|
||||||
*/
|
*/
|
||||||
searchPlaceholder() {
|
searchPlaceholder() {
|
||||||
if (this.isValueEmpty && this.placeholder) {
|
return this.isValueEmpty && this.placeholder
|
||||||
return this.placeholder;
|
? this.placeholder
|
||||||
}
|
: undefined
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -835,20 +839,22 @@ export default {
|
|||||||
* @return {array}
|
* @return {array}
|
||||||
*/
|
*/
|
||||||
filteredOptions() {
|
filteredOptions() {
|
||||||
const optionList = [].concat(this.optionList);
|
const optionList = [].concat(this.optionList)
|
||||||
|
|
||||||
if (!this.filterable && !this.taggable) {
|
if (!this.filterable && !this.taggable) {
|
||||||
return optionList;
|
return optionList
|
||||||
}
|
}
|
||||||
|
|
||||||
let options = this.search.length ? this.filter(optionList, this.search, this) : optionList;
|
let options = this.search.length
|
||||||
|
? this.filter(optionList, this.search, this)
|
||||||
|
: optionList
|
||||||
if (this.taggable && this.search.length) {
|
if (this.taggable && this.search.length) {
|
||||||
const createdOption = this.createOption(this.search);
|
const createdOption = this.createOption(this.search)
|
||||||
if (!this.optionExists(createdOption)) {
|
if (!this.optionExists(createdOption)) {
|
||||||
options.unshift(createdOption);
|
options.unshift(createdOption)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return options;
|
return options
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -856,7 +862,7 @@ export default {
|
|||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
*/
|
*/
|
||||||
isValueEmpty() {
|
isValueEmpty() {
|
||||||
return this.selectedValue.length === 0;
|
return this.selectedValue.length === 0
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -864,7 +870,9 @@ export default {
|
|||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
*/
|
*/
|
||||||
showClearButton() {
|
showClearButton() {
|
||||||
return !this.multiple && this.clearable && !this.open && !this.isValueEmpty
|
return (
|
||||||
|
!this.multiple && this.clearable && !this.open && !this.isValueEmpty
|
||||||
|
)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -877,16 +885,21 @@ export default {
|
|||||||
* @return {[type]} [description]
|
* @return {[type]} [description]
|
||||||
*/
|
*/
|
||||||
options(newOptions, oldOptions) {
|
options(newOptions, oldOptions) {
|
||||||
let shouldReset = () => typeof this.resetOnOptionsChange === 'function'
|
let shouldReset = () =>
|
||||||
? this.resetOnOptionsChange(newOptions, oldOptions, this.selectedValue)
|
typeof this.resetOnOptionsChange === 'function'
|
||||||
: this.resetOnOptionsChange;
|
? this.resetOnOptionsChange(
|
||||||
|
newOptions,
|
||||||
|
oldOptions,
|
||||||
|
this.selectedValue
|
||||||
|
)
|
||||||
|
: this.resetOnOptionsChange
|
||||||
|
|
||||||
if (!this.taggable && shouldReset()) {
|
if (!this.taggable && shouldReset()) {
|
||||||
this.clearSelection();
|
this.clearSelection()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.value && this.isTrackingValues) {
|
if (this.value && this.isTrackingValues) {
|
||||||
this.setInternalValueFromOptions(this.value);
|
this.setInternalValueFromOptions(this.value)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -903,7 +916,6 @@ export default {
|
|||||||
/**
|
/**
|
||||||
* Always reset the value when
|
* Always reset the value when
|
||||||
* the multiple prop changes.
|
* the multiple prop changes.
|
||||||
* @param {Boolean} isMultiple
|
|
||||||
* @return {void}
|
* @return {void}
|
||||||
*/
|
*/
|
||||||
multiple() {
|
multiple() {
|
||||||
@@ -911,14 +923,14 @@ export default {
|
|||||||
},
|
},
|
||||||
|
|
||||||
open(isOpen) {
|
open(isOpen) {
|
||||||
this.$emit(isOpen ? 'open' : 'close');
|
this.$emit(isOpen ? 'open' : 'close')
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
created() {
|
created() {
|
||||||
this.mutableLoading = this.loading;
|
this.mutableLoading = this.loading
|
||||||
|
|
||||||
if (typeof this.value !== "undefined" && this.isTrackingValues) {
|
if (typeof this.value !== 'undefined' && this.isTrackingValues) {
|
||||||
this.setInternalValueFromOptions(this.value)
|
this.setInternalValueFromOptions(this.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -934,9 +946,11 @@ export default {
|
|||||||
*/
|
*/
|
||||||
setInternalValueFromOptions(value) {
|
setInternalValueFromOptions(value) {
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
this.$data._value = value.map(val => this.findOptionFromReducedValue(val));
|
this.$data._value = value.map((val) =>
|
||||||
|
this.findOptionFromReducedValue(val)
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
this.$data._value = this.findOptionFromReducedValue(value);
|
this.$data._value = this.findOptionFromReducedValue(value)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -946,16 +960,16 @@ export default {
|
|||||||
* @return {void}
|
* @return {void}
|
||||||
*/
|
*/
|
||||||
select(option) {
|
select(option) {
|
||||||
this.$emit('option:selecting', option);
|
this.$emit('option:selecting', option)
|
||||||
if (!this.isOptionSelected(option)) {
|
if (!this.isOptionSelected(option)) {
|
||||||
if (this.taggable && !this.optionExists(option)) {
|
if (this.taggable && !this.optionExists(option)) {
|
||||||
this.$emit('option:created', option);
|
this.$emit('option:created', option)
|
||||||
}
|
}
|
||||||
if (this.multiple) {
|
if (this.multiple) {
|
||||||
option = this.selectedValue.concat(option)
|
option = this.selectedValue.concat(option)
|
||||||
}
|
}
|
||||||
this.updateValue(option);
|
this.updateValue(option)
|
||||||
this.$emit('option:selected', option);
|
this.$emit('option:selected', option)
|
||||||
}
|
}
|
||||||
this.onAfterSelect(option)
|
this.onAfterSelect(option)
|
||||||
},
|
},
|
||||||
@@ -966,11 +980,13 @@ export default {
|
|||||||
* @return {void}
|
* @return {void}
|
||||||
*/
|
*/
|
||||||
deselect(option) {
|
deselect(option) {
|
||||||
this.$emit('option:deselecting', option);
|
this.$emit('option:deselecting', option)
|
||||||
this.updateValue(this.selectedValue.filter(val => {
|
this.updateValue(
|
||||||
return !this.optionComparator(val, option);
|
this.selectedValue.filter((val) => {
|
||||||
}));
|
return !this.optionComparator(val, option)
|
||||||
this.$emit('option:deselected', option);
|
})
|
||||||
|
)
|
||||||
|
this.$emit('option:deselected', option)
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -988,7 +1004,7 @@ export default {
|
|||||||
*/
|
*/
|
||||||
onAfterSelect(option) {
|
onAfterSelect(option) {
|
||||||
if (this.closeOnSelect) {
|
if (this.closeOnSelect) {
|
||||||
this.open = !this.open;
|
this.open = !this.open
|
||||||
this.searchEl.blur()
|
this.searchEl.blur()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1008,18 +1024,18 @@ export default {
|
|||||||
updateValue(value) {
|
updateValue(value) {
|
||||||
if (typeof this.value === 'undefined') {
|
if (typeof this.value === 'undefined') {
|
||||||
// Vue select has to manage value
|
// Vue select has to manage value
|
||||||
this.$data._value = value;
|
this.$data._value = value
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value !== null) {
|
if (value !== null) {
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
value = value.map(val => this.reduce(val));
|
value = value.map((val) => this.reduce(val))
|
||||||
} else {
|
} else {
|
||||||
value = this.reduce(value);
|
value = this.reduce(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$emit('input', value);
|
this.$emit('input', value)
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1028,9 +1044,9 @@ export default {
|
|||||||
* @return {void}
|
* @return {void}
|
||||||
*/
|
*/
|
||||||
toggleDropdown(event) {
|
toggleDropdown(event) {
|
||||||
const targetIsNotSearch = event.target !== this.searchEl;
|
const targetIsNotSearch = event.target !== this.searchEl
|
||||||
if (targetIsNotSearch) {
|
if (targetIsNotSearch) {
|
||||||
event.preventDefault();
|
event.preventDefault()
|
||||||
}
|
}
|
||||||
|
|
||||||
// don't react to click on deselect/clear buttons,
|
// don't react to click on deselect/clear buttons,
|
||||||
@@ -1038,18 +1054,23 @@ export default {
|
|||||||
const ignoredButtons = [
|
const ignoredButtons = [
|
||||||
...(this.$refs['deselectButtons'] || []),
|
...(this.$refs['deselectButtons'] || []),
|
||||||
...([this.$refs['clearButton']] || []),
|
...([this.$refs['clearButton']] || []),
|
||||||
];
|
]
|
||||||
|
|
||||||
if (this.searchEl === undefined || ignoredButtons.filter(Boolean).some(ref => ref.contains(event.target) || ref === event.target)) {
|
if (
|
||||||
event.preventDefault();
|
this.searchEl === undefined ||
|
||||||
return;
|
ignoredButtons
|
||||||
|
.filter(Boolean)
|
||||||
|
.some((ref) => ref.contains(event.target) || ref === event.target)
|
||||||
|
) {
|
||||||
|
event.preventDefault()
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.open && targetIsNotSearch) {
|
if (this.open && targetIsNotSearch) {
|
||||||
this.searchEl.blur();
|
this.searchEl.blur()
|
||||||
} else if (!this.disabled) {
|
} else if (!this.disabled) {
|
||||||
this.open = true;
|
this.open = true
|
||||||
this.searchEl.focus();
|
this.searchEl.focus()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -1059,7 +1080,9 @@ export default {
|
|||||||
* @return {Boolean} True when selected | False otherwise
|
* @return {Boolean} True when selected | False otherwise
|
||||||
*/
|
*/
|
||||||
isOptionSelected(option) {
|
isOptionSelected(option) {
|
||||||
return this.selectedValue.some(value => this.optionComparator(value, option))
|
return this.selectedValue.some((value) =>
|
||||||
|
this.optionComparator(value, option)
|
||||||
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1070,7 +1093,7 @@ export default {
|
|||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
optionComparator(a, b) {
|
optionComparator(a, b) {
|
||||||
return this.getOptionKey(a) === this.getOptionKey(b);
|
return this.getOptionKey(a) === this.getOptionKey(b)
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1082,15 +1105,13 @@ export default {
|
|||||||
* @returns {*}
|
* @returns {*}
|
||||||
*/
|
*/
|
||||||
findOptionFromReducedValue(value) {
|
findOptionFromReducedValue(value) {
|
||||||
const predicate = option => JSON.stringify(this.reduce(option)) === JSON.stringify(value);
|
const predicate = (option) =>
|
||||||
|
JSON.stringify(this.reduce(option)) === JSON.stringify(value)
|
||||||
|
|
||||||
const matches = [
|
const matches = [...this.options, ...this.pushedTags].filter(predicate)
|
||||||
...this.options,
|
|
||||||
...this.pushedTags,
|
|
||||||
].filter(predicate);
|
|
||||||
|
|
||||||
if (matches.length === 1) {
|
if (matches.length === 1) {
|
||||||
return matches[0];
|
return matches[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1099,7 +1120,11 @@ export default {
|
|||||||
* unique reduced value.
|
* unique reduced value.
|
||||||
* @see https://github.com/sagalbot/vue-select/issues/1089#issuecomment-597238735
|
* @see https://github.com/sagalbot/vue-select/issues/1089#issuecomment-597238735
|
||||||
*/
|
*/
|
||||||
return matches.find(match => this.optionComparator(match, this.$data._value)) || value;
|
return (
|
||||||
|
matches.find((match) =>
|
||||||
|
this.optionComparator(match, this.$data._value)
|
||||||
|
) || value
|
||||||
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1118,10 +1143,17 @@ export default {
|
|||||||
* @return {this.value}
|
* @return {this.value}
|
||||||
*/
|
*/
|
||||||
maybeDeleteValue() {
|
maybeDeleteValue() {
|
||||||
if (!this.searchEl.value.length && this.selectedValue && this.selectedValue.length && this.clearable) {
|
if (
|
||||||
let value = null;
|
!this.searchEl.value.length &&
|
||||||
|
this.selectedValue &&
|
||||||
|
this.selectedValue.length &&
|
||||||
|
this.clearable
|
||||||
|
) {
|
||||||
|
let value = null
|
||||||
if (this.multiple) {
|
if (this.multiple) {
|
||||||
value = [...this.selectedValue.slice(0, this.selectedValue.length - 1)]
|
value = [
|
||||||
|
...this.selectedValue.slice(0, this.selectedValue.length - 1),
|
||||||
|
]
|
||||||
}
|
}
|
||||||
this.updateValue(value)
|
this.updateValue(value)
|
||||||
}
|
}
|
||||||
@@ -1135,7 +1167,9 @@ export default {
|
|||||||
* @return {boolean}
|
* @return {boolean}
|
||||||
*/
|
*/
|
||||||
optionExists(option) {
|
optionExists(option) {
|
||||||
return this.optionList.some(_option => this.optionComparator(_option, option))
|
return this.optionList.some((_option) =>
|
||||||
|
this.optionComparator(_option, option)
|
||||||
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1145,7 +1179,7 @@ export default {
|
|||||||
* @return {*}
|
* @return {*}
|
||||||
*/
|
*/
|
||||||
normalizeOptionForSlot(option) {
|
normalizeOptionForSlot(option) {
|
||||||
return (typeof option === 'object') ? option : {[this.label]: option};
|
return typeof option === 'object' ? option : { [this.label]: option }
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1156,7 +1190,7 @@ export default {
|
|||||||
* @return {void}
|
* @return {void}
|
||||||
*/
|
*/
|
||||||
pushTag(option) {
|
pushTag(option) {
|
||||||
this.pushedTags.push(option);
|
this.pushedTags.push(option)
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1181,7 +1215,7 @@ export default {
|
|||||||
if (this.mousedown && !this.searching) {
|
if (this.mousedown && !this.searching) {
|
||||||
this.mousedown = false
|
this.mousedown = false
|
||||||
} else {
|
} else {
|
||||||
const { clearSearchOnSelect, multiple } = this;
|
const { clearSearchOnSelect, multiple } = this
|
||||||
if (this.clearSearchOnBlur({ clearSearchOnSelect, multiple })) {
|
if (this.clearSearchOnBlur({ clearSearchOnSelect, multiple })) {
|
||||||
this.search = ''
|
this.search = ''
|
||||||
}
|
}
|
||||||
@@ -1232,37 +1266,38 @@ export default {
|
|||||||
* @return {Function}
|
* @return {Function}
|
||||||
*/
|
*/
|
||||||
onSearchKeyDown(e) {
|
onSearchKeyDown(e) {
|
||||||
const preventAndSelect = e => {
|
const preventAndSelect = (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault()
|
||||||
return !this.isComposing && this.typeAheadSelect();
|
return !this.isComposing && this.typeAheadSelect()
|
||||||
};
|
}
|
||||||
|
|
||||||
const defaults = {
|
const defaults = {
|
||||||
// backspace
|
// backspace
|
||||||
8: e => this.maybeDeleteValue(),
|
8: (e) => this.maybeDeleteValue(),
|
||||||
// tab
|
// tab
|
||||||
9: e => this.onTab(),
|
9: (e) => this.onTab(),
|
||||||
// esc
|
// esc
|
||||||
27: e => this.onEscape(),
|
27: (e) => this.onEscape(),
|
||||||
// up.prevent
|
// up.prevent
|
||||||
38: e => {
|
38: (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault()
|
||||||
return this.typeAheadUp();
|
return this.typeAheadUp()
|
||||||
},
|
},
|
||||||
// down.prevent
|
// down.prevent
|
||||||
40: e => {
|
40: (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault()
|
||||||
return this.typeAheadDown();
|
return this.typeAheadDown()
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
|
|
||||||
this.selectOnKeyCodes.forEach(keyCode => defaults[keyCode] = preventAndSelect);
|
this.selectOnKeyCodes.forEach(
|
||||||
|
(keyCode) => (defaults[keyCode] = preventAndSelect)
|
||||||
|
)
|
||||||
|
|
||||||
const handlers = this.mapKeydown(defaults, this);
|
const handlers = this.mapKeydown(defaults, this)
|
||||||
|
|
||||||
if (typeof handlers[e.keyCode] === 'function') {
|
if (typeof handlers[e.keyCode] === 'function') {
|
||||||
return handlers[e.keyCode](e);
|
return handlers[e.keyCode](e)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -7,8 +7,10 @@ export default {
|
|||||||
left,
|
left,
|
||||||
width,
|
width,
|
||||||
} = context.$refs.toggle.getBoundingClientRect()
|
} = context.$refs.toggle.getBoundingClientRect()
|
||||||
|
|
||||||
let scrollX = window.scrollX || window.pageXOffset
|
let scrollX = window.scrollX || window.pageXOffset
|
||||||
let scrollY = window.scrollY || window.pageYOffset
|
let scrollY = window.scrollY || window.pageYOffset
|
||||||
|
|
||||||
el.unbindPosition = context.calculatePosition(el, context, {
|
el.unbindPosition = context.calculatePosition(el, context, {
|
||||||
width: width + 'px',
|
width: width + 'px',
|
||||||
left: scrollX + left + 'px',
|
left: scrollX + left + 'px',
|
||||||
|
|||||||
Reference in New Issue
Block a user