+
+
+
diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js
index 5e8414f..9f9163e 100644
--- a/docs/.vuepress/config.js
+++ b/docs/.vuepress/config.js
@@ -68,11 +68,8 @@ module.exports = {
ga: isDeployPreview ? '' : 'UA-12818324-8',
},
'@vuepress/pwa': {
- serviceWorker: true,
- updatePopup: {
- message: 'New content is available.',
- buttonText: 'Refresh',
- },
+ serviceWorker: false,
+ updatePopup: true,
},
'@vuepress/plugin-register-components': {},
'@vuepress/plugin-active-header-links': {},
@@ -100,11 +97,19 @@ module.exports = {
['guide/upgrading', 'Upgrading 2.x to 3.x'],
],
},
+ {
+ title: 'Templating & Styling',
+ collapsable: false,
+ children: [
+ ['guide/components', 'Child Components'],
+ ['guide/css', 'CSS & Selectors'],
+ ['guide/slots', 'Slots'],
+ ],
+ },
{
title: 'Digging Deeper',
collapsable: false,
children: [
- ['guide/templating', 'Templating'],
['guide/vuex', 'Vuex'],
['guide/ajax', 'AJAX'],
],
diff --git a/docs/api/slots.md b/docs/api/slots.md
index 11e2489..1f3a94f 100644
--- a/docs/api/slots.md
+++ b/docs/api/slots.md
@@ -1,5 +1,5 @@
::: tip
-VueSelect leverages scoped slots to allow for total customization of the presentation layer.
+Vue Select leverages scoped slots to allow for total customization of the presentation layer.
Slots can be used to change the look and feel of the UI, or to simply swap out text.
:::
diff --git a/docs/guide/components.md b/docs/guide/components.md
new file mode 100644
index 0000000..8455044
--- /dev/null
+++ b/docs/guide/components.md
@@ -0,0 +1,94 @@
+Vue Select utilizes child components throughout, and exposes an API to overwrite these components
+with your own, using the `components` `{Object}` prop. When implementing the `components` prop in
+your code, Vue Select merge it's default components with any keys that you set in the object.
+
+Your object will be merged with the object that is exported below:
+
+<<< @/src/components/childComponents.js{4-7}
+
+You can override the value of any of these keys with your own components.
+
+## Available Components
+
+### Deselect
+
+You may wish to roll your own deselect button. `Deselect` is used within tags on
+`multiple` selects, and serves as the clear button for single selects. Maybe you just want to use
+a simple `` instead.
+
+```html
+
+```
+
+```js
+computed: {
+ Deselect() {
+ return Vue.component('Deselect', {
+ render (createElement) {
+ return createElement('button', 'Clear')
+ }
+ })
+ }
+}
+```
+
+
+
+The same approach applies for `multiple` selects:
+
+
+
+### OpenIndicator
+
+The `OpenIndicator` component is the 'caret' used within the component that adjusts orientation
+based on whether the dropdown is open or closed.
+
+```html
+
+```
+```js
+computed: {
+ OpenIndicator () {
+ return Vue.component('OpenIndicator', {
+ render (createElement) {
+ return createElement('button', '🤘🏻');
+ },
+ });
+ },
+},
+```
+
+
+
+## Setting at Registration
+
+If you want to all instances of Vue Select to use your custom components throughout your app, while
+only having to set the implementation once, you can do so when registering Vue Select as a component.
+
+```js
+import Vue from 'vue';
+import vSelect from 'vue-select';
+
+/**
+* Create custom components to override defaults.
+* @type {{OpenIndicator: *, Deselect: *}}
+*/
+const components = {
+ Deselect: Vue.component('Deselect', {
+ render: (createElement) => createElement('button', '❌'),
+ }),
+ OpenIndicator: Vue.component('OpenIndicator', {
+ render: (createElement) => createElement('span', '🔽'),
+ }),
+};
+
+// Set the components prop default to return our fresh components
+vSelect.props.components.default = () => components;
+
+// Register the component
+Vue.component(vSelect)
+```
+
+
+
+
diff --git a/docs/guide/css.md b/docs/guide/css.md
new file mode 100644
index 0000000..1ef9497
--- /dev/null
+++ b/docs/guide/css.md
@@ -0,0 +1,37 @@
+Vue Select offers many APIs for customizing the look and feel from the component. You can use
+[scoped slots](../api/slots.md), [custom child components](components.md), or modify the built in
+SCSS variables.
+
+::: tip
+Support for CSS variables (custom properties) is currently on the road map for those
+that are not using sass in their projects.
+:::
+
+## SCSS Variables
+
+Variables are leveraged in as much of the component styles as possible. If you really want to dig
+into the SCSS, the files are located in `src/scss`. The variables listed below can be found at
+[`src/scss/global/_variables`](https://github.com/sagalbot/vue-select/blob/master/src/scss/global/_variables.scss).
+
+All variables are implemented with `!default` in order to make them easier to override in your
+application.
+
+<<< @/src/scss/global/_variables.scss
+
+## Overriding Default Styles
+
+Vue Select takes the approach of using selectors with a single level of specificity, while using
+classes that are very specific to Vue Select to avoid collisions with your app.
+
+All classes within Vue Select use the `vs__` prefix, and selectors are generally a single classname
+– unless there is a state being applied to the component.
+
+In order to override a default property in your app, you should add one level of specificity.
+The easiest way to do this, is to add `.v-select` before the `vs__*` selector if you want to adjust
+all instances of Vue Select, or add your own classname if you just want to affect one.
+
+
+
+<<< @/docs/.vuepress/components/CssSpecificity.vue
+
+
diff --git a/docs/guide/templating.md b/docs/guide/slots.md
similarity index 64%
rename from docs/guide/templating.md
rename to docs/guide/slots.md
index 69ced1e..10d3c50 100644
--- a/docs/guide/templating.md
+++ b/docs/guide/slots.md
@@ -1,3 +1,9 @@
+::: tip 🚧
+This section of the guide is a work in progress! Check back soon for an update.
+Vue Select currently offers quite a few scoped slots, and you can check out the
+[API Docs for Slots](../api/slots.md) in the meantime while a good guide is put together.
+:::
+
#### Scoped Slot `option`
vue-select provides the scoped `option` slot in order to create custom dropdown templates.
diff --git a/netlify.toml b/netlify.toml
index a535877..835b998 100644
--- a/netlify.toml
+++ b/netlify.toml
@@ -13,3 +13,10 @@
[context.deploy-preview]
publish = "docs/.vuepress/dist"
command = "yarn && yarn build:preview"
+
+
+# Redirects
+# @see https://www.netlify.com/docs/netlify-toml-reference/
+[[redirects]]
+ from = "/guide/templating"
+ to = "/guide/slots"
diff --git a/src/components/Select.vue b/src/components/Select.vue
index 359b2d5..db63ef3 100644
--- a/src/components/Select.vue
+++ b/src/components/Select.vue
@@ -18,7 +18,7 @@
{{ getOptionLabel(option) }}
@@ -37,10 +37,12 @@
class="vs__clear"
title="Clear selection"
>
-
+
-
+
+
+
Loading...
@@ -75,11 +77,10 @@
import pointerScroll from '../mixins/pointerScroll'
import typeAheadPointer from '../mixins/typeAheadPointer'
import ajax from '../mixins/ajax'
- import Deselect from './Deselect'
- import OpenIndicator from './OpenIndicator'
+ import childComponents from './childComponents';
export default {
- components: {Deselect, OpenIndicator},
+ components: {...childComponents},
mixins: [pointerScroll, typeAheadPointer, ajax],
@@ -92,6 +93,18 @@
*/
value: {},
+ /**
+ * An object with any custom components that you'd like to overwrite
+ * the default implementation of in your app. The keys in this object
+ * will be merged with the defaults.
+ * @see https://vue-select.org/guide/components.html
+ * @type {Function}
+ */
+ components: {
+ type: Object,
+ default: () => ({}),
+ },
+
/**
* 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
@@ -443,10 +456,6 @@
},
},
- /**
- * Clone props into mutable values,
- * attach any event listeners.
- */
created() {
this.mutableLoading = this.loading;
@@ -878,7 +887,29 @@
},
spinner: {
loading: this.mutableLoading
- }
+ },
+ openIndicator: {
+ attributes: {
+ 'v-if': !this.noDrop,
+ 'ref': 'openIndicator',
+ 'role': 'presentation',
+ 'class': 'vs__open-indicator',
+ },
+ },
+ };
+ },
+
+ /**
+ * Returns an object containing the child components
+ * that will be used throughout the component. The
+ * `component` prop can be used to overwrite the defaults.
+ *
+ * @return {Object}
+ */
+ childComponents () {
+ return {
+ ...childComponents,
+ ...this.components
};
},
diff --git a/src/components/childComponents.js b/src/components/childComponents.js
new file mode 100644
index 0000000..ab01201
--- /dev/null
+++ b/src/components/childComponents.js
@@ -0,0 +1,7 @@
+import Deselect from './Deselect';
+import OpenIndicator from './OpenIndicator';
+
+export default {
+ Deselect,
+ OpenIndicator
+}
diff --git a/tests/unit/Components.spec.js b/tests/unit/Components.spec.js
new file mode 100644
index 0000000..3c43710
--- /dev/null
+++ b/tests/unit/Components.spec.js
@@ -0,0 +1,30 @@
+import Vue from 'vue';
+import { selectWithProps } from '../helpers';
+
+describe('Components API', () => {
+
+ it('swap the Deselect component', () => {
+ const Deselect = Vue.component('Deselect', {
+ render (createElement) {
+ return createElement('button', 'remove');
+ },
+ });
+
+ const Select = selectWithProps({components: {Deselect}});
+
+ expect(Select.contains(Deselect)).toBeTruthy();
+ });
+
+ it('swap the OpenIndicator component', () => {
+ const OpenIndicator = Vue.component('OpenIndicator', {
+ render (createElement) {
+ return createElement('i', '^');
+ },
+ });
+
+ const Select = selectWithProps({components: {OpenIndicator}});
+
+ expect(Select.contains(OpenIndicator)).toBeTruthy();
+ });
+
+});
diff --git a/tests/unit/Selecting.spec.js b/tests/unit/Selecting.spec.js
index f5a522b..d4d1489 100755
--- a/tests/unit/Selecting.spec.js
+++ b/tests/unit/Selecting.spec.js
@@ -58,7 +58,7 @@ describe("VS - Selecting Values", () => {
const spy = jest.spyOn(Select.vm, "typeAheadSelect");
- Select.find({ ref: "search" }).trigger("keyup.tab");
+ Select.find({ ref: "search" }).trigger("keydown.tab");
expect(spy).toHaveBeenCalledWith();
});