chore(SelectMenu): handle multiple default display + specific placeholder

This commit is contained in:
Benjamin Canac
2023-05-29 11:52:02 +02:00
parent 360084af7c
commit cb43548305
7 changed files with 56 additions and 19 deletions

View File

@@ -6,10 +6,10 @@ const selected = ref(people[3])
<template>
<USelectMenu v-slot="{ open }" v-model="selected" :options="people">
<UButton>
<UButton color="gray">
{{ selected }}
<UIcon name="i-heroicons-chevron-right-20-solid" class="w-5 h-5 transition-transform" :class="[open && 'transform rotate-90']" />
<UIcon name="i-heroicons-chevron-right-20-solid" class="w-5 h-5 transition-transform text-gray-400 dark:text-gray-500" :class="[open && 'transform rotate-90']" />
</UButton>
</USelectMenu>
</template>

View File

@@ -5,10 +5,5 @@ const selected = ref([])
</script>
<template>
<USelectMenu v-model="selected" :options="people" multiple>
<template #label>
<span v-if="selected.length" class="font-medium truncate">{{ selected.join(', ') }}</span>
<span v-else class="block truncate text-gray-400 dark:text-gray-500">Select people</span>
</template>
</USelectMenu>
<USelectMenu v-model="selected" :options="people" multiple placeholder="Select people" />
</template>

View File

@@ -0,0 +1,14 @@
<script setup>
const people = ['Wade Cooper', 'Arlene Mccoy', 'Devon Webb', 'Tom Cook', 'Tanya Fox', 'Hellen Schmidt', 'Caroline Schultz', 'Mason Heaney', 'Claudie Smitham', 'Emil Schaefer']
const selected = ref([])
</script>
<template>
<USelectMenu v-model="selected" :options="people" multiple>
<template #label>
<span v-if="selected.length" class="truncate">{{ selected.join(', ') }}</span>
<span v-else>Select people</span>
</template>
</USelectMenu>
</template>

View File

@@ -10,6 +10,8 @@ headlessui:
The SelectMenu component renders by default a [Select](/forms/select) component and is based on the `ui.select` preset. You can use most of the Select props to configure the display if you don't want to override the default slot such as [color](/forms/select#style), [variant](/forms/select#style), [size](/forms/select#size), [placeholder](/forms/select#placeholder), [icon](/forms/select#icon), [disabled](/forms/select#disabled), etc.
### Options
Like the Select component, you can use the `options` prop to pass an array of strings or objects.
::component-example
@@ -30,7 +32,9 @@ const selected = ref(people[0])
```
::
You can use the `multiple` prop to select multiple values but you have to override the `#label` slot and handle the display yourself.
### Multiple
You can use the `multiple` prop to select multiple values.
::component-example
#default
@@ -39,7 +43,29 @@ You can use the `multiple` prop to select multiple values but you have to overri
#code
```vue
<script setup>
const people = ['Wade Cooper', 'Arlene Mccoy', 'Devon Webb', 'Tom Cook', 'Tanya Fox', 'Hellen Schmidt', 'Caroline Schultz', 'Mason Heaney', 'Claudie Smitham', 'Emil Schaefer']
const people = [...]
const selected = ref([])
</script>
<template>
<USelectMenu v-model="selected" :options="people" multiple placeholder="Select people" />
</template>
```
::
### Slots
You can override the `#label` slot and handle the display yourself.
::component-example
#default
:select-menu-example-multiple-slot{class="max-w-[12rem] w-full"}
#code
```vue
<script setup>
const people = [...]
const selected = ref([])
</script>
@@ -47,15 +73,15 @@ const selected = ref([])
<template>
<USelectMenu v-model="selected" :options="people" multiple>
<template #label>
<span v-if="selected.length" class="font-medium truncate">{{ selected.join(', ') }}</span>
<span v-else class="block truncate text-gray-400 dark:text-gray-500">Select people</span>
<span v-if="selected.length" class="truncate">{{ selected.join(', ') }}</span>
<span v-else>Select people</span>
</template>
</USelectMenu>
</template>
```
::
You can also override the default slot entirely.
You can also override the `#default` slot entirely.
::component-example
#default
@@ -64,14 +90,14 @@ You can also override the default slot entirely.
#code
```vue
<script setup>
const people = ['Wade Cooper', 'Arlene Mccoy', 'Devon Webb', 'Tom Cook', 'Tanya Fox', 'Hellen Schmidt', 'Caroline Schultz', 'Mason Heaney', 'Claudie Smitham', 'Emil Schaefer']
const people = [...]
const selected = ref(people[3])
</script>
<template>
<USelectMenu v-slot="{ open }" v-model="selected" :options="people">
<UButton>
<UButton color="gray">
{{ selected }}
<UIcon name="i-heroicons-chevron-right-20-solid" class="w-5 h-5 transition-transform" :class="[open && 'transform rotate-90']" />
@@ -81,6 +107,8 @@ const selected = ref(people[3])
```
::
### Objects
You can pass an array of objects to `options` and either compare on the whole object or use the `by` prop to compare on a specific key. You can configure which field will be used to display the label through the `option-attribute` prop that defaults to `label`.
::component-example

View File

@@ -345,6 +345,7 @@ const textarea = {
const select = {
...input,
placeholder: 'text-gray-900 dark:text-white',
default: {
size: 'sm',
color: 'white',

View File

@@ -207,7 +207,6 @@ export default defineComponent({
return classNames(
ui.value.base,
ui.value.rounded,
ui.value.placeholder,
ui.value.size[props.size],
props.padded && ui.value.padding[props.size],
variant?.replaceAll('{color}', props.color),

View File

@@ -34,8 +34,9 @@
</span>
<slot name="label">
<span v-if="modelValue" class="block truncate">{{ typeof modelValue === 'string' ? modelValue : modelValue[optionAttribute] }}</span>
<span v-else class="block truncate text-gray-400 dark:text-gray-500">{{ placeholder || '&nbsp;' }}</span>
<span v-if="multiple && Array.isArray(modelValue) && modelValue.length" class="block truncate">{{ modelValue.length }} selected</span>
<span v-else-if="!multiple && modelValue" class="block truncate">{{ typeof modelValue === 'string' ? modelValue : modelValue[optionAttribute] }}</span>
<span v-else class="block truncate" :class="ui.placeholder">{{ placeholder || '&nbsp;' }}</span>
</slot>
<span v-if="trailingIcon" :class="trailingIconClass">
@@ -268,7 +269,6 @@ export default defineComponent({
return classNames(
uiSelect.value.base,
uiSelect.value.rounded,
uiSelect.value.placeholder,
'text-left cursor-default',
uiSelect.value.size[props.size],
uiSelect.value.gap[props.size],