mirror of
https://github.com/tenrok/vue-select.git
synced 2026-06-16 09:10:33 +03:00
Merge branch 'master' into master
This commit is contained in:
+152
-24
@@ -23,6 +23,10 @@
|
||||
.v-select.rtl .dropdown-menu {
|
||||
text-align: right;
|
||||
}
|
||||
.v-select.rtl .dropdown-toggle .clear {
|
||||
left: 30px;
|
||||
right: auto;
|
||||
}
|
||||
/* Open Indicator */
|
||||
.v-select .open-indicator {
|
||||
position: absolute;
|
||||
@@ -80,6 +84,22 @@
|
||||
clear: both;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
/* Clear Button */
|
||||
.v-select .dropdown-toggle .clear {
|
||||
position: absolute;
|
||||
bottom: 9px;
|
||||
right: 30px;
|
||||
font-size: 23px;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
color: rgba(60, 60, 60, .5);
|
||||
padding: 0;
|
||||
border: 0;
|
||||
background-color: transparent;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Dropdown Toggle States */
|
||||
.v-select.searchable .dropdown-toggle {
|
||||
cursor: text;
|
||||
@@ -186,10 +206,14 @@
|
||||
background: none;
|
||||
position: relative;
|
||||
box-shadow: none;
|
||||
float: left;
|
||||
clear: none;
|
||||
}
|
||||
/* List Items */
|
||||
.v-select.unsearchable input[type="search"] {
|
||||
opacity: 0;
|
||||
}
|
||||
.v-select.unsearchable input[type="search"]:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
/* List Items */
|
||||
.v-select li {
|
||||
line-height: 1.42857143; /* Normalize line height */
|
||||
}
|
||||
@@ -244,6 +268,7 @@
|
||||
|
||||
/* Disabled state */
|
||||
.v-select.disabled .dropdown-toggle,
|
||||
.v-select.disabled .dropdown-toggle .clear,
|
||||
.v-select.disabled .dropdown-toggle input,
|
||||
.v-select.disabled .selected-tag .close,
|
||||
.v-select.disabled .open-indicator {
|
||||
@@ -287,14 +312,17 @@
|
||||
<div :dir="dir" class="dropdown v-select" :class="dropdownClasses">
|
||||
<div ref="toggle" @mousedown.prevent="toggleDropdown" :class="['dropdown-toggle', 'clearfix']">
|
||||
|
||||
<span class="selected-tag" v-for="option in valueAsArray" v-bind:key="option.index">
|
||||
<slot name="selected-option" v-bind="option">
|
||||
{{ getOptionLabel(option) }}
|
||||
</slot>
|
||||
<button v-if="multiple" :disabled="disabled" @click="deselect(option)" type="button" class="close" aria-label="Remove option">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</span>
|
||||
<slot v-for="option in valueAsArray" name="selected-option-container"
|
||||
:option="(typeof option === 'object')?option:{[label]: option}" :deselect="deselect" :multiple="multiple" :disabled="disabled">
|
||||
<span class="selected-tag" v-bind:key="option.index">
|
||||
<slot name="selected-option" v-bind="(typeof option === 'object')?option:{[label]: option}">
|
||||
{{ getOptionLabel(option) }}
|
||||
</slot>
|
||||
<button v-if="multiple" :disabled="disabled" @click="deselect(option)" type="button" class="close" aria-label="Remove option">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</span>
|
||||
</slot>
|
||||
|
||||
<input
|
||||
ref="search"
|
||||
@@ -308,14 +336,27 @@
|
||||
@focus="onSearchFocus"
|
||||
type="search"
|
||||
class="form-control"
|
||||
autocomplete="off"
|
||||
:disabled="disabled"
|
||||
:placeholder="searchPlaceholder"
|
||||
:tabindex="tabindex"
|
||||
:readonly="!searchable"
|
||||
:style="{ width: isValueEmpty ? '100%' : 'auto' }"
|
||||
:id="inputId"
|
||||
aria-label="Search for option"
|
||||
>
|
||||
|
||||
<button
|
||||
v-show="showClearButton"
|
||||
:disabled="disabled"
|
||||
@click="clearSelection"
|
||||
type="button"
|
||||
class="clear"
|
||||
title="Clear selection"
|
||||
>
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
|
||||
<i v-if="!noDrop" ref="openIndicator" role="presentation" class="open-indicator"></i>
|
||||
|
||||
<slot name="spinner">
|
||||
@@ -327,7 +368,7 @@
|
||||
<ul ref="dropdownMenu" v-if="dropdownOpen" class="dropdown-menu" :style="{ 'max-height': maxHeight }" @mousedown="onMousedown">
|
||||
<li v-for="(option, index) in filteredOptions" v-bind:key="index" :class="{ active: isOptionSelected(option), highlight: index === typeAheadPointer }" @mouseover="typeAheadPointer = index">
|
||||
<a @mousedown.prevent.stop="select(option)">
|
||||
<slot name="option" v-bind="option">
|
||||
<slot name="option" v-bind="(typeof option === 'object')?option:{[label]: option}">
|
||||
{{ getOptionLabel(option) }}
|
||||
</slot>
|
||||
</a>
|
||||
@@ -382,6 +423,15 @@
|
||||
default: false
|
||||
},
|
||||
|
||||
/**
|
||||
* Can the user clear the selected property?
|
||||
* @type {Boolean}
|
||||
*/
|
||||
clearable: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the max-height property on the dropdown list.
|
||||
* @deprecated
|
||||
@@ -469,6 +519,13 @@
|
||||
type: Function,
|
||||
default(option) {
|
||||
if (typeof option === 'object') {
|
||||
if (!option.hasOwnProperty(this.label)) {
|
||||
return console.warn(
|
||||
`[vue-select warn]: Label key "option.${this.label}" does not` +
|
||||
` exist in options object ${JSON.stringify(option)}.\n` +
|
||||
'http://sagalbot.github.io/vue-select/#ex-labels'
|
||||
)
|
||||
}
|
||||
if (this.label && option[this.label]) {
|
||||
return option[this.label]
|
||||
}
|
||||
@@ -500,6 +557,15 @@
|
||||
default: false
|
||||
},
|
||||
|
||||
/**
|
||||
* Set the tabindex for the input field.
|
||||
* @type {Number}
|
||||
*/
|
||||
tabindex: {
|
||||
type: Number,
|
||||
default: null
|
||||
},
|
||||
|
||||
/**
|
||||
* When true, newly created tags will be added to
|
||||
* the options list.
|
||||
@@ -510,6 +576,58 @@
|
||||
default: false
|
||||
},
|
||||
|
||||
/**
|
||||
* When true, existing options will be filtered
|
||||
* by the search text. Should not be used in conjunction
|
||||
* with taggable.
|
||||
* @type {Boolean}
|
||||
*/
|
||||
filterable: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
|
||||
/**
|
||||
* Callback to determine if the provided option should
|
||||
* match the current search text. Used to determine
|
||||
* if the option should be displayed.
|
||||
* @type {Function}
|
||||
* @param {Object || String} option
|
||||
* @param {String} label
|
||||
* @param {String} search
|
||||
* @return {Boolean}
|
||||
*/
|
||||
filterBy: {
|
||||
type: Function,
|
||||
default(option, label, search) {
|
||||
return (label || '').toLowerCase().indexOf(search.toLowerCase()) > -1
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Callback to filter results when search text
|
||||
* is provided. Default implementation loops
|
||||
* each option, and returns the result of
|
||||
* this.filterBy.
|
||||
* @type {Function}
|
||||
* @param {Array} list of options
|
||||
* @param {String} search text
|
||||
* @param {Object} vSelect instance
|
||||
* @return {Boolean}
|
||||
*/
|
||||
filter: {
|
||||
"type": Function,
|
||||
default(options, search) {
|
||||
return options.filter((option) => {
|
||||
let label = this.getOptionLabel(option)
|
||||
if (typeof label === 'number') {
|
||||
label = label.toString()
|
||||
}
|
||||
return this.filterBy(option, label, search)
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* User defined function for adding Options
|
||||
* @type {Function}
|
||||
@@ -650,9 +768,7 @@
|
||||
* @return {void}
|
||||
*/
|
||||
select(option) {
|
||||
if (this.isOptionSelected(option)) {
|
||||
this.deselect(option)
|
||||
} else {
|
||||
if (!this.isOptionSelected(option)) {
|
||||
if (this.taggable && !this.optionExists(option)) {
|
||||
option = this.createOption(option)
|
||||
}
|
||||
@@ -689,6 +805,14 @@
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Clears the currently selected value(s)
|
||||
* @return {void}
|
||||
*/
|
||||
clearSelection() {
|
||||
this.mutableValue = this.multiple ? [] : null
|
||||
},
|
||||
|
||||
/**
|
||||
* Called from this.select after each selection.
|
||||
* @param {Object|String} option
|
||||
@@ -909,14 +1033,10 @@
|
||||
* @return {array}
|
||||
*/
|
||||
filteredOptions() {
|
||||
let options = this.mutableOptions.filter((option) => {
|
||||
if (typeof option === 'object' && option.hasOwnProperty(this.label)) {
|
||||
return option[this.label].toLowerCase().indexOf(this.search.toLowerCase()) > -1
|
||||
} else if (typeof option === 'object' && !option.hasOwnProperty(this.label)) {
|
||||
return console.warn(`[vue-select warn]: Label key "option.${this.label}" does not exist in options object.\nhttp://sagalbot.github.io/vue-select/#ex-labels`)
|
||||
}
|
||||
return option.toLowerCase().indexOf(this.search.toLowerCase()) > -1
|
||||
})
|
||||
if (!this.filterable && !this.taggable) {
|
||||
return this.mutableOptions.slice()
|
||||
}
|
||||
let options = this.search.length ? this.filter(this.mutableOptions, this.search, this) : this.mutableOptions;
|
||||
if (this.taggable && this.search.length && !this.optionExists(this.search)) {
|
||||
options.unshift(this.search)
|
||||
}
|
||||
@@ -946,10 +1066,18 @@
|
||||
if (this.multiple) {
|
||||
return this.mutableValue
|
||||
} else if (this.mutableValue) {
|
||||
return [this.mutableValue]
|
||||
return [].concat(this.mutableValue)
|
||||
}
|
||||
|
||||
return []
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines if the clear button should be displayed.
|
||||
* @return {Boolean}
|
||||
*/
|
||||
showClearButton() {
|
||||
return !this.multiple && this.clearable && !this.open && this.mutableValue != null
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user