├── .gitignore ├── README.md ├── dist ├── fire-select.css └── fire-select.js ├── example ├── index.html ├── script.js └── style.css ├── gulpfile.js ├── package.json └── src ├── fire-select.html ├── fire-select.js └── fire-select.scss /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🔥_Fireselect_ 2 | 3 | Vue component that transforms overwhelming `select` boxes into something fancy, simple and user-friendly. 4 | 5 | It is similar to Selectize, Chosen, Select2, etc. However it was built using Vue.js only ;) 6 | 7 | ## Options 8 | *name* | *type* | *default* 9 | 10 | - **options** | *Array* | [] 11 | An array of the initial available options. 12 | 13 | - **multiple** | *Boolean* | false 14 | Equivalent to the `select multiple` attribute. 15 | 16 | - **create** | *Boolean* | false 17 | Allows the creation of new items that aren't in the list of options. 18 | 19 | - **helper-message** | *String* | 'Type anything to search' 20 | Placeholder attribute of search input. 21 | 22 | - **placeholder** | *String* | 'Select an item' 23 | Placeholder attribute of fireselect. 24 | 25 | - **add-label** | *String* | 'Add:' 26 | Text to add new option. 27 | 28 | - **no-results-label** | *String* | 'No results found for:' 29 | Text to appear when no option is found. 30 | 31 | - **animation** | *Boolean* | true 32 | Show animation when item is selected 33 | 34 | - **name** | *String* | fire-select[] 35 | Name attribute of input 36 | 37 | - **id** | *String* | fire-select 38 | Id attribute of input 39 | 40 | ## Usage 41 | ```html 42 | 43 | 44 | .. 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | ``` 53 | 54 | ### Options 55 | ```javascript 56 | var obj = [ 57 | {value: 'html', label: 'HyperText Markup Language', selected: true}, 58 | {value: 'css', label: 'Cascading Style Sheets'}, 59 | {value: 'js', label: 'Javascript'}, 60 | ]; 61 | 62 | var arr = ['HyperText Markup Language', 'Cascading Style Sheets', 'Javascript']; 63 | ``` 64 | 65 | ## Events 66 | [Vue.js - Dispatch](http://vuejs.org/api/#vm-dispatch) 67 | 68 | - **fsOptionAdded** 69 | When a new item is added. 70 | 71 | - **fsOptionSelected** 72 | When a item is selected. 73 | 74 | - **fsOptionDeselect** 75 | When a item is deselected. 76 | 77 | ```js 78 | new Vue({ 79 | ... 80 | events: { 81 | fsOptionAdded: function(option) { 82 | // do something 83 | } 84 | } 85 | } 86 | ``` 87 | -------------------------------------------------------------------------------- /dist/fire-select.css: -------------------------------------------------------------------------------- 1 | .fire-select-box,.fire-selected-item{position:relative;box-sizing:border-box}.fire-select-box{width:100%;border:1px solid #ccc;border-radius:3px;margin-bottom:20px}.fire-select-box:after,.fire-select-box:before{content:" ";display:table}.fire-select-box:after{clear:both}.fire-select-box.multiple .fire-selected-item:not(.empty){display:inline-block;font-size:14px;padding:2px 0 2px 5px;margin:3px 0 3px 3px;border:1px solid #ccc}.fire-select-box.multiple .fire-selected-item:not(.empty)::after{display:none}.fire-select-box.multiple .fire-selected-item:not(.empty)>b{float:none;margin:0;padding:0 5px;border-right:none}.fire-select-list,.fire-selected-list{padding:0;margin:0;list-style:none}.fire-selected-list{width:100%;float:left;cursor:pointer}.fire-selected-item{border-radius:3px;padding:5px 10px;color:#333;background-image:-webkit-linear-gradient(#fff,#ddd);background-image:linear-gradient(#fff,#ddd);display:block;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;font-size:16px;line-height:1em}.fire-selected-item::after{content:'';display:block;width:0;height:0;border-left:4px solid transparent;border-right:4px solid transparent;border-top:4px solid #333;position:absolute;right:10px;top:50%;margin-top:-2px}.fire-selected-item>b{float:right;margin-right:20px;border-left:1px solid #ccc;border-right:1px solid #ccc;padding:0 10px}.fire-select-list{position:absolute;top:100%;left:0;border:1px solid #ccc;width:100%;box-sizing:border-box;border-radius:3px;z-index:1;background:#fff;overflow-y:auto;max-height:200px}.fire-select-item{padding:10px;color:#333;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;font-size:14px;border-top:1px solid #eee}.fire-select-item.hover,.fire-select-item:hover{background:#eee}.fire-select-item-input{padding:10px}.fire-select-input{border:none;font-size:14px;line-height:1em;outline:0;color:#333;width:100%}.fs-hidden{display:none!important}.animated{-webkit-animation-duration:1s;animation-duration:1s;-webkit-animation-fill-mode:both;animation-fill-mode:both}@-webkit-keyframes bounceIn{20%,40%,60%,80%,from,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}20%{-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}40%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}60%{opacity:1;-webkit-transform:scale3d(1.03,1.03,1.03);transform:scale3d(1.03,1.03,1.03)}80%{-webkit-transform:scale3d(.97,.97,.97);transform:scale3d(.97,.97,.97)}to{opacity:1;-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}@keyframes bounceIn{20%,40%,60%,80%,from,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{opacity:0;-webkit-transform:scale3d(.3,.3,.3);transform:scale3d(.3,.3,.3)}20%{-webkit-transform:scale3d(1.1,1.1,1.1);transform:scale3d(1.1,1.1,1.1)}40%{-webkit-transform:scale3d(.9,.9,.9);transform:scale3d(.9,.9,.9)}60%{opacity:1;-webkit-transform:scale3d(1.03,1.03,1.03);transform:scale3d(1.03,1.03,1.03)}80%{-webkit-transform:scale3d(.97,.97,.97);transform:scale3d(.97,.97,.97)}to{opacity:1;-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}}.fs-bounceIn{-webkit-animation-name:bounceIn;animation-name:bounceIn} -------------------------------------------------------------------------------- /dist/fire-select.js: -------------------------------------------------------------------------------- 1 | !function e(t,n,i){function s(o,u){if(!n[o]){if(!t[o]){var c="function"==typeof require&&require;if(!u&&c)return c(o,!0);if(l)return l(o,!0);var p=new Error("Cannot find module '"+o+"'");throw p.code="MODULE_NOT_FOUND",p}var r=n[o]={exports:{}};t[o][0].call(r.exports,function(e){var n=t[o][1][e];return s(n?n:e)},r,r.exports,e,t,n,i)}return n[o].exports}for(var l="function"==typeof require&&require,o=0;o\n \n\n \n\n \n\n'},{}],2:[function(e,t,n){"use strict";var i="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol?"symbol":typeof e};Vue.component("fire-select",{template:e("./fire-select.html"),props:{options:{type:Array,"default":[]},multiple:{type:Boolean,"default":!1},create:{type:Boolean,"default":!0},name:{type:String,"default":"fire-select[]"},id:{type:String,"default":"fire-select"},helperMessage:{type:String,"default":"Type anything to search"},placeholder:{type:String,"default":function(){return this.multiple?"Select some items":"Select an item"}},addLabel:{type:String,"default":"Add:"},noResultsLabel:{type:String,"default":"No results found for:"},animation:{type:Boolean,"default":!0}},data:function(){return{options_:[],input:"",index:null,isOpen:!1,isPopulating:!1,skipClose:!1}},transitions:{bounce:{enterClass:"fs-bounceIn",leaveClass:"fs-hidden"}},computed:{tips:function(){return this.options_.filter(function(e){return e.tip===!0&&e.selected===!1})},selected:function(){return this.options_.filter(function(e){return e.selected===!0})}},watch:{input:function(e){this.index=null,this.options_.forEach(function(t){var n=t.label.toLowerCase(),i=e.toLowerCase();t.tip=e.length?-1!=n.indexOf(i):!0})},options:{handler:function(){this.populate()},deep:!0},multiple:function(e){e===!1&&this.selected.length&&this.selected.forEach(function(e,t){t>0&&(e.selected=!1)})}},filters:{highlight:function(e){return this.input.length?e.replace(new RegExp("("+this.input+")","gi"),"$1"):e}},methods:{populate:function(){this.options_=[],this.index=null,this.isPopulating=!0,this.options.forEach(function(e,t){"string"==typeof e?this.addOption(t,e,!1,!0):this.addOption(e.value,e.label,e.selected,!0)}.bind(this)),this.isPopulating=!1},addOption:function(e,t,n,i){var s={value:e,label:t,selected:!1,tip:!!i};0===this.options_.filter(function(n){return n.value==e&&n.label==t}).length&&(this.options_.$set(this.options_.length,s),this.isPopulating||this.$dispatch("fsOptionAdded",Vue.util.extend({},s)),n&&this.select(s))},newOption:function(){if(this.create){var e=this.input.trim();e&&(this.singleDeselect(),this.addOption(e,e,!0,!0,!0))}},select:function(e){"object"!=("undefined"==typeof e?"undefined":i(e))&&(e=this.tips[this.index],this.index=null),this.singleDeselect(),e.selected=!0,this.isPopulating||this.$dispatch("fsOptionSelected",Vue.util.extend({},e)),this.multiple?(this.skipClose=!0,this.isOpen&&this.$els.input.focus()):this.isOpen&&this.close()},deselect:function(e){e.selected=!1,this.isPopulating||this.$dispatch("fsOptionDeselect",Vue.util.extend({},e))},singleDeselect:function(){!this.multiple&&this.selected.length&&this.deselect(this.selected[0]),this.input=""},up:function(){null!==this.index&&this.index>(this.input?-1:0)?this.index--:this.index=this.tips.length-1},down:function(){null!==this.index&&this.index 2 | 3 | 4 | 5 | 🔥 Fireselect 6 | 7 | 8 | 9 | 10 | 11 | 12 |

