diff --git a/.gitignore b/.gitignore index 9e75cf3..fff1da3 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ npm-debug.log test/unit/coverage .coveralls.yml .flowconfig +docs/_book +docs/node_modules \ No newline at end of file diff --git a/docs/Advanced/Vuex.md b/docs/Advanced/Vuex.md new file mode 100644 index 0000000..c638457 --- /dev/null +++ b/docs/Advanced/Vuex.md @@ -0,0 +1,18 @@ +### Change Event Vuex Compatibility + +`vue-select` provides a `change` event. This function is passed the currently selected value(s) as it's only parameter. + +This is very useful when integrating with Vuex, as it will allow your to trigger an action to update your vuex state object. Choose a callback and see it in action. + + +```html + +``` + +```js +methods: { + consoleCallback(val) { + console.dir(JSON.stringify(val)) + }, +} +``` diff --git a/docs/Ajax.md b/docs/Ajax/Ajax.md similarity index 100% rename from docs/Ajax.md rename to docs/Ajax/Ajax.md diff --git a/docs/AjaxExample.md b/docs/Ajax/AjaxExample.md similarity index 100% rename from docs/AjaxExample.md rename to docs/Ajax/AjaxExample.md diff --git a/docs/AjaxProps.md b/docs/Ajax/AjaxProps.md similarity index 100% rename from docs/AjaxProps.md rename to docs/Ajax/AjaxProps.md diff --git a/docs/Basics.md b/docs/Basics.md new file mode 100644 index 0000000..7e69810 --- /dev/null +++ b/docs/Basics.md @@ -0,0 +1 @@ +## Getting Started diff --git a/docs/Basics/Localization.md b/docs/Basics/Localization.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/Basics/Options.md b/docs/Basics/Options.md new file mode 100644 index 0000000..6b5609e --- /dev/null +++ b/docs/Basics/Options.md @@ -0,0 +1,36 @@ +## Dropdown Options {#options} + +`vue-select` accepts arrays of strings or objects to use as options through the `options` prop: + +```html + +``` + +When provided an array of objects, `vue-select` will display a single value of the object. By default, `vue-select` will look for a key named `label` on the object to use as display text. + +```html + +``` + +### Option Labels {#labels} + +When the `options` array contains objects, `vue-select` looks for the `label` key to display by default. You can set your own label to match your source data using the `label` prop. + +For example, consider an object with `countryCode` and `countryName` properties: + +```json +{ + countryCode: "CA", + countryName: "Canada" +} +``` + +If you wanted to display `Canada` in the dropdown, you'd use the `countryName` key: + +```html + +``` + +### Null / Empty Options {#emptyOptions} + +`vue-select` requires the `option` property to be an `array`. If you are using Vue in development mode, you will get warnings attempting to pass anything other than an `array` to the `options` prop. If you need a `null`/`empty` value, use an empty array `[]`. diff --git a/docs/Basics/Values.md b/docs/Basics/Values.md new file mode 100644 index 0000000..e8b596b --- /dev/null +++ b/docs/Basics/Values.md @@ -0,0 +1,23 @@ +## Selecting Values {#values} + +The most common use case for `vue-select` is to have the chosen value synced with a parent component. `vue-select` takes advantage of the `v-model` syntax to sync values with a parent. + +```html + +``` + +If you don't require the `value` to be synced, you can also pass the prop directly: + +```html + +``` + +This method allows you to pre-select a value(s), without syncing any changes to the parent component. + +### Single/Multiple Selection {#multiple} + +By default, `vue-select` supports choosing a single value. If you need multiple values, use the `multiple` prop: + +```html + +``` diff --git a/docs/CustomLabels.md b/docs/CustomLabels.md deleted file mode 100644 index 709a53c..0000000 --- a/docs/CustomLabels.md +++ /dev/null @@ -1,9 +0,0 @@ -### Custom Labels - -By default when the `options` array contains objects, `vue-select` looks for the `label` key for display. If your data source doesn't contain that key, you can set your own using the `label` prop. - -On this page, the list of countries used in the examples contains `value` and `label` properties: `{value: "CA", label: "Canada"}`. In this example, we'll display the country code instead of the label. - -`` - - diff --git a/docs/Examples.md b/docs/Examples.md index e69de29..b41615c 100644 --- a/docs/Examples.md +++ b/docs/Examples.md @@ -0,0 +1,19 @@ +- [HTML5 Validation](#validation) +- [Vuex](#vuex) +- [AJAX](#ajax) +- [Dependent vSelects](#dependent) +- [Custom Component with Mixins](#customComponent) + +## HTML5 Validation {#validation} + + + +## Vuex {#vuex} + +[](codepen://sagalbot/aJQJyp?height=500&theme=0) + +## AJAX {#ajax} + +## Dependent vSelects {#dependent} + +## Custom Component with Mixins {#customComponent} diff --git a/docs/Install.md b/docs/Install.md index 4d870f8..19d570c 100644 --- a/docs/Install.md +++ b/docs/Install.md @@ -1,36 +1,20 @@ +## Vue Compatibility +- `vue ~2.0` use `vue-select ~2.0` +- `vue ~1.0` use `vue-select ~1.0` + ## NPM Based WorkFlows -``` bash +```bash $ npm install vue-select ``` -```html - - - -``` - ## Browser Globals -`v1.3.0+` no longer requires any toolchain to use the component: - -Just include `vue` & `vue-select.js` - I recommend using [unpkg.com](https://unpkg.com/#/). +Include `vue` & `vue-select.js` - I recommend using [unpkg.com](https://unpkg.com/#/). ```html + + + diff --git a/docs/Introduction.md b/docs/Introduction.md new file mode 100644 index 0000000..85382da --- /dev/null +++ b/docs/Introduction.md @@ -0,0 +1,26 @@ +# vue-select [![Build Status](https://travis-ci.org/sagalbot/vue-select.svg?branch=master)](https://travis-ci.org/sagalbot/vue-select) [![Code Score](https://img.shields.io/codeclimate/github/sagalbot/vue-select.svg?style=flat-square)](https://lima.codeclimate.com/github/sagalbot/vue-select) [![Code Coverage](https://img.shields.io/codeclimate/coverage/github/sagalbot/vue-select.svg?style=flat-square)](https://codeclimate.com/github/sagalbot/vue-select) [![No Dependencies](https://img.shields.io/gemnasium/sagalbot/vue-select.svg?style=flat-square)](https://gemnasium.com/github.com/sagalbot/vue-select) ![MIT License](https://img.shields.io/github/license/sagalbot/vue-select.svg?style=flat-square) ![Current Release](https://img.shields.io/github/release/sagalbot/vue-select.svg?style=flat-square) + +> A native Vue.js select component that provides similar functionality to Select2 without the overhead of jQuery. + +#### Features +- AJAX Support +- Tagging +- List Filtering/Searching +- Supports Vuex +- Select Single/Multiple Options +- Tested with Bootstrap 3/4, Bulma, Foundation +- +95% Test Coverage +- ~33kb minified with CSS +- Zero dependencies + +## Documentation +- **[Demo & Docs](http://sagalbot.github.io/vue-select/)** +- **[Example on JSBin](http://jsbin.com/saxaru/8/edit?html,js,output)** +- **[CodePen Template](http://codepen.io/sagalbot/pen/NpwrQO)** +- **[Trello Roadmap](https://trello.com/b/vWvITNzS/vue-select)** + +## Install + +###### Vue Compatibility +- `vue ~2.0` use `vue-select ~2.0` +- `vue ~1.0` use `vue-select ~1.0` diff --git a/docs/OnChange.md b/docs/OnChange.md deleted file mode 100644 index 4b3ad49..0000000 --- a/docs/OnChange.md +++ /dev/null @@ -1,26 +0,0 @@ -### Change Event Vuex Compatibility - -vue-select provides a `change` event. This function is passed the currently selected value(s) as it's only parameter. - -This is very useful when integrating with Vuex, as it will allow your to trigger an action to update your vuex state object. Choose a callback and see it in action. - -
-
-
-
- -```html - -``` - -```js -methods: { - consoleCallback(val) { - console.dir(JSON.stringify(val)) - }, - - alertCallback(val) { - alert(JSON.stringify(val)) - } -} -``` diff --git a/docs/Props/Props.md b/docs/Props/Props.md new file mode 100644 index 0000000..e67b919 --- /dev/null +++ b/docs/Props/Props.md @@ -0,0 +1,223 @@ +```js +/** + * Contains the currently selected value. Very similar to a + * `value` attribute on an . + * @type {Object||String||null} + */ +value: { + default: null +} + +/** + * An array of strings or objects to be used as dropdown choices. + * 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 {Array} + */ +options: { + type: Array, + default() { + return [] + }, +} + +/** + * Sets the max-height property on the dropdown list. + * @deprecated + * @type {String} + */ +maxHeight: { + type: String, + default: '400px' +}, + +/** + * Enable/disable filtering the options. + * @type {Boolean} + */ +searchable: { + type: Boolean, + default: true +}, + +/** + * Equivalent to the `multiple` attribute on a ``. + * @type {Object} + */ +placeholder: { + type: String, + default: '' +}, + +/** + * Sets a Vue transition property on the `.dropdown-menu`. vue-select + * does not include CSS for transitions, you'll need to add them yourself. + * @type {String} + */ +transition: { + type: String, + default: 'fade' +}, + +/** + * Enables/disables clearing the search text when an option is selected. + * @type {Boolean} + */ +clearSearchOnSelect: { + type: Boolean, + default: true +}, + +/** + * Close a dropdown when an option is chosen. Set to false to keep the dropdown + * open (useful when combined with multi-select, for example) + * @type {Boolean} + */ +closeOnSelect: { + type: Boolean, + default: true +}, + +/** + * Tells vue-select what key to use when generating option + * labels when each `option` is an object. + * @type {String} + */ +label: { + type: String, + default: 'label' +}, + +/** + * Callback to generate the label text. If {option} + * is an object, returns option[this.label] by default. + * @param {Object || String} option + * @return {String} + */ +getOptionLabel: { + type: Function, + default(option) { + if (typeof option === 'object') { + if (this.label && option[this.label]) { + return option[this.label] + } + } + return option; + } +}, + +/** + * An optional callback function that is called each time the selected + * 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} + */ +onChange: { + type: Function, + default: function (val) { + this.$emit('input', val) + } +}, + +/** + * Enable/disable creating options from searchInput. + * @type {Boolean} + */ +taggable: { + type: Boolean, + default: false +}, + +/** + * When true, newly created tags will be added to + * the options list. + * @type {Boolean} + */ +pushTags: { + type: Boolean, + default: false +}, + +/** + * User defined function for adding Options + * @type {Function} + */ +createOption: { + type: Function, + default(newOption) { + if (typeof this.mutableOptions[0] === 'object') { + newOption = {[this.label]: newOption} + } + this.$emit('option:created', newOption) + return newOption + } +}, + +/** + * When false, updating the options will not reset the select value + * @type {Boolean} + */ +resetOnOptionsChange: { + type: Boolean, + default: false +}, + +/** + * Disable the dropdown entirely. + * @type {Boolean} + */ +noDrop: { + type: Boolean, + default: false +}, + +/** + * Sets the id of the input element. + * @type {String} + * @default {null} + */ +inputId: { + type: String +} +``` + +# AJAX {#ajax} + +```js +/** + * Toggles the adding of a 'loading' class to the main + * .v-select wrapper. Useful to control UI state when + * results are being processed through AJAX. + */ +loading: { + type: Boolean, + default: false +}, + +/** + * Accept a callback function that will be + * run when the search text changes. + * + * loading() accepts a boolean value, and can + * be used to toggle a loading class from + * the onSearch callback. + * + * @param {search} String Current search text + * @param {loading} Function(bool) Toggle loading class + */ +onSearch: { + type: Function, + default: function(search, loading){} +} +``` diff --git a/docs/README.md b/docs/README.md index 3d07efe..3b83f35 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,2 +1,18 @@ -# Introduction +# vue-select +[![Build Status](https://travis-ci.org/sagalbot/vue-select.svg?branch=master)](https://travis-ci.org/sagalbot/vue-select) [![Code Score](https://img.shields.io/codeclimate/github/sagalbot/vue-select.svg?style=flat-square)](https://lima.codeclimate.com/github/sagalbot/vue-select) [![Code Coverage](https://img.shields.io/codeclimate/coverage/github/sagalbot/vue-select.svg?style=flat-square)](https://codeclimate.com/github/sagalbot/vue-select) [![No Dependencies](https://img.shields.io/gemnasium/sagalbot/vue-select.svg?style=flat-square)](https://gemnasium.com/github.com/sagalbot/vue-select) ![MIT License](https://img.shields.io/github/license/sagalbot/vue-select.svg?style=flat-square) ![Current Release](https://img.shields.io/github/release/sagalbot/vue-select.svg?style=flat-square) + +> A native Vue.js select component that provides similar functionality to Select2 without the overhead of jQuery. + +Vue Select was designed to be the Select2 replacement for VueJS. + +#### Features +- AJAX Support +- Tagging +- List Filtering/Searching +- Supports Vuex +- Select Single/Multiple Options +- Tested with Bootstrap 3/4, Bulma, Foundation +- +95% Test Coverage +- ~33kb minified with CSS +- Zero dependencies diff --git a/docs/ReactiveOptions.md b/docs/ReactiveOptions.md deleted file mode 100644 index 0f13ab0..0000000 --- a/docs/ReactiveOptions.md +++ /dev/null @@ -1,19 +0,0 @@ -### Reactive Options - -When the list of options provided by the parent changes, vue-select will react as you'd expect. - -
- -
- -
- -
- - diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index 263112f..173e6fe 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -1,4 +1,27 @@ # Summary -* [Introduction](README.md) +- [Introduction](README.md) +- [Installation](Install.md) + - [npm](Install.md#npm) + - [cdn](Install.md#cdn) +- [Getting Started](Basics.md) + - [Dropdown Options](Basics/Options.md) + - [Option Labels](Basics/Options.md#labels) + - [Null Options](Basics/Options.md#null) + - [Selecting Values](Basics/Values.md#values) + - [Tagging](Basics/Values.md#tagging) + - [Multiple](Basics/Values.md#multiple) +- [Localization](Basics/Localization.md) +- Digging Deeper + - [Templating](Basics.md#options) + - [Vuex](Basics.md#options) + - [AJAX](Basics.md#options) + - [Mixins](Basics.md#options) + - [Validation](Basics.md#options) + - [Examples](Examples.md) + +- API +- [Props](Props/Props.md) +- Events +- Slots diff --git a/docs/SingleMultiple.md b/docs/SingleMultiple.md deleted file mode 100644 index 4257901..0000000 --- a/docs/SingleMultiple.md +++ /dev/null @@ -1,29 +0,0 @@ -
- -### Single/Multiple Selection - -
- -
- -#### Single Option Select - -```html - -``` - -
- -
- -#### Multiple Option Select - -```html - -``` - -
- -
- -
diff --git a/docs/VModel.md b/docs/VModel.md deleted file mode 100644 index e0af80a..0000000 --- a/docs/VModel.md +++ /dev/null @@ -1,15 +0,0 @@ -### Two-Way Value Syncing - -The most common use case for vue-select is being able to sync the components value with a parent component. The `value` property supports two-way data binding to accomplish this. The `.sync` data-binding modifier is completely optional. You may use `value` without a two-way binding to preselect options. Here we have preselected 'Canada' by setting `syncedVal: 'Canada'` on the parent component. The buttons below demonstrate how you can set the `value` from the parent. Current value: {{ syncedVal }} - -
-`` -
-
- -
- -
- - -
diff --git a/docs/book.json b/docs/book.json new file mode 100644 index 0000000..527280d --- /dev/null +++ b/docs/book.json @@ -0,0 +1,20 @@ +{ + "title": "vue-select", + "gitbook": ">3.0.0", + "plugins": ["edit-link", "-fontsettings", "github", "codepen"], + "pluginsConfig": { + "edit-link": { + "base": "https://github.com/sagalbot/vue-select/edit/master/docs", + "label": "Edit This Page" + }, + "github": { + "url": "https://github.com/sagalbot/vue-select/" + } + }, + "links": { + "sharing": { + "facebook": false, + "twitter": false + } + } +} diff --git a/docs/styles/website.css b/docs/styles/website.css new file mode 100644 index 0000000..3ad9d29 --- /dev/null +++ b/docs/styles/website.css @@ -0,0 +1,227 @@ +@import url('https://fonts.googleapis.com/css?family=Roboto+Mono|Source+Sans+Pro:300,400,600'); + +body { + letter-spacing: 0; + color: #34495e; + font-family: 'Source Sans Pro', 'Helvetica Neue', Arial, sans-serif; + font-size: 15px; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + color: #34495e; + background-color: #fff; + margin: 0; +} + +/* LANGS.md index page */ +.book-langs-index { + font-family: 'Source Sans Pro', 'Helvetica Neue', Arial, sans-serif; +} +.book-langs-index .inner .languages { + padding: 20px 0px; +} +.book-langs-index .inner .languages li { + float: none; +} +li a { + color: #42b983; + font-weight: 600; +} + +/* set correct fonts on sidebar and main page */ +.book .book-body .page-wrapper .page-inner section.normal, .book-summary { font-family: 'Source Sans Pro', 'Helvetica Neue', Arial, sans-serif; } + +/* sidebar */ +.book-summary ul.summary li a, +.book-summary ul.summary li span { + color: #7f8c8d; + font-family: 'Source Sans Pro', 'Helvetica Neue', Arial, sans-serif; +} +.book .book-summary ul.summary li span { + opacity: 0.6; + cursor: not-allowed; +} +.book-summary ul.summary li.active>a { + color: #42b983; + font-weight: 600; +} +#book-search-input { background-color: #fafafa; } +.book-summary { background-color: #fff; } + +/* markdown content found on pages */ +.markdown-section h1, +.markdown-section h2, +.markdown-section h3, +.markdown-section h4, +.markdown-section strong { + font-weight: 600; + color: #2c3e50; +} +.markdown-section a { + color: #42b983; + font-weight: 600; +} +.markdown-section p, +.markdown-section ul, +.markdown-section ol { + word-spacing: 0.05em; +} +.markdown-section em { + color: #7f8c8d; +} + +.markdown-section pre { + padding: 1.2em 1.4em; + line-height: 1.5em; + margin: 0; +} + +.markdown-section code, .markdown-section pre { + font-family: 'Roboto Mono', Monaco, courier, monospace; + -webkit-font-smoothing: initial; + -moz-osx-font-smoothing: initial; + background-color: #f8f8f8; +} +code span.css, +code span.javascript, +code span.html, +span[class^="hljs-"] { + -webkit-font-smoothing: initial; + -moz-osx-font-smoothing: initial; +} +.markdown-section pre>code { + font-size: 0.8em; + display: block; +} +.markdown-section code:after, .markdown-section code:before { + content: none; + letter-spacing: 0.05em; +} + +code, pre { + font-family: 'Roboto Mono', Monaco, courier, monospace; + font-size: 0.8em; + background-color: #f8f8f8; + -webkit-font-smoothing: initial; + -moz-osx-font-smoothing: initial; +} +code { + color: #e96900; + padding: 3px 5px; + margin: 0 2px; + border-radius: 2px; + white-space: nowrap; +} + +code .token { + min-height: 1.5em; + -webkit-font-smoothing: initial; + -moz-osx-font-smoothing: initial; +} +pre code { position: relative; } +pre code.lang-html:after, +pre code.lang-js:after, +pre code.lang-bash:after, +pre code.lang-css:after { + position: absolute; + top: 0; + right: 0; + color: #ccc; + text-align: right; + font-size: 0.75em; + padding: 5px 10px 0; + line-height: 15px; + height: 15px; + font-weight: 600; +} +pre code.lang-html:after { + content: 'HTML'; +} +pre code.lang-js:after { + content: 'JS'; +} +pre code.lang-bash:after { + content: 'Shell'; +} +pre code.lang-css:after { + content: 'CSS'; +} +.content img { + max-width: 100%; +} +.content span.light { + color: #7f8c8d; +} +.content span.info { + font-size: 0.85em; + display: inline-block; + vertical-align: middle; + width: 280px; + margin-left: 20px; +} +.markdown-section h1 { + margin: 0 0 1em; +} +.markdown-section h2 { + margin: 45px 0 0.8em; + padding-bottom: 0.7em; + border-bottom: 1px solid #ddd; +} +.markdown-section h3 { + margin: 52px 0 1.2em; +} +.markdown-section figure, +.markdown-section p, +.markdown-section ul, +.markdown-section ol { + margin: 1.2em 0; +} +.markdown-section p, +.markdown-section ul, +.markdown-section ol { + line-height: 1.6em; +} +.markdown-section ul, +.markdown-section ol { + padding-left: 1.5em; +} +.markdown-section a { + color: #42b983; + font-weight: 600; +} +.markdown-section blockquote { + margin: 2em 0; + padding-left: 20px; + border-left: 4px solid #42b983; +} +.markdown-section blockquote p { + font-weight: 600; + margin-left: 0; +} +.markdown-section iframe { + margin: 1em 0; +} + +/* these aren't in gitbook at the moment, but leaving them in for future reference */ +img { + border: none; +} +.highlight { + overflow-x: auto; + position: relative; + padding: 0; + background-color: #f8f8f8; + padding: 0.8em 0.8em 0.4em; + line-height: 1.1em; + border-radius: 2px; +} +.highlight table, +.highlight tr, +.highlight td { + width: 100%; + border-collapse: collapse; + padding: 0; + margin: 0; +} +.highlight .gutter { + width: 1.5em; +} diff --git a/package.json b/package.json index 042b69d..2c961e4 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "license": "MIT", "scripts": { "dev": "node build/dev-server.js", - "dev:docs": "node build/dev-server.js --docs", + "docs": "gitbook serve docs", "build": "node build/build.js", "lint": "eslint --ext .js,.vue src test/unit/specs", "test": "karma start test/unit/karma.conf.js --single-run", @@ -42,6 +42,9 @@ "file-loader": "^0.8.4", "function-bind": "^1.0.2", "gh-pages": "^0.11.0", + "gitbook-plugin-codepen": "^0.1.2", + "gitbook-plugin-edit-link": "^2.0.2", + "gitbook-plugin-github": "^3.0.0", "highlight.js": "^9.9.0", "html-loader": "^0.4.4", "html-webpack-plugin": "^2.8.1",