Skip to content
This repository has been archived by the owner on Jan 3, 2024. It is now read-only.

Add label to OcSelect (port to master) #1633

Merged
merged 3 commits into from
Sep 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions changelog/unreleased/change-ocselect-label
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Change: Label for OcSelect

We've added a configurable `<label>` for OcSelect accessible via the `label` property.
This shadows the `label` property of `vue-select`. Hence we introduced the `optionLabel`
property on OcSelect which maps to the `label` property of `vue-select`.

https://github.com/owncloud/owncloud-design-system/pull/1633
https://github.com/owncloud/owncloud-design-system/pull/1570
https://github.com/owncloud/owncloud-design-system/issues/1503
141 changes: 117 additions & 24 deletions src/components/OcSelect.vue
Original file line number Diff line number Diff line change
@@ -1,27 +1,31 @@
<template>
<vue-select
ref="select"
:disabled="disabled"
:filter="filter"
class="oc-select"
v-bind="$attrs"
v-on="$listeners"
>
<template #search="{ attributes, events }">
<input class="vs__search" v-bind="attributes" @input="userInput" v-on="events" />
</template>
<template v-for="(index, name) in $scopedSlots" #[name]="data">
<slot v-if="name !== 'search'" :name="name" v-bind="data" />
</template>
<div slot="no-options" v-translate>No options available.</div>
<template #spinner="{ loading }">
<oc-spinner v-if="loading" />
</template>
</vue-select>
<div>
<label :for="id" v-text="label" />
<vue-select
ref="select"
:disabled="disabled"
:filter="filter"
class="oc-select"
v-bind="additionalAttributes"
v-on="$listeners"
>
<template #search="{ attributes, events }">
<input class="vs__search" v-bind="attributes" @input="userInput" v-on="events" />
</template>
<template v-for="(index, name) in $scopedSlots" #[name]="data">
<slot v-if="name !== 'search'" :name="name" v-bind="data" />
</template>
<div slot="no-options" v-translate>No options available.</div>
<template #spinner="{ loading }">
<oc-spinner v-if="loading" />
</template>
</vue-select>
</div>
</template>

<script>
import Fuse from "fuse.js"
import uniqueId from "../utils/uniqueId"
import VueSelect from "vue-select"
import "vue-select/dist/vue-select.css"

Expand All @@ -38,6 +42,17 @@ export default {
inheritAttrs: true,

props: {
/**
* The ID of the element.
*/
id: {
type: String,
required: false,
default: () => uniqueId("oc-select-"),
},
/**
* Function to filter items when searching
*/
filter: {
type: Function,
required: false,
Expand All @@ -59,11 +74,41 @@ export default {
return search.length ? fuse.search(search).map(({ item }) => item) : fuse.list
},
},
/**
* Disable the select component
*/
disabled: {
type: Boolean,
required: false,
default: false,
},
/**
* Label of the select component
* ATTENTION: this shadows the vue-select prop `label`. If you need access to that use `optionLabel`.
*/
label: {
type: String,
default: null,
},
/**
* Key to use as label when option is an object
* NOTE: this maps to the vue-select prop `label`
*/
optionLabel: {
type: String,
default: null,
},
},

computed: {
additionalAttributes() {
const additionalAttrs = {}
additionalAttrs["input-id"] = this.id
if (this.optionLabel) {
additionalAttrs["label"] = this.optionLabel
}
return { ...this.$attrs, ...additionalAttrs }
kulmann marked this conversation as resolved.
Show resolved Hide resolved
},
},

mounted() {
Expand Down Expand Up @@ -164,7 +209,7 @@ For detailed documentation (props, slots, events, etc.), please visit https://vu
```js
<template>
<div class="oc-docs-width-medium">
<oc-select v-model="selected" :options="['Bannana', 'Orange', 'Pear']" />
<oc-select label="Custom label" v-model="selected" :options="['Bannana', 'Orange', 'Pear']" />
</div>
</template>
<script>
Expand Down Expand Up @@ -236,16 +281,64 @@ To prevent user from filtering options by typing a serach query into the `oc-sel
</script>
```

### Use objects as options
If we want to select from a list of option objects, we can use `option-label` to select the key of the object to use as label.

```js
<template>
<div class="oc-docs-width-medium">
<oc-select
label="Custom Label"
option-label="title"
:options="options"
v-model="selected"
class="oc-mb-m"
/>
</div>
</template>
<script>
const options = [
{
title: 'Apple',
desc: 'An apple is an edible fruit produced by an apple tree (Malus domestica)'
},
{
title: 'Bannana',
desc: 'Bannana is a genus of goblin spiders (family Oonopidae) native to Xishuangbanna prefecture, Yunnan Province, China, where it lives in the leaf-litter of tropical rainforest'
},
{
title: 'Orange',
desc: 'The orange is the fruit of various citrus species in the family Rutaceae'
},
]

export default {
data: () => ({
selected: options[1],
options
})
}
</script>
```




### Using slots to display complex options
Sometimes we need to display more complex options. This can include e.g. an option with a title and a description. To
still display all those values exactly as we want to, we need to use scoped slot called `option`.
We can then retrieve all the values that we want to display from the slots parametres. It is important to specify the
`label` prop on the `oc-select` component which will specify which key should be used as the option label.
still display all those values exactly as we want to, we need to use scoped slots called `option` and `selected-option`.
We can then retrieve all the values that we want to display from the slot parameters.
It is important to specify the `option-label` prop on the `oc-select` to make filtering work.

```js
<template>
<div class="oc-docs-width-medium">
<oc-select v-model="selected" :options="options" label="title" class="oc-mb-m">
<oc-select
label="Custom Label"
:options="options"
v-model="selected"
class="oc-mb-m"
>
<template v-slot:option="{ title, desc }">
<span class="option">
<strong v-text="title" />
Expand Down