Skip to content

Commit

Permalink
feat: add label slot (#270)
Browse files Browse the repository at this point in the history
* feat: add label slot

* Update docs/api-reference.md

* Update docs/api-reference.md

* return emptyModelValue if nothing is selected

* lint

* only expose selected

Co-authored-by: Ernest <iendeavor.github.io@gmail.com>
  • Loading branch information
schelmo and Ernest authored Aug 5, 2021
1 parent d4793be commit c9d57c3
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 10 deletions.
46 changes: 46 additions & 0 deletions cypress/integration/slots/label/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<link
type="text/css"
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css"
/>
<link type="text/css" rel="stylesheet" href="/dist/index.css" />
<script src="https://unpkg.com/vue@next/dist/vue.global.prod.js"></script>
</head>

<body>
<div id="app"></div>
<script src="/dist/vue-next-select.iife.js"></script>
<script>
const { ref, createApp } = Vue
const app = createApp({
name: 'app',
setup() {
const selectedOptions = ref()
const options = ref(['i'])
return {
selectedOptions,
options,
}
},
template: `
<vue-select
v-model="selectedOptions"
:options="options"
>
<template #label="{ selected }">
<span v-if="selected">{{ selected.toUpperCase() }}</span>
<span v-else>Select option</span>
</template>
</vue-select>
`,
})

app.component('vue-select', VueNextSelect)
app.mount(document.querySelector('#app'))
</script>
</body>
</html>
22 changes: 22 additions & 0 deletions cypress/integration/slots/label/index.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/// <reference types="cypress" />
import path from 'path'

context('label', () => {
it('should show the placeholder then the selected', () => {
cy.visit(path.join(__dirname, 'index.html'))
cy.get('.vue-input').should('have.text', 'Select option')
cy.get('.vue-select').click()
cy.get('.vue-dropdown').children().first().click()
cy.get('.vue-input').should('have.text', 'I')
})

it('should show the selected options count', () => {
cy.visit(path.join(__dirname, 'multiple.html'))
cy.get('.vue-input').should('have.text', 'Select option')
cy.get('.vue-select').click()
cy.get('.vue-dropdown').children().first().click()
cy.get('.vue-input').should('have.text', '1')
cy.get('.vue-dropdown').children().first().next().click()
cy.get('.vue-input').should('have.text', '2')
})
})
47 changes: 47 additions & 0 deletions cypress/integration/slots/label/multiple.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<link
type="text/css"
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css"
/>
<link type="text/css" rel="stylesheet" href="/dist/index.css" />
<script src="https://unpkg.com/vue@next/dist/vue.global.prod.js"></script>
</head>

<body>
<div id="app"></div>
<script src="/dist/vue-next-select.iife.js"></script>
<script>
const { ref, createApp } = Vue
const app = createApp({
name: 'app',
setup() {
const selectedOptions = ref([])
const options = ref(['i', 'j', 'k'])
return {
selectedOptions,
options,
}
},
template: `
<vue-select
v-model="selectedOptions"
:options="options"
multiple
>
<template #label="{ selected }">
<span v-if="selected.length">{{ selected.length }}</span>
<span v-else>Select option</span>
</template>
</vue-select>
`,
})

app.component('vue-select', VueNextSelect)
app.mount(document.querySelector('#app'))
</script>
</body>
</html>
8 changes: 8 additions & 0 deletions docs/api-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,14 @@ New in `2.6.0+`

- `{OptionType}` option

### label

New in `v2.9.0+`

- **Attributes**:

- `{(OptionType | EmptyModelValueType) | (OptionType | EmptyModelValueType)[]}` selected

### tag

- **Attributes**:
Expand Down
6 changes: 6 additions & 0 deletions examples/src/views/CustomDropdown.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@
<pre>modelValue: {{ JSON.stringify(country) }}</pre>

<vue-select v-model="country" :options="countryOptions" label-by="label">
<template #label="{ selected }">
<template v-if="selected">
<div>{{ selected.flag }} {{ selected.label }}</div>
</template>
<template v-else>Select option</template>
</template>
<template #dropdown-item="{ option }">
<div>{{ option.flag }} {{ option.label }}</div>
</template>
Expand Down
2 changes: 1 addition & 1 deletion src/components/input.vue
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export default {
props: {
autocomplete: {
required: false,
type: String
type: String,
},
modelValue: {
required: true,
Expand Down
29 changes: 20 additions & 9 deletions src/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@
v-if="(multiple && taggable && modelValue.length === 0) || (searchable === false && taggable === false)"
>
<div class="vue-input">
<input :placeholder="innerPlaceholder" :autocomplete="autocomplete" readonly @click="focus" />
<slot name="label" :selected="selected">
<input :placeholder="innerPlaceholder" :autocomplete="autocomplete" readonly @click="focus" />
</slot>
</div>
</template>

Expand Down Expand Up @@ -234,7 +236,7 @@ const VueSelect = {
// misc
autocomplete: {
default: "off",
default: 'off',
type: String,
},
disabled: {
Expand Down Expand Up @@ -689,26 +691,34 @@ const VueSelect = {
}))
provide('dataAttrs', dataAttrs)
const innerPlaceholder = computed(() => {
const selectedOptions = optionsWithInfo.value.filter(option => option.selected).filter(option => !option.group)
const selectedOptions = computed(() => {
return optionsWithInfo.value.filter(option => option.selected).filter(option => !option.group)
})
const innerPlaceholder = computed(() => {
if (props.multiple) {
if (selectedOptions.length === 0) {
if (selectedOptions.value.length === 0) {
return props.placeholder
} else if (selectedOptions.length === 1) {
} else if (selectedOptions.value.length === 1) {
return '1 option selected'
} else {
return selectedOptions.length + ' options selected'
return selectedOptions.value.length + ' options selected'
}
} else {
if (selectedOptions.length === 0) {
if (selectedOptions.value.length === 0) {
return props.placeholder
} else {
return selectedOptions[0].label + ''
return selectedOptions.value[0].label + ''
}
}
})
const selected = computed(() => {
const selected = selectedOptions.value.map(option => option.originalOption)
if (props.multiple) return selected
return selected[0] || props.emptyModelValue
})
const direction = ref()
watch(
() => [props.openDirection, isFocusing.value],
Expand Down Expand Up @@ -749,6 +759,7 @@ const VueSelect = {
dataAttrs,
innerPlaceholder,
selected,
highlightedOriginalIndex,
pointerForward,
Expand Down

0 comments on commit c9d57c3

Please sign in to comment.