2
0
mirror of https://github.com/tenrok/vue-select.git synced 2026-06-16 09:10:33 +03:00

Sass & Class Renames (#759)

* - add autoprefixer
- add cssnano
- add postcss-loader
- remove unused packages

* create RTL scss module

* add vs__ prefix to open-indicator, extract to module

* module for dropdown-toggle

* vs__clear module

* vs__dropdown-menu module

* rename `selected-tag` to `vs__selected`

* remove rtl class

* remove dropdown class

* search-input scss module

* move animations to global module

* refactor dropdown list items

* - spinner slot is now scoped with `loading` variable
- move spinner to scss module

* apply vs__search class directly to search input: if you're using the slot, you might not want default styles

* finish global modules

* make RTL a component state

* - update component states to use vs-- prefix
- rename dropdownClasses to stateClasses

* remove unused property

* Closes #760

* fix states

* more state fixes

* rename .close to vs__deselect

* - simplify dev.html
- start on 'sandbox' development

* update build

* - update webpack config
- move Sandbox to VuePress folder

* update external framework version links

* assign grid areas, ensure 100% height outside of docs

* limit specificity

* first pass at assigning variables

* assign 'darkest'

* remove max-height prop

* rename 'component' variables to 'state'

* update badges

* add deprecation notice to docs

* bump travis config

* add coveralls coverage reporter

* bump netlify config

* additional pass pulling up to variables

* start converting to SVG icons

* middle align action icons

* update netlify config

* netlify bump

* fix travis

* fix travis

* try lcov

* netlify attempt

* prune old packages

* bump travis config
This commit is contained in:
Jeff Sagal
2019-02-18 22:01:39 -08:00
committed by GitHub
parent 06800bfb16
commit dc91310860
43 changed files with 1122 additions and 1644 deletions
+5
View File
@@ -0,0 +1,5 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10">
<path d="M6.895455 5l2.842897-2.842898c.348864-.348863.348864-.914488 0-1.263636L9.106534.261648c-.348864-.348864-.914489-.348864-1.263636 0L5 3.104545 2.157102.261648c-.348863-.348864-.914488-.348864-1.263636 0L.261648.893466c-.348864.348864-.348864.914489 0 1.263636L3.104545 5 .261648 7.842898c-.348864.348863-.348864.914488 0 1.263636l.631818.631818c.348864.348864.914773.348864 1.263636 0L5 6.895455l2.842898 2.842897c.348863.348864.914772.348864 1.263636 0l.631818-.631818c.348864-.348864.348864-.914489 0-1.263636L6.895455 5z"/>
</svg>
</template>
+5
View File
@@ -0,0 +1,5 @@
<template>
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="10">
<path d="M9.211364 7.59931l4.48338-4.867229c.407008-.441854.407008-1.158247 0-1.60046l-.73712-.80023c-.407008-.441854-1.066904-.441854-1.474243 0L7 5.198617 2.51662.33139c-.407008-.441853-1.066904-.441853-1.474243 0l-.737121.80023c-.407008.441854-.407008 1.158248 0 1.600461l4.48338 4.867228L7 10l2.211364-2.40069z"/>
</svg>
</template>
+52 -351
View File
@@ -1,363 +1,69 @@
<style>
.v-select {
position: relative;
font-family: inherit;
}
.v-select,
.v-select * {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
/* Rtl support - Because we're using a flexbox-based layout, the `dir="rtl"` HTML
attribute does most of the work for us by rearranging the child elements visually.
*/
.v-select[dir="rtl"] .vs__actions {
padding: 0 3px 0 6px;
}
.v-select[dir="rtl"] .dropdown-toggle .clear {
margin-left: 6px;
margin-right: 0;
}
.v-select[dir="rtl"] .selected-tag .close {
margin-left: 0;
margin-right: 2px;
}
.v-select[dir="rtl"] .dropdown-menu {
text-align: right;
}
/* Open Indicator */
.v-select .open-indicator {
display: flex;
align-items: center;
cursor: pointer;
pointer-events: all;
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;
width: 12px; /* To account for extra width from rotating. */
}
.v-select .open-indicator:before {
border-color: rgba(60, 60, 60, .5);
border-style: solid;
border-width: 3px 3px 0 0;
content: '';
display: inline-block;
height: 10px;
width: 10px;
vertical-align: text-top;
transform: rotate(133deg);
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);
box-sizing: inherit;
}
/* Open Indicator States */
.v-select.open .open-indicator:before {
transform: rotate(315deg);
}
.v-select.loading .open-indicator {
opacity: 0;
}
/* Dropdown Toggle */
.v-select .dropdown-toggle {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
display: flex;
padding: 0 0 4px 0;
background: none;
border: 1px solid rgba(60, 60, 60, .26);
border-radius: 4px;
white-space: normal;
}
.v-select .vs__selected-options {
display: flex;
flex-basis: 100%;
flex-grow: 1;
flex-wrap: wrap;
padding: 0 2px;
position: relative;
}
.v-select .vs__actions {
display: flex;
align-items: stretch;
padding: 0 6px 0 3px;
}
/* Clear Button */
.v-select .dropdown-toggle .clear {
font-size: 23px;
font-weight: 700;
line-height: 1;
color: rgba(60, 60, 60, 0.5);
padding: 0;
border: 0;
background-color: transparent;
cursor: pointer;
margin-right: 6px;
}
/* Dropdown Toggle States */
.v-select.searchable .dropdown-toggle {
cursor: text;
}
.v-select.unsearchable .dropdown-toggle {
cursor: pointer;
}
.v-select.open .dropdown-toggle {
border-bottom-color: transparent;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
/* Dropdown Menu */
.v-select .dropdown-menu {
display:block;
position: absolute;
top: 100%;
left: 0;
z-index: 1000;
min-width: 160px;
padding: 5px 0;
margin: 0;
width: 100%;
overflow-y: auto;
border: 1px solid rgba(0, 0, 0, .26);
box-shadow: 0px 3px 6px 0px rgba(0,0,0,.15);
border-top: none;
border-radius: 0 0 4px 4px;
text-align: left;
list-style: none;
background: #fff;
}
.v-select .no-options {
text-align: center;
}
/* Selected Tags */
.v-select .selected-tag {
display: flex;
align-items: center;
background-color: #f0f0f0;
border: 1px solid #ccc;
border-radius: 4px;
color: #333;
line-height: 1.42857143; /* Normalize line height */
margin: 4px 2px 0px 2px;
padding: 0 0.25em;
transition: opacity .25s;
}
.v-select.single .selected-tag {
background-color: transparent;
border-color: transparent;
}
.v-select.single.open .selected-tag {
position: absolute;
opacity: .4;
}
.v-select.single.searching .selected-tag {
display: none;
}
.v-select .selected-tag .close {
margin-left: 2px;
font-size: 1.25em;
appearance: none;
padding: 0;
cursor: pointer;
background: 0 0;
border: 0;
font-weight: 700;
line-height: 1;
color: #000;
text-shadow: 0 1px 0 #fff;
filter: alpha(opacity=20);
opacity: .2;
}
.v-select.single.searching:not(.open):not(.loading) input[type="search"] {
opacity: .2;
}
/* Search Input */
.v-select input[type="search"]::-webkit-search-decoration,
.v-select input[type="search"]::-webkit-search-cancel-button,
.v-select input[type="search"]::-webkit-search-results-button,
.v-select input[type="search"]::-webkit-search-results-decoration {
display: none;
}
.v-select input[type="search"]::-ms-clear {
display: none;
}
.v-select input[type="search"],
.v-select input[type="search"]:focus {
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
line-height: 1.42857143;
font-size: 1em;
display: inline-block;
border: 1px solid transparent;
border-left: none;
outline: none;
margin: 4px 0 0 0;
padding: 0 7px;
max-width: 100%;
background: none;
box-shadow: none;
flex-grow: 1;
width: 0;
}
.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 */
}
.v-select li > a {
display: block;
padding: 3px 20px;
clear: both;
color: #333; /* Overrides most CSS frameworks */
white-space: nowrap;
}
.v-select li:hover {
cursor: pointer;
}
.v-select .dropdown-menu .active > a {
color: #333;
background: rgba(50, 50, 50, .1);
}
.v-select .dropdown-menu > .highlight > a {
/*
* required to override bootstrap 3's
* .dropdown-menu > li > a:hover {} styles
*/
background: #5897fb;
color: #fff;
}
.v-select .highlight:not(:last-child) {
margin-bottom: 0; /* Fixes Bulma Margin */
}
/* Loading Spinner */
.v-select .spinner {
align-self: center;
opacity: 0;
font-size: 5px;
text-indent: -9999em;
overflow: hidden;
border-top: .9em solid rgba(100, 100, 100, .1);
border-right: .9em solid rgba(100, 100, 100, .1);
border-bottom: .9em solid rgba(100, 100, 100, .1);
border-left: .9em solid rgba(60, 60, 60, .45);
transform: translateZ(0);
animation: vSelectSpinner 1.1s infinite linear;
transition: opacity .1s;
}
.v-select .spinner,
.v-select .spinner:after {
border-radius: 50%;
width: 5em;
height: 5em;
}
/* 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 {
cursor: not-allowed;
background-color: rgb(248, 248, 248);
}
/* Loading Spinner States */
.v-select.loading .spinner {
opacity: 1;
}
/* KeyFrames */
@-webkit-keyframes vSelectSpinner {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
@keyframes vSelectSpinner {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
/* Dropdown Default Transition */
.fade-enter-active,
.fade-leave-active {
transition: opacity .15s cubic-bezier(1.0, 0.5, 0.8, 1.0);
}
.fade-enter,
.fade-leave-to {
opacity: 0;
}
<style lang="scss">
@import '../scss/vue-select.scss';
</style>
<template>
<div :dir="dir" class="dropdown v-select" :class="dropdownClasses">
<div ref="toggle" @mousedown.prevent="toggleDropdown" class="dropdown-toggle">
<div :dir="dir" class="v-select" :class="stateClasses">
<div ref="toggle" @mousedown.prevent="toggleDropdown" class="vs__dropdown-toggle">
<div class="vs__selected-options" ref="selectedOptions">
<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 v-for="option in valueAsArray"
name="selected-option-container"
:option="(typeof option === 'object')?option:{[label]: option}"
:deselect="deselect"
:multiple="multiple"
:disabled="disabled">
<span class="vs__selected" 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">&times;</span>
<button v-if="multiple" :disabled="disabled" @click="deselect(option)" type="button" class="vs__deselect" aria-label="Deselect option">
<deselect />
</button>
</span>
</slot>
<slot name="search" v-bind="scope.search">
<input v-bind="scope.search.attributes" v-on="scope.search.events">
<input class="vs__search" v-bind="scope.search.attributes" v-on="scope.search.events">
</slot>
</div>
<div class="vs__actions">
<button
v-show="showClearButton"
:disabled="disabled"
@click="clearSelection"
type="button"
class="clear"
class="vs__clear"
title="Clear selection"
>
<span aria-hidden="true">&times;</span>
<deselect />
</button>
<i v-if="!noDrop" ref="openIndicator" role="presentation" class="open-indicator"></i>
<open-indicator v-if="!noDrop" ref="openIndicator" role="presentation" class="vs__open-indicator" />
<slot name="spinner">
<div class="spinner" v-show="mutableLoading">Loading...</div>
<slot name="spinner" v-bind="scope.spinner">
<div class="vs__spinner" v-show="mutableLoading">Loading...</div>
</slot>
</div>
</div>
<transition :name="transition">
<ul ref="dropdownMenu" v-if="dropdownOpen" class="dropdown-menu" :style="{ 'max-height': maxHeight }" role="listbox" @mousedown="onMousedown">
<li role="option" 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)">
<ul ref="dropdownMenu" v-if="dropdownOpen" class="vs__dropdown-menu" role="listbox" @mousedown="onMousedown">
<li
role="option"
v-for="(option, index) in filteredOptions"
:key="index"
class="vs__dropdown-option"
:class="{ active: isOptionSelected(option), 'vs__dropdown-option--highlight': index === typeAheadPointer }"
@mouseover="typeAheadPointer = index"
@mousedown.prevent.stop="select(option)"
>
<slot name="option" v-bind="(typeof option === 'object')?option:{[label]: option}">
{{ getOptionLabel(option) }}
</slot>
</a>
</li>
<li v-if="!filteredOptions.length" class="no-options" @mousedown.stop="">
<li v-if="!filteredOptions.length" class="vs__no-options" @mousedown.stop="">
<slot name="no-options">Sorry, no matching options.</slot>
</li>
</ul>
@@ -369,8 +75,12 @@
import pointerScroll from '../mixins/pointerScroll'
import typeAheadPointer from '../mixins/typeAheadPointer'
import ajax from '../mixins/ajax'
import Deselect from './Deselect'
import OpenIndicator from './OpenIndicator'
export default {
components: {Deselect, OpenIndicator},
mixins: [pointerScroll, typeAheadPointer, ajax],
props: {
@@ -416,16 +126,6 @@
default: true
},
/**
* Sets the max-height property on the dropdown list.
* @deprecated
* @type {String}
*/
maxHeight: {
type: String,
default: '400px'
},
/**
* Enable/disable filtering the options.
* @type {Boolean}
@@ -454,13 +154,12 @@
},
/**
* Sets a Vue transition property on the `.dropdown-menu`. vue-select
* does not include CSS for transitions, you'll need to add them yourself.
* Sets a Vue transition property on the `.vs__dropdown-menu`.
* @type {String}
*/
transition: {
type: String,
default: 'fade'
default: 'vs__fade'
},
/**
@@ -902,7 +601,7 @@
*/
toggleDropdown(e) {
if (e.target === this.$refs.openIndicator || e.target === this.searchEl || e.target === this.$refs.toggle ||
e.target.classList.contains('selected-tag') || e.target === this.$el) {
e.target.classList.contains('vs__selected') || e.target === this.$el) {
if (this.open) {
this.searchEl.blur() // dropdown will close on blur
} else {
@@ -1147,7 +846,7 @@
'role': 'combobox',
'type': 'search',
'autocomplete': 'off',
'class': 'form-control',
'value': this.search,
},
events: {
'keydown': this.onSearchKeyDown,
@@ -1157,23 +856,25 @@
'input': (e) => this.search = e.target.value,
},
},
spinner: {
loading: this.mutableLoading
}
};
},
/**
* Classes to be output on .dropdown
* Holds the current state of the component.
* @return {Object}
*/
dropdownClasses() {
stateClasses() {
return {
open: this.dropdownOpen,
single: !this.multiple,
searching: this.searching,
searchable: this.searchable,
unsearchable: !this.searchable,
loading: this.mutableLoading,
rtl: this.dir === 'rtl', // This can be removed - styling is handled by `dir="rtl"` attribute
disabled: this.disabled
'vs--open': this.dropdownOpen,
'vs--single': !this.multiple,
'vs--searching': this.searching,
'vs--searchable': this.searchable,
'vs--unsearchable': !this.searchable,
'vs--loading': this.mutableLoading,
'vs--disabled': this.disabled
}
},
@@ -1191,7 +892,7 @@
* @return {Boolean} True if non empty value
*/
searching() {
return !!this.search
return !! this.search
},
/**