🔥Fireselect

13 | 14 |
15 |

Fireselect

16 | 26 | 27 |
28 | 29 |
30 |

Props

31 | 32 |
33 | 38 | 39 | 44 |
45 | 46 | 50 | 51 | 55 | 56 | 60 | 61 | 65 | 66 | 70 | 71 | 75 | 76 | 80 |
81 |
82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /example/script.js: -------------------------------------------------------------------------------- 1 | var obj = [ 2 | {value: 'html', label: 'HyperText Markup Language'}, 3 | {value: 'css', label: 'Cascading Style Sheets'}, 4 | {value: 'js', label: 'Javascript'}, 5 | // {value: 'php', label: 'Hypertext Preprocessor'}, 6 | ]; 7 | 8 | // var languages = ['HyperText Markup Language', 'Cascading Style Sheets', 'Javascript', 'Hypertext Preprocessor']; 9 | var arr = ['HyperText Markup Language', 'Cascading Style Sheets', 'Javascript']; 10 | 11 | var vm = new Vue({ 12 | el: 'body', 13 | 14 | data: { 15 | languagesObj: obj, 16 | languages: arr, 17 | options: 'object', 18 | multiple: false, 19 | create: true, 20 | animation: true, 21 | helperMessage: 'Type anything to search', 22 | placeholder: 'Select an item', 23 | addLabel: 'Add:', 24 | noResultsLabel: 'No results found for:', 25 | }, 26 | 27 | events: { 28 | fsOptionAdded: function(option) { 29 | console.log('fire-select option added:', option); 30 | }, 31 | 32 | fsOptionSelected: function(option) { 33 | console.log('fire-select option selected:', option); 34 | }, 35 | 36 | fsOptionDeselect: function(option) { 37 | console.log('fire-select option deselected:', option); 38 | }, 39 | } 40 | }); 41 | -------------------------------------------------------------------------------- /example/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: 'Open Sans', sans-serif; 3 | color: #666; 4 | } 5 | 6 | .title { 7 | text-align: center; 8 | font-size: 42px; 9 | font-style: italic; 10 | } 11 | 12 | .fire { 13 | color: #ff3200; 14 | } 15 | 16 | .fire span { 17 | font-style: normal; 18 | } 19 | 20 | #content { 21 | width: 400px; 22 | margin: 50px auto; 23 | } 24 | 25 | hr { 26 | margin: 0; 27 | padding: 0; 28 | height: 1px; 29 | background: #ccc; 30 | border: none; 31 | } 32 | 33 | #props label { 34 | display: block; 35 | margin-bottom: 15px; 36 | font-size: 14px; 37 | box-sizing: border-box; 38 | line-height: 1em; 39 | position: relative; 40 | } 41 | 42 | #props label:hover pre { 43 | display: block; 44 | } 45 | 46 | #props label pre { 47 | border: 1px solid #ccc; 48 | background: #eee; 49 | padding: 10px; 50 | position: absolute; 51 | top: 100%; 52 | left: 0; 53 | display: none; 54 | z-index: 1; 55 | border-radius: 5px; 56 | font-size: 11px; 57 | line-height: 1.5em; 58 | } 59 | 60 | #props input { 61 | margin: 0; 62 | padding: 0; 63 | } 64 | 65 | #props input[type=text] { 66 | padding: 10px; 67 | border: 1px solid #ccc; 68 | font-size: 14px; 69 | line-height: 1em; 70 | outline: none; 71 | color: #333; 72 | width: 100%; 73 | box-sizing: border-box; 74 | border-radius: 3px; 75 | margin-top: 5px; 76 | } 77 | 78 | .radio { 79 | display: flex; 80 | flex-flow: row; 81 | } 82 | 83 | .radio label { 84 | width: 50%; 85 | } 86 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var elixir = require('laravel-elixir'); 2 | require('laravel-elixir-livereload'); 3 | 4 | elixir.config.sourcemaps = false; 5 | 6 | elixir(function(mix) { 7 | mix 8 | .sass('./src/fire-select.scss', './dist/fire-select.css') 9 | .browserify('./src/fire-select.js', './dist/fire-select.js') 10 | 11 | .livereload([ 12 | './dist/fire-select.css', 13 | './dist/fire-select.js', 14 | './example/index.html', 15 | './example/script.js', 16 | ]); 17 | }); 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fire-select", 3 | "version": "0.0.3", 4 | "description": "Fire Select", 5 | "author": "Firework - Web Solutions", 6 | "license": "MIT", 7 | "devDependencies": { 8 | "laravel-elixir": "^6.0.0-0", 9 | "laravel-elixir-livereload": "^1.1.4" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/fire-select.html: -------------------------------------------------------------------------------- 1 |
8 |
    9 |
  • {{ placeholder }}
  • 10 |
  • 18 | {{ option.label }} 19 | × 20 |
  • 21 |
22 | 23 |
    24 |
  • 25 | 37 |
  • 38 | 39 |
  • 46 | {{ addLabel }} {{ input }} 47 |
  • 48 | 49 |
  • 50 | {{ noResultsLabel }} {{ input }} 51 |
  • 52 | 53 |
  • 62 | {{{ option.label | highlight }}} 63 |
  • 64 |
65 | 66 | 69 |
70 | -------------------------------------------------------------------------------- /src/fire-select.js: -------------------------------------------------------------------------------- 1 | Vue.component('fire-select', { 2 | template: require('./fire-select.html'), 3 | 4 | props: { 5 | options: { 6 | type: Array, 7 | default: [], 8 | }, 9 | 10 | multiple: { 11 | type: Boolean, 12 | default: false 13 | }, 14 | 15 | create: { 16 | type: Boolean, 17 | default: true 18 | }, 19 | 20 | name: { 21 | type: String, 22 | default: 'fire-select[]' 23 | }, 24 | 25 | id: { 26 | type: String, 27 | default: 'fire-select' 28 | }, 29 | 30 | helperMessage: { 31 | type: String, 32 | default: 'Type anything to search' 33 | }, 34 | 35 | placeholder: { 36 | type: String, 37 | default: function () { 38 | return this.multiple ? 'Select some items' : 'Select an item'; 39 | } 40 | }, 41 | 42 | addLabel: { 43 | type: String, 44 | default: 'Add:' 45 | }, 46 | 47 | noResultsLabel: { 48 | type: String, 49 | default: 'No results found for:' 50 | }, 51 | 52 | animation: { 53 | type: Boolean, 54 | default: true 55 | } 56 | }, 57 | 58 | data: function() { 59 | return { 60 | options_: [], 61 | input: '', 62 | index: null, 63 | isOpen: false, 64 | isPopulating: false, 65 | skipClose: false, 66 | }; 67 | }, 68 | 69 | transitions: { 70 | 'bounce': { 71 | enterClass: 'fs-bounceIn', 72 | leaveClass: 'fs-hidden' 73 | }, 74 | }, 75 | 76 | computed: { 77 | tips: function() { 78 | return this.options_.filter(function(option) { return option.tip === true && option.selected === false; }); 79 | }, 80 | 81 | selected: function() { 82 | return this.options_.filter(function(option) { return option.selected === true; }); 83 | }, 84 | }, 85 | 86 | watch: { 87 | 'input': function (val) { 88 | this.index = null; 89 | 90 | this.options_.forEach(function(option) { 91 | var label = option.label.toLowerCase(), 92 | value = val.toLowerCase(); 93 | 94 | option.tip = val.length ? label.indexOf(value) != -1 : true; 95 | }); 96 | }, 97 | 98 | 'options': { 99 | handler: function() { 100 | this.populate(); 101 | }, 102 | deep: true 103 | }, 104 | 105 | multiple: function(val) { 106 | if (val === false && this.selected.length) { 107 | this.selected.forEach(function(option, index){ 108 | if (index > 0) option.selected = false; 109 | }); 110 | } 111 | }, 112 | }, 113 | 114 | filters: { 115 | highlight: function(value) { 116 | return this.input.length ? 117 | value.replace(new RegExp('('+this.input+')', 'gi'), '$1') 118 | : value; 119 | } 120 | }, 121 | 122 | methods: { 123 | populate: function() { 124 | this.options_ = []; 125 | this.index = null; 126 | this.isPopulating = true; 127 | 128 | this.options.forEach(function(option, index) { 129 | if (typeof option == 'string') { 130 | this.addOption(index, option, false, true); 131 | } else { 132 | this.addOption(option.value, option.label, option.selected, true); 133 | } 134 | }.bind(this)); 135 | 136 | this.isPopulating = false; 137 | }, 138 | 139 | addOption: function(value, label, selected, tip) { 140 | var option = { 141 | value: value, 142 | label: label, 143 | selected: false, 144 | tip: !! tip, 145 | }; 146 | 147 | if (this.options_.filter(function(item_) { 148 | return item_.value == value && item_.label == label; 149 | }).length === 0) { 150 | this.options_.$set(this.options_.length, option); 151 | if (! this.isPopulating) this.$dispatch('fsOptionAdded', Vue.util.extend({}, option)); 152 | if (!! selected) this.select(option); 153 | } 154 | }, 155 | 156 | newOption: function() { 157 | if (! this.create) return; 158 | 159 | var text = this.input.trim(); 160 | 161 | if (! text) return; 162 | 163 | this.singleDeselect(); 164 | this.addOption(text, text, true, true, true); 165 | }, 166 | 167 | select: function(option) { 168 | // get a option by this.index 169 | if (typeof option != 'object') { 170 | option = this.tips[this.index]; 171 | this.index = null; 172 | } 173 | 174 | this.singleDeselect(); 175 | 176 | option.selected = true; 177 | if (! this.isPopulating) this.$dispatch('fsOptionSelected', Vue.util.extend({}, option)); 178 | 179 | if (this.multiple) { 180 | this.skipClose = true; 181 | if (this.isOpen) this.$els.input.focus(); 182 | } else { 183 | if (this.isOpen) this.close(); 184 | } 185 | }, 186 | 187 | deselect: function(option) { 188 | option.selected = false; 189 | if (! this.isPopulating) this.$dispatch('fsOptionDeselect', Vue.util.extend({}, option)); 190 | }, 191 | 192 | singleDeselect: function() { 193 | if (! this.multiple && this.selected.length) this.deselect(this.selected[0]); 194 | this.input = ''; 195 | }, 196 | 197 | up: function() { 198 | if (this.index !== null && this.index > (this.input ? -1 : 0)) { 199 | this.index--; 200 | } else { 201 | this.index = this.tips.length - 1; 202 | } 203 | }, 204 | 205 | down: function() { 206 | if (this.index !== null && this.index < (this.tips.length - 1)) { 207 | this.index++; 208 | } else { 209 | this.index = this.input ? -1 : 0; 210 | } 211 | }, 212 | 213 | open: function() { 214 | this.isOpen = true; 215 | 216 | this.$nextTick(function () { 217 | this.$els.input.focus(); 218 | }.bind(this)); 219 | }, 220 | 221 | close: function() { 222 | if (this.skipClose === true) { 223 | this.skipClose = false; 224 | return; 225 | } 226 | 227 | this.isOpen = false; 228 | }, 229 | }, 230 | 231 | created: function() { 232 | this.populate(); 233 | } 234 | }); 235 | -------------------------------------------------------------------------------- /src/fire-select.scss: -------------------------------------------------------------------------------- 1 | // ==================================================== 2 | // 🔥Fireselect 3 | // ==================================================== 4 | 5 | .fire-select-box { 6 | width: 100%; 7 | border: 1px solid #ccc; 8 | border-radius: 3px; 9 | position: relative; 10 | box-sizing: border-box; 11 | margin-bottom: 20px; 12 | 13 | &:before, 14 | &:after { 15 | content: " "; 16 | display: table; 17 | } 18 | 19 | &:after { 20 | clear: both; 21 | } 22 | 23 | &.multiple { 24 | .fire-selected-item:not(.empty) { 25 | display: inline-block; 26 | font-size: 14px; 27 | padding: 2px 0 2px 5px; 28 | margin: 3px 0 3px 3px; 29 | border: 1px solid #ccc; 30 | 31 | &::after { 32 | display: none; 33 | } 34 | 35 | & > b { 36 | float: none; 37 | margin: 0; 38 | padding: 0 5px; 39 | border-right: none; 40 | } 41 | } 42 | } 43 | } 44 | 45 | .fire-select-list, 46 | .fire-selected-list { 47 | padding: 0; 48 | margin: 0; 49 | list-style: none; 50 | } 51 | 52 | .fire-selected-list { 53 | width: 100%; 54 | float: left; 55 | cursor: pointer; 56 | } 57 | 58 | .fire-selected-item { 59 | box-sizing: border-box; 60 | border-radius: 3px; 61 | padding: 5px 10px; 62 | color: #333; 63 | background-image: linear-gradient(#fff, #ddd); 64 | display: block; 65 | user-select: none; 66 | font-size: 16px; 67 | line-height: 1em; 68 | position: relative; 69 | 70 | &::after { 71 | content: ''; 72 | display: block; 73 | width: 0; 74 | height: 0; 75 | border-left: 4px solid transparent; 76 | border-right: 4px solid transparent; 77 | border-top: 4px solid #333; 78 | position: absolute; 79 | right: 10px; 80 | top: 50%; 81 | margin-top: -2px; 82 | } 83 | 84 | & > b { 85 | float: right; 86 | margin-right: 20px; 87 | border-left: 1px solid #ccc; 88 | border-right: 1px solid #ccc; 89 | padding: 0 10px; 90 | } 91 | } 92 | 93 | .fire-select-list { 94 | position: absolute; 95 | top: 100%; 96 | left: 0; 97 | border: 1px solid #ccc; 98 | width: 100%; 99 | box-sizing: border-box; 100 | border-radius: 3px; 101 | z-index: 1; 102 | background: #fff; 103 | overflow-y: auto; 104 | max-height: 200px; 105 | } 106 | 107 | .fire-select-item { 108 | padding: 10px; 109 | color: #333; 110 | cursor: pointer; 111 | user-select: none; 112 | font-size: 14px; 113 | border-top: 1px solid #eee; 114 | 115 | &:hover, 116 | &.hover { 117 | background: #eee; 118 | } 119 | } 120 | 121 | .fire-select-item-input { 122 | padding: 10px; 123 | } 124 | 125 | .fire-select-input { 126 | border: none; 127 | font-size: 14px; 128 | line-height: 1em; 129 | outline: none; 130 | color: #333; 131 | width: 100%; 132 | } 133 | 134 | .fs-hidden { 135 | display: none !important; 136 | } 137 | 138 | // ==================================================== 139 | // Animate.css - bounceIn 140 | // ==================================================== 141 | 142 | .animated { 143 | -webkit-animation-duration: 1s; 144 | animation-duration: 1s; 145 | -webkit-animation-fill-mode: both; 146 | animation-fill-mode: both; 147 | } 148 | 149 | @keyframes bounceIn { 150 | from, 20%, 40%, 60%, 80%, to { 151 | animation-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000); 152 | } 153 | 154 | 0% { 155 | opacity: 0; 156 | transform: scale3d(.3, .3, .3); 157 | } 158 | 159 | 20% { 160 | transform: scale3d(1.1, 1.1, 1.1); 161 | } 162 | 163 | 40% { 164 | transform: scale3d(.9, .9, .9); 165 | } 166 | 167 | 60% { 168 | opacity: 1; 169 | transform: scale3d(1.03, 1.03, 1.03); 170 | } 171 | 172 | 80% { 173 | transform: scale3d(.97, .97, .97); 174 | } 175 | 176 | to { 177 | opacity: 1; 178 | transform: scale3d(1, 1, 1); 179 | } 180 | } 181 | 182 | .fs-bounceIn { 183 | animation-name: bounceIn; 184 | } 185 | --------------------------------------------------------------------------------