mirror of
https://github.com/tenrok/vue-select.git
synced 2026-06-07 07:12:23 +03:00
Merge branch 'master' of https://github.com/sagalbot/vue-select into patch-3
This commit is contained in:
@@ -9,17 +9,15 @@
|
||||
<!--<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet">-->
|
||||
<!-- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha.6/css/bootstrap.min.css"> -->
|
||||
<style>
|
||||
html,
|
||||
body,
|
||||
#app {
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
|
||||
#app {
|
||||
height: 95vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
justify-content: flex-start;
|
||||
flex-wrap: wrap;
|
||||
align-content: center;
|
||||
}
|
||||
|
||||
.v-select {
|
||||
@@ -32,6 +30,7 @@
|
||||
<body>
|
||||
<div id="app">
|
||||
<v-select placeholder="default" :options="options"></v-select>
|
||||
<v-select placeholder="default, RTL" :options="options" dir="rtl"></v-select>
|
||||
<v-select placeholder="multiple" multiple :options="options"></v-select>
|
||||
<v-select placeholder="multiple, taggable" multiple taggable :options="options" no-drop></v-select>
|
||||
<v-select placeholder="multiple, taggable, push-tags" multiple push-tags taggable :options="[{label: 'Foo', value: 'foo'}]"></v-select>
|
||||
@@ -39,6 +38,18 @@
|
||||
<v-select placeholder="multiple, closeOnSelect=false" multiple :close-on-select="false" :options="['cat', 'dog', 'bear']"></v-select>
|
||||
<v-select placeholder="unsearchable" :options="options" :searchable="false"></v-select>
|
||||
<v-select placeholder="search github.." label="full_name" @search="search" :options="ajaxRes"></v-select>
|
||||
<v-select placeholder="custom option template" :options="options" multiple>
|
||||
<template slot="selected-option" scope="option">
|
||||
<img :src='"https://www.kidlink.org/icons/f0-" + option.value.toLowerCase() + ".gif"'/>
|
||||
{{option.label}}
|
||||
</template>
|
||||
<template slot="option" scope="option">
|
||||
<img :src='"https://www.kidlink.org/icons/f0-" + option.value.toLowerCase() + ".gif"'/>
|
||||
{{option.label}} ({{option.value}})
|
||||
</template>
|
||||
</v-select>
|
||||
<v-select disabled placeholder="disabled" value="disabled"></v-select>
|
||||
<v-select disabled multiple placeholder="disabled" :value="['disabled', 'multiple']"></v-select>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
|
||||
Vendored
+2
-2
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
+2
-7
@@ -1,12 +1,13 @@
|
||||
{
|
||||
"name": "vue-select",
|
||||
"version": "2.2.0",
|
||||
"version": "2.3.0",
|
||||
"description": "A native Vue.js component that provides similar functionality to Select2 without the overhead of jQuery.",
|
||||
"author": "Jeff Sagal <sagalbot@gmail.com>",
|
||||
"private": false,
|
||||
"main": "dist/vue-select.js",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"start": "npm run dev",
|
||||
"dev": "node build/dev-server.js",
|
||||
"dev:docs": "node build/dev-server.js --docs",
|
||||
"build": "node build/build.js",
|
||||
@@ -14,12 +15,6 @@
|
||||
"test": "karma start test/unit/karma.conf.js --single-run",
|
||||
"test-watch": "karma start test/unit/karma.conf.js --single-run=false --auto-watch=true"
|
||||
},
|
||||
"browserify": {
|
||||
"transform": [
|
||||
"vueify",
|
||||
"babelify"
|
||||
]
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sagalbot/vue-select.git"
|
||||
|
||||
+68
-20
@@ -3,12 +3,26 @@
|
||||
position: relative;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
.v-select,
|
||||
.v-select * {
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
/* Rtl support */
|
||||
.v-select.rtl .open-indicator {
|
||||
left: 10px;
|
||||
right: auto;
|
||||
}
|
||||
.v-select.rtl .selected-tag {
|
||||
float: right;
|
||||
margin-right: 3px;
|
||||
margin-left: 1px;
|
||||
}
|
||||
.v-select.rtl .dropdown-menu {
|
||||
text-align: right;
|
||||
}
|
||||
/* Open Indicator */
|
||||
.v-select .open-indicator {
|
||||
position: absolute;
|
||||
@@ -20,7 +34,6 @@
|
||||
transition: all 150ms cubic-bezier(1.000, -0.115, 0.975, 0.855);
|
||||
transition-timing-function: cubic-bezier(1.000, -0.115, 0.975, 0.855);
|
||||
opacity: 1;
|
||||
transition: opacity .1s;
|
||||
height: 20px; width: 10px;
|
||||
}
|
||||
.v-select .open-indicator:before {
|
||||
@@ -58,7 +71,6 @@
|
||||
border: 1px solid rgba(60, 60, 60, .26);
|
||||
border-radius: 4px;
|
||||
white-space: normal;
|
||||
transition: border-radius .25s;
|
||||
}
|
||||
.v-select .dropdown-toggle:after {
|
||||
visibility: hidden;
|
||||
@@ -177,10 +189,6 @@
|
||||
float: left;
|
||||
clear: none;
|
||||
}
|
||||
/* Search Input States */
|
||||
.v-select.unsearchable input[type="search"] {
|
||||
max-width: 1px;
|
||||
}
|
||||
/* List Items */
|
||||
.v-select li {
|
||||
line-height: 1.42857143; /* Normalize line height */
|
||||
@@ -233,6 +241,16 @@
|
||||
width: 5em;
|
||||
height: 5em;
|
||||
}
|
||||
|
||||
/* Disabled state */
|
||||
.v-select.disabled .dropdown-toggle,
|
||||
.v-select.disabled .dropdown-toggle input,
|
||||
.v-select.disabled .selected-tag .close,
|
||||
.v-select.disabled .open-indicator {
|
||||
cursor: not-allowed;
|
||||
background-color: rgb(248, 248, 248);
|
||||
}
|
||||
|
||||
/* Loading Spinner States */
|
||||
.v-select.loading .spinner {
|
||||
opacity: 1;
|
||||
@@ -266,12 +284,14 @@
|
||||
</style>
|
||||
|
||||
<template>
|
||||
<div class="dropdown v-select" :class="dropdownClasses">
|
||||
<div ref="toggle" @mousedown.prevent="toggleDropdown" class="dropdown-toggle">
|
||||
<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">
|
||||
{{ getOptionLabel(option) }}
|
||||
<button v-if="multiple" @click="deselect(option)" type="button" class="close" aria-label="Remove option">
|
||||
<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>
|
||||
@@ -283,11 +303,12 @@
|
||||
@keyup.esc="onEscape"
|
||||
@keydown.up.prevent="typeAheadUp"
|
||||
@keydown.down.prevent="typeAheadDown"
|
||||
@keyup.enter.prevent="typeAheadSelect"
|
||||
@keydown.enter.prevent="typeAheadSelect"
|
||||
@blur="onSearchBlur"
|
||||
@focus="onSearchFocus"
|
||||
type="search"
|
||||
class="form-control"
|
||||
:disabled="disabled"
|
||||
:placeholder="searchPlaceholder"
|
||||
:readonly="!searchable"
|
||||
:style="{ width: isValueEmpty ? '100%' : 'auto' }"
|
||||
@@ -306,7 +327,9 @@
|
||||
<ul ref="dropdownMenu" v-if="dropdownOpen" class="dropdown-menu" :style="{ 'max-height': maxHeight }">
|
||||
<li v-for="(option, index) in filteredOptions" v-bind:key="index" :class="{ active: isOptionSelected(option), highlight: index === typeAheadPointer }" @mouseover="typeAheadPointer = index">
|
||||
<a @mousedown.prevent="select(option)">
|
||||
<slot name="option" v-bind="option">
|
||||
{{ getOptionLabel(option) }}
|
||||
</slot>
|
||||
</a>
|
||||
</li>
|
||||
<li v-if="!filteredOptions.length" class="no-options">
|
||||
@@ -341,7 +364,7 @@
|
||||
* If you are using an array of objects, vue-select will look for
|
||||
* a `label` key (ex. [{label: 'This is Foo', value: 'foo'}]). A
|
||||
* custom label key can be set with the `label` prop.
|
||||
* @type {Object}
|
||||
* @type {Array}
|
||||
*/
|
||||
options: {
|
||||
type: Array,
|
||||
@@ -350,6 +373,15 @@
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Disable the entire component.
|
||||
* @type {Boolean}
|
||||
*/
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the max-height property on the dropdown list.
|
||||
* @deprecated
|
||||
@@ -371,7 +403,7 @@
|
||||
|
||||
/**
|
||||
* Equivalent to the `multiple` attribute on a `<select>` input.
|
||||
* @type {Object}
|
||||
* @type {Boolean}
|
||||
*/
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
@@ -380,7 +412,7 @@
|
||||
|
||||
/**
|
||||
* Equivalent to the `placeholder` attribute on an `<input>`.
|
||||
* @type {Object}
|
||||
* @type {String}
|
||||
*/
|
||||
placeholder: {
|
||||
type: String,
|
||||
@@ -429,6 +461,7 @@
|
||||
/**
|
||||
* Callback to generate the label text. If {option}
|
||||
* is an object, returns option[this.label] by default.
|
||||
* @type {Function}
|
||||
* @param {Object || String} option
|
||||
* @return {String}
|
||||
*/
|
||||
@@ -467,7 +500,7 @@
|
||||
* value(s) change. When integrating with Vuex, use this callback to trigger
|
||||
* an action, rather than using :value.sync to retreive the selected value.
|
||||
* @type {Function}
|
||||
* @default {null}
|
||||
* @param {Object || String} val
|
||||
*/
|
||||
onChange: {
|
||||
type: Function,
|
||||
@@ -535,7 +568,18 @@
|
||||
*/
|
||||
inputId: {
|
||||
type: String
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets RTL support. Accepts 'ltr', 'rtl', 'auto'.
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/dir
|
||||
* @type {String}
|
||||
* @default 'auto'
|
||||
*/
|
||||
dir: {
|
||||
type: String,
|
||||
default: 'auto'
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
@@ -689,8 +733,10 @@
|
||||
if (this.open) {
|
||||
this.$refs.search.blur() // dropdown will close on blur
|
||||
} else {
|
||||
this.open = true
|
||||
this.$refs.search.focus()
|
||||
if (!this.disabled) {
|
||||
this.open = true
|
||||
this.$refs.search.focus()
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -814,7 +860,9 @@
|
||||
searching: this.searching,
|
||||
searchable: this.searchable,
|
||||
unsearchable: !this.searchable,
|
||||
loading: this.mutableLoading
|
||||
loading: this.mutableLoading,
|
||||
rtl: this.dir === 'rtl',
|
||||
disabled: this.disabled
|
||||
}
|
||||
},
|
||||
|
||||
@@ -824,7 +872,7 @@
|
||||
*/
|
||||
clearSearchOnBlur() {
|
||||
return this.clearSearchOnSelect && !this.multiple
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the current state of the
|
||||
|
||||
@@ -65,7 +65,7 @@ function searchSubmit(vm, search = false) {
|
||||
vm.$children[0].search = search
|
||||
}
|
||||
|
||||
trigger(vm.$children[0].$refs.search, 'keyup', function (e) {
|
||||
trigger(vm.$children[0].$refs.search, 'keydown', function (e) {
|
||||
e.keyCode = 13
|
||||
})
|
||||
}
|
||||
@@ -315,6 +315,25 @@ describe('Select.vue', () => {
|
||||
})
|
||||
|
||||
describe('Toggling Dropdown', () => {
|
||||
it('should not open the dropdown when the el is clicked but the component is disabled', (done) => {
|
||||
const vm = new Vue({
|
||||
template: '<div><v-select :options="options" :value="value" disabled></v-select></div>',
|
||||
components: {vSelect},
|
||||
data: {
|
||||
value: [{label: 'one'}],
|
||||
options: [{label: 'one'}]
|
||||
}
|
||||
}).$mount()
|
||||
|
||||
vm.$children[0].toggleDropdown({target: vm.$children[0].$refs.search})
|
||||
Vue.nextTick(() => {
|
||||
Vue.nextTick(() => {
|
||||
expect(vm.$children[0].open).toEqual(false)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('should open the dropdown when the el is clicked', (done) => {
|
||||
const vm = new Vue({
|
||||
template: '<div><v-select :options="options" :value="value"></v-select></div>',
|
||||
@@ -674,6 +693,22 @@ describe('Select.vue', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('should not remove tag when close icon is clicked and component is disabled', (done) => {
|
||||
const vm = new Vue({
|
||||
template: '<div><v-select disabled multiple :options="options" v-model="value"></v-select></div>',
|
||||
components: {vSelect},
|
||||
data: {
|
||||
value: ['one'],
|
||||
options: ['one', 'two', 'three']
|
||||
}
|
||||
}).$mount()
|
||||
vm.$children[0].$refs.toggle.querySelector('.close').click()
|
||||
Vue.nextTick(() => {
|
||||
expect(vm.$children[0].mutableValue).toEqual(['one'])
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('should remove the last item in the value array on delete keypress when multiple is true', () => {
|
||||
|
||||
const vm = new Vue({
|
||||
|
||||
Reference in New Issue
Block a user