mirror of
https://github.com/tenrok/vue-select.git
synced 2026-06-16 09:10:33 +03:00
nuxt setup, tailwind
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
<template>
|
||||
<v-select>
|
||||
<template v-slot:no-options="{ search, searching }">
|
||||
<template v-if="searching">
|
||||
No results found for <em>{{ search }}</em>.
|
||||
</template>
|
||||
<em style="opacity: 0.5;" v-else>Start typing to search for a country.</em>
|
||||
</template>
|
||||
</v-select>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'BetterNoOptions',
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,21 @@
|
||||
<template>
|
||||
<div>
|
||||
<v-select
|
||||
placeholder="choose a country"
|
||||
v-model="selected"
|
||||
:components="{Deselect}"
|
||||
:options="['Canada', 'United States']"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data: () => ({
|
||||
selected: 'Canada',
|
||||
Deselect: {
|
||||
render: createElement => createElement('span', '❌'),
|
||||
},
|
||||
}),
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,28 @@
|
||||
<template>
|
||||
<p :data-height="height"
|
||||
data-theme-id="32252"
|
||||
:data-slug-hash="url"
|
||||
data-default-tab="result"
|
||||
data-user="sagalbot"
|
||||
class="codepen">
|
||||
</p>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import mountCodePen from '../utils/codePen.js';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
url: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
height: {
|
||||
default: 250
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
mountCodePen();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,63 @@
|
||||
<template>
|
||||
<ul>
|
||||
<li v-for="{ login, avatar_url, html_url, contributions } in contributors">
|
||||
<img :src="`${avatar_url}&s=75`" :alt="`${login}'s Avatar`" />
|
||||
<div>
|
||||
<a :href="html_url">@{{ login }}</a>
|
||||
<br /><a
|
||||
class="contributions-link"
|
||||
:href="
|
||||
`https://github.com/sagalbot/vue-select/commits?author=${login}`
|
||||
"
|
||||
>{{ contributions }} contributions</a
|
||||
>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { CONTRIBUTORS } from "@dynamic/constants";
|
||||
|
||||
export default {
|
||||
data: () => ({
|
||||
contributors: CONTRIBUTORS.filter(
|
||||
({ login }) => login !== "semantic-release-bot"
|
||||
)
|
||||
})
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
max-width: 100%;
|
||||
margin-top: 2rem;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
}
|
||||
img {
|
||||
width: 75px;
|
||||
height: 75px;
|
||||
margin-right: 1rem;
|
||||
border-radius: 100%;
|
||||
}
|
||||
li {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
margin-bottom: 2rem;
|
||||
margin-right: 1rem;
|
||||
}
|
||||
a {
|
||||
display: inline-block;
|
||||
max-width: 150px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.contributions-link {
|
||||
color: #2c5282;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,18 @@
|
||||
<template>
|
||||
<v-select :options="options"></v-select>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import countryCodes from '../data/countryCodes.js';
|
||||
|
||||
export default {
|
||||
name: 'CountrySelect',
|
||||
data: () => ({
|
||||
options: countryCodes,
|
||||
}),
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,26 @@
|
||||
<template>
|
||||
<div>
|
||||
<v-select
|
||||
class="style-chooser"
|
||||
placeholder="Choose a Styling Option"
|
||||
:options="['Components', 'CSS / Variables', 'Slots']"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.style-chooser .vs__search::placeholder,
|
||||
.style-chooser .vs__dropdown-toggle,
|
||||
.style-chooser .vs__dropdown-menu {
|
||||
background: #dfe5fb;
|
||||
border: none;
|
||||
color: #394066;
|
||||
text-transform: lowercase;
|
||||
font-variant: small-caps;
|
||||
}
|
||||
|
||||
.style-chooser .vs__clear,
|
||||
.style-chooser .vs__open-indicator {
|
||||
fill: #394066;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,19 @@
|
||||
<template>
|
||||
<v-select
|
||||
:options="['Vue.js', 'React', 'Angular']"
|
||||
:components="{Deselect, OpenIndicator}"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data: () => ({
|
||||
Deselect: {
|
||||
render: createElement => createElement('span', '❌'),
|
||||
},
|
||||
OpenIndicator: {
|
||||
render: createElement => createElement('span', '🔽'),
|
||||
},
|
||||
}),
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,25 @@
|
||||
<template>
|
||||
<v-select
|
||||
taggable
|
||||
multiple
|
||||
no-drop
|
||||
:map-keydown="handlers"
|
||||
placeholder="enter an email"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'CustomHandlers',
|
||||
methods: {
|
||||
handlers: (map, vm) => ({
|
||||
...map, 50: e => {
|
||||
e.preventDefault();
|
||||
if( e.key === '@' && vm.search.length > 0 ) {
|
||||
vm.search = `${vm.search}@gmail.com`;
|
||||
}
|
||||
},
|
||||
}),
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,31 @@
|
||||
<template>
|
||||
<v-select :filter="fuseSearch" :options="books" :getOptionLabel="option => option.title">
|
||||
<template #option="{ author, title }">
|
||||
{{ title }}
|
||||
<br />
|
||||
<cite>{{ author.firstName }} {{ author.lastName }}</cite>
|
||||
</template>
|
||||
</v-select>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Fuse from "fuse.js";
|
||||
import books from "../data/books.js";
|
||||
|
||||
export default {
|
||||
computed: {
|
||||
books: () => books
|
||||
},
|
||||
methods: {
|
||||
fuseSearch(options, search) {
|
||||
const fuse = new Fuse(options, {
|
||||
keys: ["title", "author.firstName", "author.lastName"],
|
||||
shouldSort: true
|
||||
});
|
||||
return search.length
|
||||
? fuse.search(search).map(({ item }) => item)
|
||||
: fuse.list;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,74 @@
|
||||
<template>
|
||||
<v-select
|
||||
:options="paginated"
|
||||
:filterable="false"
|
||||
@open="onOpen"
|
||||
@close="onClose"
|
||||
@search="query => search = query"
|
||||
>
|
||||
<template #list-footer>
|
||||
<li ref="load" class="loader" v-show="hasNextPage">
|
||||
Loading more options...
|
||||
</li>
|
||||
</template>
|
||||
</v-select>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import countries from '../data/countries.js';
|
||||
|
||||
export default {
|
||||
name: "InfiniteScroll",
|
||||
data: () => ({
|
||||
observer: null,
|
||||
limit: 10,
|
||||
search: ''
|
||||
}),
|
||||
mounted () {
|
||||
/**
|
||||
* You could do this directly in data(), but since these docs
|
||||
* are server side rendered, IntersectionObserver doesn't exist
|
||||
* in that environment, so we need to do it in mounted() instead.
|
||||
*/
|
||||
this.observer = new IntersectionObserver(this.infiniteScroll);
|
||||
},
|
||||
computed: {
|
||||
filtered () {
|
||||
return countries.filter(country => country.includes(this.search));
|
||||
},
|
||||
paginated () {
|
||||
return this.filtered.slice(0, this.limit);
|
||||
},
|
||||
hasNextPage () {
|
||||
return this.paginated.length < this.filtered.length;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async onOpen () {
|
||||
if (this.hasNextPage) {
|
||||
await this.$nextTick();
|
||||
this.observer.observe(this.$refs.load)
|
||||
}
|
||||
},
|
||||
onClose () {
|
||||
this.observer.disconnect();
|
||||
},
|
||||
async infiniteScroll ([{isIntersecting, target}]) {
|
||||
if (isIntersecting) {
|
||||
const ul = target.offsetParent;
|
||||
const scrollTop = target.offsetParent.scrollTop;
|
||||
this.limit += 10;
|
||||
await this.$nextTick();
|
||||
ul.scrollTop = scrollTop;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.loader {
|
||||
text-align: center;
|
||||
color: #bbbbbb;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,21 @@
|
||||
<template>
|
||||
<v-select
|
||||
multiple
|
||||
placeholder="Choose up to 3 books!"
|
||||
label="title"
|
||||
v-model="selected"
|
||||
:options="books"
|
||||
:selectable="() => selected.length < 3"
|
||||
/>
|
||||
</template>
|
||||
<script>
|
||||
import books from '../data/books.js';
|
||||
export default {
|
||||
data() {
|
||||
return { selected: [] }
|
||||
},
|
||||
computed: {
|
||||
books: () => books,
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,43 @@
|
||||
<template>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Country</th>
|
||||
</tr>
|
||||
<tr v-for="person in people">
|
||||
<td>{{ person.name }}</td>
|
||||
<td>
|
||||
<v-select
|
||||
:options="options"
|
||||
:value="person.country"
|
||||
@input="country => updateCountry(person, country)"
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import countries from '../data/countries.js';
|
||||
|
||||
export default {
|
||||
data: () => ({
|
||||
people: [{name: 'John', country: ''}, {name: 'Jane', country: ''}],
|
||||
}),
|
||||
methods: {
|
||||
updateCountry (person, country) {
|
||||
person.country = country;
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
options: () => countries,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
table {
|
||||
display: table;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,21 @@
|
||||
<template>
|
||||
<div>
|
||||
<v-select
|
||||
multiple
|
||||
v-model="selected"
|
||||
:options="['Canada', 'United States']"
|
||||
:components="{Deselect}"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data: () => ({
|
||||
selected: ['Canada'],
|
||||
Deselect: {
|
||||
render: createElement => createElement('span', '❌'),
|
||||
},
|
||||
}),
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,18 @@
|
||||
<template>
|
||||
<div>
|
||||
<v-select
|
||||
:options="['Canada', 'United States']"
|
||||
:components="{OpenIndicator}"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data: () => ({
|
||||
OpenIndicator: {
|
||||
render: createElement => createElement('span', '🔽'),
|
||||
},
|
||||
}),
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,49 @@
|
||||
<template>
|
||||
<v-select :options="paginated" @search="query => search = query" :filterable="false">
|
||||
<li slot="list-footer" class="pagination">
|
||||
<button @click="offset -= 10" :disabled="!hasPrevPage">Prev</button>
|
||||
<button @click="offset += 10" :disabled="!hasNextPage">Next</button>
|
||||
</li>
|
||||
</v-select>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import countries from '../data/countries.js';
|
||||
export default {
|
||||
data: () => ({
|
||||
countries,
|
||||
search: '',
|
||||
offset: 0,
|
||||
limit: 10,
|
||||
}),
|
||||
computed: {
|
||||
filtered () {
|
||||
return this.countries.filter(country => country.includes(this.search));
|
||||
},
|
||||
paginated () {
|
||||
return this.filtered.slice(this.offset, this.limit + this.offset);
|
||||
},
|
||||
hasNextPage () {
|
||||
const nextOffset = this.offset + 10;
|
||||
return Boolean(this.filtered.slice(nextOffset, this.limit + nextOffset).length);
|
||||
},
|
||||
hasPrevPage () {
|
||||
const prevOffset = this.offset - 10;
|
||||
return Boolean(this.filtered.slice(prevOffset, this.limit + prevOffset).length);
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.pagination {
|
||||
display: flex;
|
||||
margin: .25rem .25rem 0;
|
||||
}
|
||||
.pagination button {
|
||||
flex-grow: 1;
|
||||
}
|
||||
.pagination button:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,83 @@
|
||||
<template>
|
||||
<div>
|
||||
<v-select :options="countries" append-to-body :calculate-position="withPopper" />
|
||||
|
||||
<label for="position" style="display: block; margin: 1rem 0;">
|
||||
<input
|
||||
type="checkbox"
|
||||
id="position"
|
||||
v-model="placement"
|
||||
true-value="top"
|
||||
false-value="bottom"
|
||||
>
|
||||
Position dropdown above
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import countries from '../data/countries.js'
|
||||
import { createPopper } from '@popperjs/core';
|
||||
|
||||
export default {
|
||||
data: () => ({countries, placement: 'top'}),
|
||||
methods: {
|
||||
withPopper (dropdownList, component, {width}) {
|
||||
/**
|
||||
* We need to explicitly define the dropdown width since
|
||||
* it is usually inherited from the parent with CSS.
|
||||
*/
|
||||
dropdownList.style.width = width;
|
||||
|
||||
/**
|
||||
* Here we position the dropdownList relative to the $refs.toggle Element.
|
||||
*
|
||||
* The 'offset' modifier aligns the dropdown so that the $refs.toggle and
|
||||
* the dropdownList overlap by 1 pixel.
|
||||
*
|
||||
* The 'toggleClass' modifier adds a 'drop-up' class to the Vue Select
|
||||
* wrapper so that we can set some styles for when the dropdown is placed
|
||||
* above.
|
||||
*/
|
||||
const popper = createPopper(component.$refs.toggle, dropdownList, {
|
||||
placement: this.placement,
|
||||
modifiers: [
|
||||
{
|
||||
name: 'offset', options: {
|
||||
offset: [0, -1]
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'toggleClass',
|
||||
enabled: true,
|
||||
phase: 'write',
|
||||
fn ({state}) {
|
||||
component.$el.classList.toggle('drop-up', state.placement === 'top')
|
||||
},
|
||||
}]
|
||||
});
|
||||
|
||||
/**
|
||||
* To prevent memory leaks Popper needs to be destroyed.
|
||||
* If you return function, it will be called just before dropdown is removed from DOM.
|
||||
*/
|
||||
return () => popper.destroy();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.v-select.drop-up.vs--open .vs__dropdown-toggle {
|
||||
border-radius: 0 0 4px 4px;
|
||||
border-top-color: transparent;
|
||||
border-bottom-color: rgba(60, 60, 60, 0.26);
|
||||
}
|
||||
|
||||
[data-popper-placement='top'] {
|
||||
border-radius: 4px 4px 0 0;
|
||||
border-top-style: solid;
|
||||
border-bottom-style: none;
|
||||
box-shadow: 0 -3px 6px rgba(0, 0, 0, 0.15)
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,60 @@
|
||||
<template>
|
||||
<div class="flex">
|
||||
<div>
|
||||
<v-select
|
||||
label="country"
|
||||
v-model="selected"
|
||||
:reduce="opt => opt.meta.id"
|
||||
:options="options"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<pre><code>v-model value: {{ selected || 'null' }}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ReducerNestedValue',
|
||||
data: () => ({
|
||||
selected: null,
|
||||
options: [
|
||||
{
|
||||
country: 'canada',
|
||||
meta: {
|
||||
id: '1',
|
||||
code: 'ca',
|
||||
},
|
||||
}],
|
||||
}),
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.flex {
|
||||
margin-bottom: 2rem;
|
||||
border: 1px solid #eaecef;
|
||||
/*padding: 1rem;*/
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.flex > div {
|
||||
flex-grow: 1;
|
||||
width: 50%;
|
||||
padding: 0 1rem;
|
||||
}
|
||||
|
||||
pre {
|
||||
margin: 0;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
code {
|
||||
color: #635762 !important;
|
||||
color: #5b2d2d !important;
|
||||
/*color: #7ec699 !important;*/
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,276 @@
|
||||
<template>
|
||||
<div id="sandbox-wrap">
|
||||
<div id="config">
|
||||
|
||||
<div class="list-item" v-if="!hideHelp">
|
||||
<p>Use the controls below to adjust the props used
|
||||
by the vue-select components.</p>
|
||||
<p>The API provides
|
||||
more props than are shown here, these are some
|
||||
commonly adjusted settings.</p>
|
||||
</div>
|
||||
|
||||
<h5 class="list-item">Basic Features</h5>
|
||||
|
||||
<div class="list-item">
|
||||
<label for="multiple">
|
||||
<input id="multiple" type="checkbox" v-model="configuration.multiple">
|
||||
<code>:multiple="{{ configuration.multiple ? 'true' : 'false' }}"</code>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="list-item">
|
||||
<label for="disabled">
|
||||
<input id="disabled" type="checkbox" v-model="configuration.disabled">
|
||||
<code>:disabled="{{ configuration.disabled ? 'true' : 'false' }}"</code>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="list-item">
|
||||
<label for="clearable">
|
||||
<input id="clearable" type="checkbox" v-model="configuration.clearable">
|
||||
<code>:clearable="{{ configuration.clearable ? 'true' : 'false' }}"</code>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="list-item">
|
||||
<label for="searchable">
|
||||
<input id="searchable" type="checkbox" v-model="configuration.searchable">
|
||||
<code>:searchable="{{ configuration.searchable ? 'true' : 'false' }}"</code>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="list-item">
|
||||
<label for="filterable">
|
||||
<input id="filterable" type="checkbox" v-model="configuration.filterable">
|
||||
<code>:filterable="{{ configuration.searchable ? 'true' : 'false' }}"</code>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<h5 class="list-item">Tagging</h5>
|
||||
|
||||
<div class="list-item">
|
||||
<label for="taggable">
|
||||
<input id="taggable" type="checkbox" v-model="configuration.taggable">
|
||||
<code>:taggable="{{ configuration.taggable ? 'true' : 'false' }}"</code>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="list-item">
|
||||
<label for="noDrop">
|
||||
<input id="noDrop" type="checkbox" v-model="configuration.noDrop">
|
||||
<code>:no-drop="{{ configuration.noDrop ? 'true' : 'false' }}"</code>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="list-item">
|
||||
<label for="pushTags">
|
||||
<input id="pushTags" type="checkbox" v-model="configuration.pushTags">
|
||||
<code>:push-tags="{{ configuration.pushTags ? 'true' : 'false' }}"</code>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<h5 class="list-item">UX</h5>
|
||||
|
||||
<div class="list-item">
|
||||
<label for="selectOnTab">
|
||||
<input id="selectOnTab" type="checkbox" v-model="configuration.selectOnTab">
|
||||
<code>:select-on-tab="{{ configuration.selectOnTab ? 'true' : 'false' }}"</code>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="list-item">
|
||||
<label for="closeOnSelect">
|
||||
<input id="closeOnSelect" type="checkbox" v-model="configuration.closeOnSelect">
|
||||
<code>:close-on-select="{{ configuration.closeOnSelect ? 'true' : 'false' }}"</code>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<h5 class="list-item">Localization / i18n</h5>
|
||||
|
||||
<div class="list-item">
|
||||
<label for="rtl">
|
||||
<input id="rtl" type="radio" v-model="configuration.dir" value="rtl">
|
||||
<code>dir="rtl"</code>
|
||||
</label>
|
||||
<label for="ltr">
|
||||
<input id="ltr" type="radio" v-model="configuration.dir" value="ltr">
|
||||
<code>dir="ltr"</code>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="sandbox">
|
||||
<slot v-bind="configuration">
|
||||
<div class="example">
|
||||
<v-select v-bind="configuration" placeholder="country objects"></v-select>
|
||||
</div>
|
||||
|
||||
<div class="example">
|
||||
<v-select v-bind="configuration" placeholder="country objects, using option scoped slots">
|
||||
<template slot="selected-option" slot-scope="{ label, value }">
|
||||
{{ label }} -- {{ value }}
|
||||
</template>
|
||||
<template slot="option" slot-scope="{ label, value }">
|
||||
{{ label }} ({{ value }})
|
||||
</template>
|
||||
</v-select>
|
||||
</div>
|
||||
|
||||
<div class="example">
|
||||
<v-select v-bind="configuration" :options="['cat', 'dog', 'bear']" placeholder="string options, option slots">
|
||||
<template slot="selected-option" slot-scope="{ label }">
|
||||
{{ label }}
|
||||
</template>
|
||||
<template slot="option" slot-scope="{ label }">
|
||||
{{ label }}
|
||||
</template>
|
||||
</v-select>
|
||||
</div>
|
||||
|
||||
<div class="example">
|
||||
<v-select v-bind="configuration" :options="[1,5,10]" placeholder="options=[1,5,10]"></v-select>
|
||||
</div>
|
||||
|
||||
<div class="example">
|
||||
<v-select v-bind="configuration" label="title" :options="optionDataSets.books" :filter="fuseSearch"
|
||||
placeholder="advanced filtering w/ fuse.js + scoped slots">
|
||||
<template slot="option" slot-scope="option">
|
||||
<strong>{{ option.title }}</strong><br>
|
||||
<em>{{ `${option.author.firstName} ${option.author.lastName}` }}</em>
|
||||
</template>
|
||||
</v-select>
|
||||
</div>
|
||||
|
||||
<div class="example">
|
||||
<v-select
|
||||
v-bind="configuration"
|
||||
placeholder="search github repositories.."
|
||||
label="full_name"
|
||||
@search="search"
|
||||
:options="ajaxRes"
|
||||
>
|
||||
</v-select>
|
||||
</div>
|
||||
|
||||
<div class="example">
|
||||
<v-select v-bind="configuration" :options="[]" placeholder="options=[]"></v-select>
|
||||
</div>
|
||||
</slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Fuse from 'fuse.js';
|
||||
import debounce from 'lodash/debounce';
|
||||
import vSelect from '../../src/components/Select.vue';
|
||||
import countries from '../data/countryCodes.js';
|
||||
import books from '../data/books.js';
|
||||
|
||||
const defaultConfig = () => ({
|
||||
options: countries,
|
||||
multiple: false,
|
||||
dir: 'ltr',
|
||||
clearable: true,
|
||||
searchable: true,
|
||||
filterable: true,
|
||||
noDrop: false,
|
||||
closeOnSelect: true,
|
||||
disabled: false,
|
||||
selectOntab: false,
|
||||
placeholder: 'Select a Country...',
|
||||
});
|
||||
|
||||
export default {
|
||||
props: {
|
||||
hideHelp: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
components: {vSelect},
|
||||
data () {
|
||||
return {
|
||||
configuration: defaultConfig(),
|
||||
value: null,
|
||||
ajaxRes: [],
|
||||
people: [],
|
||||
optionDataSet: 'countries',
|
||||
optionDataSets: {
|
||||
countries,
|
||||
books,
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
search (search, loading) {
|
||||
loading(true);
|
||||
this.getRepositories(search, loading, this);
|
||||
},
|
||||
searchPeople (search, loading) {
|
||||
loading(true);
|
||||
this.getPeople(loading, this);
|
||||
},
|
||||
getPeople: debounce((loading, vm) => {
|
||||
vm.$http.get(`https://reqres.in/api/users?per_page=10`).then(res => {
|
||||
vm.people = res.data.data;
|
||||
loading(false);
|
||||
});
|
||||
}, 250),
|
||||
getRepositories: debounce((search, loading, vm) => {
|
||||
vm.$http
|
||||
.get(`https://api.github.com/search/repositories?q=${search}`)
|
||||
.then(res => {
|
||||
vm.ajaxRes = res.data.items;
|
||||
loading(false);
|
||||
});
|
||||
}, 250),
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
#sandbox-wrap {
|
||||
min-height: 100%;
|
||||
display: grid;
|
||||
grid-template-columns: auto 75%;
|
||||
grid-template-rows: auto;
|
||||
grid-template-areas:
|
||||
"sidebar component"
|
||||
}
|
||||
|
||||
#config {
|
||||
grid-area: sidebar;
|
||||
border-right: 1px solid #eaecef;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#sandbox {
|
||||
grid-area: component;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.list-item {
|
||||
margin-top: 0;
|
||||
margin-bottom: 1rem;
|
||||
padding: 1rem 1rem 0;
|
||||
}
|
||||
|
||||
.list-item:not(:first-child) {
|
||||
border-top: 1px solid #eaecef;
|
||||
}
|
||||
|
||||
.example {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.v-select {
|
||||
width: 25em;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<v-select append-to-body>
|
||||
<template #footer>
|
||||
<div style="opacity: .8">Bottom of the component, in the footer slot!</div>
|
||||
</template>
|
||||
</v-select>
|
||||
</template>
|
||||
@@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<v-select>
|
||||
<template #header>
|
||||
<div style="opacity: .8">Top of the component, in the header slot!</div>
|
||||
</template>
|
||||
</v-select>
|
||||
</template>
|
||||
@@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<v-select>
|
||||
<template #list-footer>
|
||||
<li style="text-align: center">Bottom of the list!</li>
|
||||
</template>
|
||||
</v-select>
|
||||
</template>
|
||||
@@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<v-select>
|
||||
<template #list-header>
|
||||
<li style="text-align: center">Top of the list!</li>
|
||||
</template>
|
||||
</v-select>
|
||||
</template>
|
||||
@@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<v-select>
|
||||
<template #no-options="{ search, searching, loading }">
|
||||
This is the no options slot.
|
||||
</template>
|
||||
</v-select>
|
||||
</template>
|
||||
@@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<v-select>
|
||||
<template #open-indicator="{ attributes }">
|
||||
<span v-bind="attributes">🔽</span>
|
||||
</template>
|
||||
</v-select>
|
||||
</template>
|
||||
@@ -0,0 +1,24 @@
|
||||
<template>
|
||||
<v-select :options="books" label="title">
|
||||
<template #option="{ title, author }">
|
||||
<h3 style="margin: 0">{{ title }}</h3>
|
||||
<em>{{ author.firstName }} {{ author.lastName }}</em>
|
||||
</template>
|
||||
</v-select>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data: () => ({
|
||||
books: [
|
||||
{
|
||||
title: "Old Man's War",
|
||||
author: {
|
||||
firstName: "John",
|
||||
lastName: "Scalzi"
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,12 @@
|
||||
<template>
|
||||
<v-select>
|
||||
<template #search="{ attributes, events }">
|
||||
<input
|
||||
maxlength="1"
|
||||
class="vs__search"
|
||||
v-bind="attributes"
|
||||
v-on="events"
|
||||
>
|
||||
</template>
|
||||
</v-select>
|
||||
</template>
|
||||
@@ -0,0 +1,26 @@
|
||||
<template>
|
||||
<v-select v-model="selected" :options="books" label="title">
|
||||
<template #selected-option="{ title, author }">
|
||||
<div style="display: flex; align-items: baseline;">
|
||||
<strong>{{ title }}</strong>
|
||||
<em style="margin-left: .5rem;">by {{ author.firstName }} {{ author.lastName }}</em>
|
||||
</div>
|
||||
</template>
|
||||
</v-select>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const book = {
|
||||
title: "Old Man's War",
|
||||
author: {
|
||||
firstName: "John",
|
||||
lastName: "Scalzi"
|
||||
}
|
||||
};
|
||||
export default {
|
||||
data: () => ({
|
||||
books: [book],
|
||||
selected: book
|
||||
})
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,23 @@
|
||||
<template>
|
||||
<v-select :options="books" label="title">
|
||||
<template #selected-option-container="{ option, deselect, multiple, disabled }">
|
||||
<div class="vs__selected">{{ option.title }}</div>
|
||||
</template>
|
||||
</v-select>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data: () => ({
|
||||
books: [
|
||||
{
|
||||
title: "Old Man's War",
|
||||
author: {
|
||||
firstName: "John",
|
||||
lastName: "Scalzi"
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,9 @@
|
||||
<template>
|
||||
<v-select :loading="true">
|
||||
<template #spinner="{ loading }">
|
||||
<div v-if="loading" style="border-left-color: rgba(88,151,251,0.71)" class="vs__spinner">
|
||||
The .vs__spinner class will hide the text for me.
|
||||
</div>
|
||||
</template>
|
||||
</v-select>
|
||||
</template>
|
||||
@@ -0,0 +1,25 @@
|
||||
<template>
|
||||
<p class="sponsor">
|
||||
Are you using Vue Select on a lot of projects? Please consider
|
||||
<a href="https://github.com/sponsors/sagalbot" target="_blank">
|
||||
sponsoring @sagalbot!
|
||||
</a>
|
||||
</p>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.sponsor {
|
||||
display: block;
|
||||
border: 2px solid #e2e8f0;
|
||||
background: #f7fafc;
|
||||
border-radius: 10px;
|
||||
padding: 0.25rem;
|
||||
font-weight: 600;
|
||||
text-align: center;
|
||||
margin: 0 auto;
|
||||
color: #8492a4;
|
||||
}
|
||||
p a {
|
||||
color: #48BB78;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,146 @@
|
||||
<template>
|
||||
<div class="sponsor-me">
|
||||
<div class="avatar">
|
||||
<a href="https://github.com/sponsors/sagalbot">
|
||||
<img
|
||||
src="https://avatars2.githubusercontent.com/u/692538?s=400&u=a5ab0d164266bd2d59ce1a514835627b4cc4f24f&v=4"
|
||||
alt="Jeff Sagal's Avatar"
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
<div class="cta">
|
||||
<p style="font-size: 1.2rem; font-weight: 600;">
|
||||
Hi! I'm Jeff Sagal, the author of Vue Select.
|
||||
</p>
|
||||
<p>
|
||||
I've spent hundreds of hours working alongside contributors to make Vue
|
||||
Select the best it can be. I've researched UX and accessibility
|
||||
patterns, squashed bugs, reviewed code, tested-cross browser, and spent
|
||||
many evenings and weekends working on these docs.
|
||||
</p>
|
||||
<p>
|
||||
If it's saved you time on your projects, please consider supporting me
|
||||
on GitHub sponsors.
|
||||
</p>
|
||||
<div class="links">
|
||||
<a
|
||||
href="https://github.com/sponsors/sagalbot"
|
||||
class="button"
|
||||
target="_blank"
|
||||
>
|
||||
<svg viewBox="0 0 20 20">
|
||||
<path
|
||||
d="M10 0a10 10 0 00-3.16 19.49c.5.1.68-.22.68-.48l-.01-1.7c-2.78.6-3.37-1.34-3.37-1.34-.46-1.16-1.11-1.47-1.11-1.47-.9-.62.07-.6.07-.6 1 .07 1.53 1.03 1.53 1.03.9 1.52 2.34 1.08 2.91.83.1-.65.35-1.09.63-1.34-2.22-.25-4.55-1.11-4.55-4.94 0-1.1.39-1.99 1.03-2.69a3.6 3.6 0 01.1-2.64s.84-.27 2.75 1.02a9.58 9.58 0 015 0c1.91-1.3 2.75-1.02 2.75-1.02.55 1.37.2 2.4.1 2.64.64.7 1.03 1.6 1.03 2.69 0 3.84-2.34 4.68-4.57 4.93.36.31.68.92.68 1.85l-.01 2.75c0 .26.18.58.69.48A10 10 0 0010 0"
|
||||
/>
|
||||
</svg>
|
||||
Sponsor Vue Select!
|
||||
</a>
|
||||
<a href="https://twitter.com/sagalbot" target="_blank" class="social-link">
|
||||
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M23.954 4.569a10 10 0 01-2.825.775 4.958 4.958 0 002.163-2.723c-.951.555-2.005.959-3.127 1.184a4.92 4.92 0 00-8.384 4.482C7.691 8.094 4.066 6.13 1.64 3.161a4.822 4.822 0 00-.666 2.475c0 1.71.87 3.213 2.188 4.096a4.904 4.904 0 01-2.228-.616v.061a4.923 4.923 0 003.946 4.827 4.996 4.996 0 01-2.212.085 4.937 4.937 0 004.604 3.417 9.868 9.868 0 01-6.102 2.105c-.39 0-.779-.023-1.17-.067a13.995 13.995 0 007.557 2.209c9.054 0 13.999-7.496 13.999-13.986 0-.209 0-.42-.015-.63a9.936 9.936 0 002.46-2.548l-.047-.02z"
|
||||
/>
|
||||
</svg>
|
||||
Follow @sagalbot
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.sponsor-me {
|
||||
display: flex;
|
||||
border: 2px solid #c3dafe;
|
||||
background: #ebf4ff;
|
||||
border-radius: 10px;
|
||||
/*align-items: top;*/
|
||||
padding: 2rem 1rem;
|
||||
margin: 3rem 0;
|
||||
flex-direction: column;
|
||||
}
|
||||
.avatar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-evenly;
|
||||
padding: 1rem;
|
||||
}
|
||||
.cta {
|
||||
/*text-align: center;*/
|
||||
}
|
||||
@media (min-width: 1150px) {
|
||||
.sponsor-me {
|
||||
flex-direction: row;
|
||||
}
|
||||
.avatar {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
flex-direction: column;
|
||||
margin: 0 2rem;
|
||||
}
|
||||
.cta {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
p {
|
||||
margin-top: 0;
|
||||
}
|
||||
.avatar img {
|
||||
max-width: 150px;
|
||||
border-radius: 100%;
|
||||
}
|
||||
.button {
|
||||
display: inline-flex;
|
||||
text-align: center;
|
||||
align-items: center;
|
||||
padding: 0.75rem 1rem;
|
||||
background: #63b3ed;
|
||||
color: #fff;
|
||||
font-weight: 600;
|
||||
border-radius: 5px;
|
||||
margin-top: 0.5rem;
|
||||
transition: background-color 0.25s, box-shadow 0.25s;
|
||||
}
|
||||
.button svg {
|
||||
max-width: 25px;
|
||||
fill: currentColor;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
a.button:hover {
|
||||
box-shadow: inset 0px 0px 3px #3182ce;
|
||||
background: #90cdf4;
|
||||
text-decoration: none;
|
||||
text-shadow: 0 1px 1px #63b3ed;
|
||||
}
|
||||
.links {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
.links a {
|
||||
margin: 1rem;
|
||||
}
|
||||
@media (min-width: 1150px) {
|
||||
.links {
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.links a {
|
||||
margin: 0 2rem 0 0;
|
||||
}
|
||||
}
|
||||
.social-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #3182ce;
|
||||
}
|
||||
.social-link svg {
|
||||
fill: currentColor;
|
||||
width: 20px;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
.social-link:hover {
|
||||
color: #2c5282;
|
||||
text-decoration: none;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,56 @@
|
||||
<template>
|
||||
<ul>
|
||||
<li v-for="{ createdAt, login, avatarUrl } in sponsors">
|
||||
<img :src="avatarUrl + '&s=150'" :alt="`@${login}'s avatar`" />
|
||||
<p>
|
||||
<a :href="`https://github.com/${login}`">@{{ login }}</a> <br />
|
||||
Sponsor since {{ createdAt }}
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { SPONSORS } from "@dynamic/constants";
|
||||
import { format } from "date-fns";
|
||||
|
||||
export default {
|
||||
data: () => ({
|
||||
sponsors: SPONSORS.map(({ createdAt, sponsorEntity }) => ({
|
||||
createdAt: format(new Date(createdAt), "LLL yyyy"),
|
||||
...sponsorEntity
|
||||
}))
|
||||
}),
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
max-width: 100%;
|
||||
margin-top: 2rem;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
}
|
||||
img {
|
||||
width: 75px;
|
||||
height: 75px;
|
||||
margin-right: 1rem;
|
||||
border-radius: 100%;
|
||||
}
|
||||
li {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
margin-bottom: 2rem;
|
||||
/*max-width: 220px;*/
|
||||
}
|
||||
a {
|
||||
display: inline-block;
|
||||
max-width: 150px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,4 @@
|
||||
<template>
|
||||
<!-- tag on 188/comma & 13/return -->
|
||||
<v-select no-drop taggable multiple :select-on-key-codes="[188, 13]" />
|
||||
</template>
|
||||
@@ -0,0 +1,16 @@
|
||||
<template>
|
||||
<v-select
|
||||
placeholder="Choose a book to read"
|
||||
label="title"
|
||||
:options="books"
|
||||
:selectable="option => ! option.author.lastName.includes('Woodhouse')"
|
||||
/>
|
||||
</template>
|
||||
<script>
|
||||
import books from '../data/books.js';
|
||||
export default {
|
||||
computed: {
|
||||
books: () => books,
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,51 @@
|
||||
<template>
|
||||
<form @submit.stop="onSubmit">
|
||||
<v-select :options="books" label="title" v-model="selected">
|
||||
<template #search="{attributes, events}">
|
||||
<input
|
||||
:required="!selected"
|
||||
class="vs__search"
|
||||
v-bind="attributes"
|
||||
v-on="events"
|
||||
/>
|
||||
</template>
|
||||
</v-select>
|
||||
|
||||
<input type="submit">
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import books from '../data/books.js'
|
||||
export default {
|
||||
data: () => ({
|
||||
books,
|
||||
selected: null,
|
||||
}),
|
||||
methods: {
|
||||
onSubmit() {
|
||||
alert('Submitted!');
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
form {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.v-select {
|
||||
width: 75%;
|
||||
}
|
||||
|
||||
input[type="submit"] {
|
||||
margin-left: 1rem;
|
||||
background: #44ae7d;
|
||||
border: none;
|
||||
border-radius: 3px;
|
||||
color: #fff;
|
||||
width: 20%;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user