Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enh(NcSelect): Add visible input label #4963

Merged
merged 5 commits into from
Jan 3, 2024
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
3 changes: 0 additions & 3 deletions l10n/messages.pot
Original file line number Diff line number Diff line change
Expand Up @@ -269,9 +269,6 @@ msgstr ""
msgid "Search emoji"
msgstr ""

msgid "Search for options"
msgstr ""

msgid "Search for time zone"
msgstr ""

Expand Down
117 changes: 62 additions & 55 deletions src/components/NcSelect/NcSelect.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,27 +30,19 @@ General purpose multiselect component.
```vue
<template>
<div class="grid">
<div v-for="{ name, props } in selectArray"
<div v-for="{ props } in selectArray"
class="container">
<label :for="props.inputId">{{ name }}</label>
<NcSelect v-bind="props"
v-model="props.value" />
</div>
</div>
</template>

<script>
import GenRandomId from '../../utils/GenRandomId.js'

const getRandomId = () => {
return `select-${GenRandomId()}`
}

const selectArray = [
{
name: 'Simple',
props: {
inputId: getRandomId(),
inputLabel: 'Simple',
options: [
'foo',
'bar',
Expand All @@ -62,9 +54,8 @@ const selectArray = [
},

{
name: 'Simple (top placement)',
props: {
inputId: getRandomId(),
inputLabel: 'Simple (top placement)',
placement: 'top',
options: [
'foo',
Expand All @@ -77,9 +68,8 @@ const selectArray = [
},

{
name: 'Multiple (with placeholder)',
props: {
inputId: getRandomId(),
inputLabel: 'Multiple (with placeholder)',
multiple: true,
placeholder: 'Select multiple options',
options: [
Expand All @@ -93,9 +83,8 @@ const selectArray = [
},

{
name: 'Multiple (objects, pre-selected, stay open on select)',
props: {
inputId: getRandomId(),
inputLabel: 'Multiple (objects, pre-selected, stay open on select)',
multiple: true,
closeOnSelect: false,
options: [
Expand Down Expand Up @@ -187,13 +176,11 @@ parent container is limited to `350px`
<template>
<div class="grid">
<div class="container">
<label :for="data1.props.inputId">{{ data1.name }}</label>
<NcSelect :no-wrap="false"
v-bind="data1.props"
v-model="data1.props.value" />
</div>
<div class="container">
<label :for="data2.props.inputId">{{ data2.name }}</label>
<NcSelect :no-wrap="true"
v-bind="data2.props"
v-model="data2.props.value" />
Expand All @@ -202,16 +189,9 @@ parent container is limited to `350px`
</template>

<script>
import GenRandomId from '../../utils/GenRandomId.js'

const getRandomId = () => {
return `select-${GenRandomId()}`
}

const data1 = {
name: 'Wrapped (Default)',
props: {
inputId: getRandomId(),
inputLabel: 'Wrapped (Default)',
multiple: true,
closeOnSelect: false,
options: [
Expand Down Expand Up @@ -242,9 +222,8 @@ const data1 = {
}

const data2 = {
name: 'Not wrapped',
props: {
inputId: getRandomId(),
inputLabel: 'Not wrapped',
multiple: true,
closeOnSelect: false,
options: [
Expand Down Expand Up @@ -305,9 +284,8 @@ export default {
```vue
<template>
<div class="grid">
<div v-for="{ name, props } in selectArray"
<div v-for="{ props } in selectArray"
class="container">
<label :for="props.inputId">{{ name }}</label>
<NcSelect v-bind="props"
v-model="props.value" />
</div>
Expand All @@ -318,17 +296,10 @@ export default {
import AccountGroup from '@mdi/svg/svg/account-group.svg?raw'
import Email from '@mdi/svg/svg/email.svg?raw'

import GenRandomId from '../../utils/GenRandomId.js'

const getRandomId = () => {
return `select-${GenRandomId()}`
}

const selectArray = [
{
name: 'User select',
props: {
inputId: getRandomId(),
inputLabel: 'User select',
userSelect: true,
options: [
{
Expand Down Expand Up @@ -394,9 +365,8 @@ const selectArray = [
},

{
name: 'Multiple user select (stay open on select)',
props: {
inputId: getRandomId(),
inputLabel: 'Multiple user select (stay open on select)',
userSelect: true,
multiple: true,
closeOnSelect: false,
Expand Down Expand Up @@ -491,6 +461,12 @@ export default {
v-bind="propsToForward"
v-on="$listeners"
@search="searchString => search = searchString">
<template v-if="!labelOutside && inputLabel" #header>
<label :for="inputId"
class="select__label">
{{ inputLabel }}
</label>
</template>
<template #search="{ attributes, events }">
<input :class="['vs__search', inputClass]"
v-bind="attributes"
Expand Down Expand Up @@ -538,6 +514,7 @@ export default {
<script>
import '@nextcloud/vue-select/dist/vue-select.css'

import Vue from 'vue'
import { VueSelect } from '@nextcloud/vue-select'
import {
autoUpdate,
Expand Down Expand Up @@ -572,6 +549,7 @@ export default {
props: {
// Add VueSelect props to $props
...VueSelect.props,
...VueSelect.mixins.reduce((allProps, mixin) => ({ ...allProps, ...mixin.props }), {}),

/**
* `aria-label` for the clear input button
Expand All @@ -583,10 +561,12 @@ export default {

/**
* `aria-label` for the search input
*
* A descriptive `inputLabel` is preferred as this is not visible.
*/
ariaLabelCombobox: {
type: String,
default: t('Search for options'),
default: null,
},

/**
Expand Down Expand Up @@ -719,14 +699,30 @@ export default {

/**
* Input element id
*
* @see https://vue-select.org/api/props.html#inputid
*/
inputId: {
type: String,
default: () => `select-input-${GenRandomId()}`,
},

/**
* Visible label for the input element
*
* @todo Set default for @nextcloud/vue 9
*/
inputLabel: {
type: String,
default: null,
},

/**
* Pass true if you are using an external label
*/
labelOutside: {
type: Boolean,
default: false,
},

/**
* Display a visible border around dropdown options
* which have keyboard focus
Expand Down Expand Up @@ -1005,27 +1001,34 @@ export default {
},

propsToForward() {
const {
// Props handled by this component
inputClass,
noWrap,
placement,
userSelect,
// Props to forward
...initialPropsToForward
} = this.$props

const vueSelectKeys = [
...Object.keys(VueSelect.props),
...VueSelect.mixins.flatMap(mixin => Object.keys(mixin.props ?? {})),
Pytal marked this conversation as resolved.
Show resolved Hide resolved
]
const initialPropsToForward = Object.fromEntries(
Object.entries(this.$props)
.filter(([key, _value]) => vueSelectKeys.includes(key)),
)
const propsToForward = {
...initialPropsToForward,
// Custom overrides of vue-select props
calculatePosition: this.localCalculatePosition,
filterBy: this.localFilterBy,
label: this.localLabel,
}

return propsToForward
},
},

mounted() {
if (!this.labelOutside && !this.inputLabel && !this.ariaLabelCombobox) {
Vue.util.warn('[NcSelect] An `inputLabel` or `ariaLabelCombobox` should be set.')
}
Pytal marked this conversation as resolved.
Show resolved Hide resolved
if (this.inputLabel && this.ariaLabelCombobox) {
Vue.util.warn('[NcSelect] Only one of `inputLabel` or `ariaLabelCombobox` should to be set.')
}
},

methods: {
t,
},
Expand Down Expand Up @@ -1106,6 +1109,11 @@ body {
min-width: 260px;
margin: 0;

.select__label {
display: block;
margin-bottom: 2px;
}

.vs__selected {
height: 32px;
padding: 0 8px 0 12px;
Expand Down Expand Up @@ -1233,5 +1241,4 @@ body {
.user-select .vs__selected {
padding: 0 2px !important;
}

</style>
8 changes: 4 additions & 4 deletions src/components/NcSelectTags/NcSelectTags.vue
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
```vue
<template>
<div class="wrapper">
<NcSelectTags v-model="value" :multiple="false" />
<NcSelectTags v-model="value" input-label="Tag" :multiple="false" />
{{ value }}
</div>
</template>
Expand All @@ -47,7 +47,7 @@ export default {
```vue
<template>
<div class="wrapper">
<NcSelectTags v-model="value" :multiple="true" />
<NcSelectTags v-model="value" input-label="Tags" :multiple="true" />
{{ value }}
</div>
</template>
Expand All @@ -71,7 +71,7 @@ Because of compatibility reasons only 5 tag entries are shown by default. If you
```vue
<template>
<div class="wrapper">
<NcSelectTags v-model="value" :limit="null" />
<NcSelectTags v-model="value" input-label="Tags" :limit="null" />
{{ value }}
</div>
</template>
Expand All @@ -94,7 +94,7 @@ It's also possible to apply any custom filter logic by setting the `optionsFilte
```vue
<template>
<div class="wrapper">
<NcSelectTags v-model="value" :options-filter="customFilter" />
<NcSelectTags v-model="value" input-label="Tags" :options-filter="customFilter" />
{{ value }}
</div>
</template>
Expand Down
Loading