diff --git a/docs/app/components/content/examples/form/FormExampleElements.vue b/docs/app/components/content/examples/form/FormExampleElements.vue index faefa18248..9aa3fe8324 100644 --- a/docs/app/components/content/examples/form/FormExampleElements.vue +++ b/docs/app/components/content/examples/form/FormExampleElements.vue @@ -36,6 +36,12 @@ const schema = z.object({ checkboxGroup: z.any().refine(values => !!values?.find((option: any) => option === 'option-2'), { message: 'Include Option 2' }), + listbox: z.any().refine(option => option?.value === 'option-2', { + message: 'Select Option 2' + }), + listboxMultiple: z.any().refine(values => !!values?.find((option: any) => option.value === 'option-2'), { + message: 'Include Option 2' + }), slider: z.number().max(20, { message: 'Must be less than 20' }), pin: z.string().regex(/^\d$/).array().length(5), file: z.file().min(1).max(1024 * 1024).mime('image/png') @@ -120,6 +126,14 @@ async function onSubmit(event: FormSubmitEvent) { + + + + + + + + diff --git a/docs/app/components/content/examples/listbox/ListboxFilterFieldsExample.vue b/docs/app/components/content/examples/listbox/ListboxFilterFieldsExample.vue new file mode 100644 index 0000000000..357b9a5481 --- /dev/null +++ b/docs/app/components/content/examples/listbox/ListboxFilterFieldsExample.vue @@ -0,0 +1,36 @@ + + + diff --git a/docs/app/components/content/examples/listbox/ListboxIgnoreFilterExample.vue b/docs/app/components/content/examples/listbox/ListboxIgnoreFilterExample.vue new file mode 100644 index 0000000000..54a10f4b99 --- /dev/null +++ b/docs/app/components/content/examples/listbox/ListboxIgnoreFilterExample.vue @@ -0,0 +1,36 @@ + + + diff --git a/docs/app/components/content/examples/listbox/ListboxModelValueExample.vue b/docs/app/components/content/examples/listbox/ListboxModelValueExample.vue new file mode 100644 index 0000000000..fa74e4d135 --- /dev/null +++ b/docs/app/components/content/examples/listbox/ListboxModelValueExample.vue @@ -0,0 +1,22 @@ + + + diff --git a/docs/app/components/content/examples/listbox/ListboxSearchTermExample.vue b/docs/app/components/content/examples/listbox/ListboxSearchTermExample.vue new file mode 100644 index 0000000000..1ca2155dad --- /dev/null +++ b/docs/app/components/content/examples/listbox/ListboxSearchTermExample.vue @@ -0,0 +1,16 @@ + + + diff --git a/docs/app/components/content/examples/listbox/ListboxSelectedIconExample.vue b/docs/app/components/content/examples/listbox/ListboxSelectedIconExample.vue new file mode 100644 index 0000000000..756af0b271 --- /dev/null +++ b/docs/app/components/content/examples/listbox/ListboxSelectedIconExample.vue @@ -0,0 +1,13 @@ + + + diff --git a/docs/app/components/content/examples/listbox/ListboxTransferListExample.vue b/docs/app/components/content/examples/listbox/ListboxTransferListExample.vue new file mode 100644 index 0000000000..da2100248d --- /dev/null +++ b/docs/app/components/content/examples/listbox/ListboxTransferListExample.vue @@ -0,0 +1,75 @@ + + + diff --git a/docs/app/components/content/examples/listbox/ListboxVirtualizeExample.vue b/docs/app/components/content/examples/listbox/ListboxVirtualizeExample.vue new file mode 100644 index 0000000000..6de3ff4aeb --- /dev/null +++ b/docs/app/components/content/examples/listbox/ListboxVirtualizeExample.vue @@ -0,0 +1,21 @@ + + + diff --git a/docs/content/docs/2.components/listbox.md b/docs/content/docs/2.components/listbox.md new file mode 100644 index 0000000000..3557de512c --- /dev/null +++ b/docs/content/docs/2.components/listbox.md @@ -0,0 +1,662 @@ +--- +description: A selectable list of items with search, virtualization and rich item rendering. +category: form +links: + - label: Listbox + icon: i-custom-reka-ui + to: https://reka-ui.com/docs/components/listbox + - label: GitHub + icon: i-simple-icons-github + to: https://github.com/nuxt/ui/blob/v4/src/runtime/components/Listbox.vue +navigation.badge: Soon +--- + +## Usage + +Use the `v-model` directive to control the value of the Listbox or the `default-value` prop to set the initial value when you do not need to control its state. + +::component-code +--- +collapse: true +hide: + - class +ignore: + - modelValue.label + - modelValue.icon + - modelValue.value + - items +external: + - items + - modelValue +externalTypes: + - ListboxItem[] +props: + modelValue: + label: 'France' + icon: 'i-lucide-map-pin' + value: 'FR' + items: + - label: 'France' + icon: 'i-lucide-map-pin' + value: 'FR' + - label: 'Germany' + icon: 'i-lucide-map-pin' + value: 'DE' + - label: 'Italy' + icon: 'i-lucide-map-pin' + value: 'IT' + - label: 'Spain' + icon: 'i-lucide-map-pin' + value: 'ES' + - label: 'Netherlands' + icon: 'i-lucide-map-pin' + value: 'NL' + - label: 'Poland' + icon: 'i-lucide-map-pin' + value: 'PL' + - label: 'Belgium' + icon: 'i-lucide-map-pin' + value: 'BE' + - label: 'Portugal' + icon: 'i-lucide-map-pin' + value: 'PT' + - label: 'Austria' + icon: 'i-lucide-map-pin' + value: 'AT' + - label: 'Sweden' + icon: 'i-lucide-map-pin' + value: 'SE' + class: 'w-full' +--- +:: + +### Items + +Use the `items` prop as an array of objects with the following properties: + +- `label?: string`{lang="ts-type"} +- [`description?: string`{lang="ts-type"}](#with-description-in-items) +- [`type?: "label" | "separator" | "item"`{lang="ts-type"}](#with-items-type) +- [`icon?: string`{lang="ts-type"}](#with-icon-in-items) +- [`avatar?: AvatarProps`{lang="ts-type"}](#with-avatar-in-items) +- [`chip?: ChipProps`{lang="ts-type"}](#with-chip-in-items) +- `disabled?: boolean`{lang="ts-type"} +- `onSelect?: (e: Event) => void`{lang="ts-type"} +- `class?: any`{lang="ts-type"} +- `ui?: { label?: ClassNameValue, separator?: ClassNameValue, item?: ClassNameValue, itemLeadingIcon?: ClassNameValue, ... }`{lang="ts-type"} + +::component-code +--- +collapse: true +hide: + - class +ignore: + - items +external: + - items +externalTypes: + - ListboxItem[] +props: + items: + - label: 'France' + description: 'The Hexagon' + icon: 'i-lucide-map-pin' + value: 'FR' + - label: 'Germany' + description: 'The Federal Republic' + icon: 'i-lucide-map-pin' + value: 'DE' + - label: 'Italy' + description: 'The Boot' + icon: 'i-lucide-map-pin' + value: 'IT' + - label: 'Spain' + description: 'The Bull Skin' + icon: 'i-lucide-map-pin' + value: 'ES' + class: 'w-full' +--- +:: + +You can also pass an array of arrays to the `items` prop to display separated groups of items. + +::component-code +--- +collapse: true +hide: + - class +ignore: + - items +external: + - items +externalTypes: + - ListboxItem[][] +props: + items: + - - label: 'France' + icon: 'i-lucide-map-pin' + value: 'FR' + - label: 'Germany' + icon: 'i-lucide-map-pin' + value: 'DE' + - label: 'Italy' + icon: 'i-lucide-map-pin' + value: 'IT' + - - label: 'Brazil' + icon: 'i-lucide-map-pin' + value: 'BR' + - label: 'Argentina' + icon: 'i-lucide-map-pin' + value: 'AR' + class: 'w-full' +--- +:: + +### Multiple + +Use the `multiple` prop to allow selecting multiple items. When enabled, the `v-model` will be an array. + +::component-code +--- +collapse: true +hide: + - class +ignore: + - items + - multiple +external: + - items +externalTypes: + - ListboxItem[] +props: + multiple: true + items: + - label: 'France' + icon: 'i-lucide-map-pin' + value: 'FR' + - label: 'Germany' + icon: 'i-lucide-map-pin' + value: 'DE' + - label: 'Italy' + icon: 'i-lucide-map-pin' + value: 'IT' + - label: 'Spain' + icon: 'i-lucide-map-pin' + value: 'ES' + class: 'w-full' +--- +:: + +### Value Key + +You can choose to bind a single property of the object rather than the whole object by using the `value-key` prop. Defaults to `undefined`. + +::component-code +--- +collapse: true +ignore: + - modelValue + - valueKey + - items + - class +external: + - items + - modelValue +externalTypes: + - ListboxItem[] +props: + modelValue: 'FR' + valueKey: 'value' + items: + - label: 'France' + icon: 'i-lucide-map-pin' + value: 'FR' + - label: 'Germany' + icon: 'i-lucide-map-pin' + value: 'DE' + - label: 'Italy' + icon: 'i-lucide-map-pin' + value: 'IT' + - label: 'Spain' + icon: 'i-lucide-map-pin' + value: 'ES' + class: 'w-full' +--- +:: + +### Filter + +Use the `filter` prop to display a filter input or pass an object to customize the [Input](/docs/components/input) component. Defaults to `false`. + +::component-code +--- +collapse: true +hide: + - class +ignore: + - items +external: + - items +externalTypes: + - ListboxItem[] +props: + filter: + placeholder: 'Filter...' + icon: 'i-lucide-search' + items: + - label: 'France' + icon: 'i-lucide-map-pin' + value: 'FR' + - label: 'Germany' + icon: 'i-lucide-map-pin' + value: 'DE' + - label: 'Italy' + icon: 'i-lucide-map-pin' + value: 'IT' + - label: 'Spain' + icon: 'i-lucide-map-pin' + value: 'ES' + - label: 'Netherlands' + icon: 'i-lucide-map-pin' + value: 'NL' + - label: 'Poland' + icon: 'i-lucide-map-pin' + value: 'PL' + class: 'w-full' +--- +:: + +### Selected Icon + +Use the `selected-icon` prop to customize the icon when an item is selected. Defaults to `i-lucide-check`. + +::component-code +--- +collapse: true +ignore: + - items + - modelValue + - valueKey + - class +external: + - items + - modelValue +externalTypes: + - ListboxItem[] +props: + modelValue: 'FR' + selectedIcon: 'i-lucide-flame' + valueKey: 'value' + items: + - label: 'France' + icon: 'i-lucide-map-pin' + value: 'FR' + - label: 'Germany' + icon: 'i-lucide-map-pin' + value: 'DE' + - label: 'Italy' + icon: 'i-lucide-map-pin' + value: 'IT' + - label: 'Spain' + icon: 'i-lucide-map-pin' + value: 'ES' + class: 'w-full' +--- +:: + +### Size + +Use the `size` prop to change the size of the Listbox. + +::component-code +--- +collapse: true +hide: + - class +ignore: + - items +external: + - items +externalTypes: + - ListboxItem[] +props: + size: xl + items: + - label: 'France' + icon: 'i-lucide-map-pin' + value: 'FR' + - label: 'Germany' + icon: 'i-lucide-map-pin' + value: 'DE' + - label: 'Italy' + icon: 'i-lucide-map-pin' + value: 'IT' + - label: 'Spain' + icon: 'i-lucide-map-pin' + value: 'ES' + class: 'w-full' +--- +:: + +### Loading + +Use the `loading` prop to display a loading indicator. Use the `loading-icon` prop to customize the icon. + +::component-code +--- +collapse: true +hide: + - class +ignore: + - items +external: + - items +externalTypes: + - ListboxItem[] +props: + loading: true + items: + - label: 'France' + icon: 'i-lucide-map-pin' + value: 'FR' + - label: 'Germany' + icon: 'i-lucide-map-pin' + value: 'DE' + class: 'w-full' +--- +:: + +### Disabled + +Use the `disabled` prop to prevent any user interaction with the Listbox. + +::component-code +--- +collapse: true +hide: + - class +ignore: + - items +external: + - items +externalTypes: + - ListboxItem[] +props: + disabled: true + items: + - label: 'France' + icon: 'i-lucide-map-pin' + value: 'FR' + - label: 'Germany' + icon: 'i-lucide-map-pin' + value: 'DE' + - label: 'Italy' + icon: 'i-lucide-map-pin' + value: 'IT' + - label: 'Spain' + icon: 'i-lucide-map-pin' + value: 'ES' + class: 'w-full' +--- +:: + +## Examples + +### With items type + +You can use the `type` property with `separator` to display a separator between items or `label` to display a label. + +::component-code +--- +collapse: true +hide: + - class +ignore: + - items +external: + - items +externalTypes: + - ListboxItem[][] +props: + items: + - - type: 'label' + label: 'Fruits' + - label: 'Apple' + - label: 'Banana' + - label: 'Blueberry' + - label: 'Grapes' + - label: 'Pineapple' + - - type: 'label' + label: 'Vegetables' + - label: 'Aubergine' + - label: 'Broccoli' + - label: 'Carrot' + - label: 'Courgette' + - label: 'Leek' + class: 'w-full' +--- +:: + +### With icon in items + +You can use the `icon` property to display an [Icon](/docs/components/icon) inside the items. + +::component-code +--- +collapse: true +hide: + - class +ignore: + - items +external: + - items +externalTypes: + - ListboxItem[] +props: + items: + - label: 'Backlog' + icon: 'i-lucide-circle-help' + value: 'backlog' + - label: 'Todo' + icon: 'i-lucide-circle-plus' + value: 'todo' + - label: 'In Progress' + icon: 'i-lucide-circle-arrow-up' + value: 'in_progress' + - label: 'Done' + icon: 'i-lucide-circle-check' + value: 'done' + class: 'w-full' +--- +:: + +### With avatar in items + +You can use the `avatar` property to display an [Avatar](/docs/components/avatar) inside the items. + +::component-code +--- +collapse: true +hide: + - class +ignore: + - items +external: + - items +externalTypes: + - ListboxItem[] +props: + items: + - label: 'benjamincanac' + avatar: + src: 'https://github.com/benjamincanac.png' + - label: 'romhml' + avatar: + src: 'https://github.com/romhml.png' + - label: 'atinux' + avatar: + src: 'https://github.com/atinux.png' + - label: 'HugoRCD' + avatar: + src: 'https://github.com/HugoRCD.png' + class: 'w-full' +--- +:: + +### With chip in items + +You can use the `chip` property to display a [Chip](/docs/components/chip) inside the items. + +::component-code +--- +collapse: true +hide: + - class +ignore: + - items +external: + - items +externalTypes: + - ListboxItem[] +props: + items: + - label: 'bug' + chip: + color: 'error' + - label: 'feature' + chip: + color: 'success' + - label: 'enhancement' + chip: + color: 'info' + class: 'w-full' +--- +:: + +### With description in items + +You can use the `description` property to display additional text below the label. + +::component-code +--- +collapse: true +hide: + - class +ignore: + - items +external: + - items +externalTypes: + - ListboxItem[] +props: + items: + - label: 'France' + description: 'The Hexagon' + icon: 'i-lucide-map-pin' + value: 'FR' + - label: 'Germany' + description: 'The Federal Republic' + icon: 'i-lucide-map-pin' + value: 'DE' + - label: 'Italy' + description: 'The Boot' + icon: 'i-lucide-map-pin' + value: 'IT' + - label: 'Spain' + description: 'The Bull Skin' + icon: 'i-lucide-map-pin' + value: 'ES' + class: 'w-full' +--- +:: + +### Control selected items + +You can control the selected item by using the `default-value` prop or the `v-model` directive. + +::component-example +--- +name: 'listbox-model-value-example' +collapse: true +--- +:: + +### Control search term + +Use the `v-model:search-term` directive to control the search term. + +::component-example +--- +name: 'listbox-search-term-example' +--- +:: + +### With ignore filter + +Set the `ignore-filter` prop to `true` to disable the internal search and use your own search logic. + +::component-example +--- +collapse: true +name: 'listbox-ignore-filter-example' +--- +:: + +::note +This example uses [`refDebounced`](https://vueuse.org/shared/refDebounced/#refdebounced) to debounce the API calls. +:: + +### With filter fields + +Use the `filter-fields` prop with an array of fields to filter on. Defaults to `[labelKey]`. + +::component-example +--- +collapse: true +name: 'listbox-filter-fields-example' +--- +:: + +### With virtualization + +Use the `virtualize` prop to enable virtualization for large lists as a boolean or an object with options like `{ estimateSize: 32, overscan: 12 }`. + +::component-example +--- +name: 'listbox-virtualize-example' +collapse: true +--- +:: + +### As a transfer list + +You can compose two Listbox components with [Button](/docs/components/button) controls to build a transfer list pattern. + +::component-example +--- +name: 'listbox-transfer-list-example' +collapse: true +--- +:: + +## API + +### Props + +:component-props + +### Slots + +:component-slots + +### Emits + +:component-emits + +## Theme + +:component-theme + +## Changelog + +:component-changelog diff --git a/docs/public/components/dark/listbox.png b/docs/public/components/dark/listbox.png new file mode 100644 index 0000000000..dd908ea22e Binary files /dev/null and b/docs/public/components/dark/listbox.png differ diff --git a/docs/public/components/light/listbox.png b/docs/public/components/light/listbox.png new file mode 100644 index 0000000000..89b24c3fc3 Binary files /dev/null and b/docs/public/components/light/listbox.png differ diff --git a/playgrounds/nuxt/app/composables/useNavigation.ts b/playgrounds/nuxt/app/composables/useNavigation.ts index c3bbfcf333..e427a0ee72 100644 --- a/playgrounds/nuxt/app/composables/useNavigation.ts +++ b/playgrounds/nuxt/app/composables/useNavigation.ts @@ -48,6 +48,7 @@ const components = [ 'input', 'kbd', 'link', + 'listbox', 'locale', 'marquee', 'modal', diff --git a/playgrounds/nuxt/app/pages/components/listbox.vue b/playgrounds/nuxt/app/pages/components/listbox.vue new file mode 100644 index 0000000000..1779d1e443 --- /dev/null +++ b/playgrounds/nuxt/app/pages/components/listbox.vue @@ -0,0 +1,58 @@ + + + diff --git a/src/runtime/components/Listbox.vue b/src/runtime/components/Listbox.vue new file mode 100644 index 0000000000..14aa1a2a85 --- /dev/null +++ b/src/runtime/components/Listbox.vue @@ -0,0 +1,397 @@ + + + + + + + diff --git a/src/runtime/locale/ar.ts b/src/runtime/locale/ar.ts index eb7bd6c560..8096c5b41e 100644 --- a/src/runtime/locale/ar.ts +++ b/src/runtime/locale/ar.ts @@ -101,6 +101,11 @@ export default defineLocale({ decrement: 'تقليل', increment: 'زيادة' }, + listbox: { + noData: 'لا توجد بيانات', + noMatch: 'لا توجد نتائج مطابقة', + search: 'بحث…' + }, modal: { close: 'إغلاق' }, diff --git a/src/runtime/locale/az.ts b/src/runtime/locale/az.ts index 246af6e41a..9a7337255a 100644 --- a/src/runtime/locale/az.ts +++ b/src/runtime/locale/az.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'Azalt', increment: 'Artır' }, + listbox: { + noData: 'Məlumat yoxdur', + noMatch: 'Uyğun məlumat tapılmadı', + search: 'Axtar…' + }, modal: { close: 'Bağla' }, diff --git a/src/runtime/locale/be.ts b/src/runtime/locale/be.ts index 1afc0d6153..3f5d3e798f 100644 --- a/src/runtime/locale/be.ts +++ b/src/runtime/locale/be.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'Паменшыць', increment: 'Павялічыць' }, + listbox: { + noData: 'Няма даных', + noMatch: 'Супадзенняў не знойдзена', + search: 'Пошук…' + }, modal: { close: 'Закрыць' }, diff --git a/src/runtime/locale/bg.ts b/src/runtime/locale/bg.ts index f07984bfad..e444e14286 100644 --- a/src/runtime/locale/bg.ts +++ b/src/runtime/locale/bg.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'Намаляване', increment: 'Увеличаване' }, + listbox: { + noData: 'Няма данни', + noMatch: 'Няма съвпадение на данни', + search: 'Потърсете…' + }, modal: { close: 'Затворете' }, diff --git a/src/runtime/locale/bn.ts b/src/runtime/locale/bn.ts index 7f124ae709..b85e3d94c5 100644 --- a/src/runtime/locale/bn.ts +++ b/src/runtime/locale/bn.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'হ্রাস করুন', increment: 'বৃদ্ধি করুন' }, + listbox: { + noData: 'কোন তথ্য নেই', + noMatch: 'কোন মিল পাওয়া যায়নি', + search: 'অনুসন্ধান করুন…' + }, modal: { close: 'বন্ধ করুন' }, diff --git a/src/runtime/locale/ca.ts b/src/runtime/locale/ca.ts index 9fcf96c2c1..715ba57db3 100644 --- a/src/runtime/locale/ca.ts +++ b/src/runtime/locale/ca.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'Decrementar', increment: 'Incrementar' }, + listbox: { + noData: 'Sense dades', + noMatch: 'No hi ha dades coincidents', + search: 'Cerca…' + }, modal: { close: 'Tancar' }, diff --git a/src/runtime/locale/ckb.ts b/src/runtime/locale/ckb.ts index 121566019c..e944365f68 100644 --- a/src/runtime/locale/ckb.ts +++ b/src/runtime/locale/ckb.ts @@ -30,7 +30,7 @@ export default defineLocale({ prev: 'پێشتر' }, chatPrompt: { - placeholder: 'نامەکەت لێرە بنوسە...' + placeholder: 'نامەکەت لێرە بنوسە…' }, chatPromptSubmit: { label: 'ناردن' @@ -101,6 +101,11 @@ export default defineLocale({ decrement: 'کەمکردنەوە', increment: 'زیادکردن' }, + listbox: { + noData: 'هیچ داتایەک نییە', + noMatch: 'هیچ ئەنجامێک نەدۆزرایەوە', + search: 'گەڕان…' + }, modal: { close: 'داخستن' }, diff --git a/src/runtime/locale/cs.ts b/src/runtime/locale/cs.ts index f2e9ce70e5..046b7f14ea 100644 --- a/src/runtime/locale/cs.ts +++ b/src/runtime/locale/cs.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'Snížit', increment: 'Zvýšit' }, + listbox: { + noData: 'Žádná data', + noMatch: 'Žádná shoda', + search: 'Hledat…' + }, modal: { close: 'Zavřít' }, diff --git a/src/runtime/locale/da.ts b/src/runtime/locale/da.ts index 269bf8bc68..369cfc6b4a 100644 --- a/src/runtime/locale/da.ts +++ b/src/runtime/locale/da.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'Reducer', increment: 'Øg' }, + listbox: { + noData: 'Ingen data', + noMatch: 'Ingen matchende data', + search: 'Søg…' + }, modal: { close: 'Luk' }, diff --git a/src/runtime/locale/de.ts b/src/runtime/locale/de.ts index 22e28b1028..acf4c3f91a 100644 --- a/src/runtime/locale/de.ts +++ b/src/runtime/locale/de.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'Verringern', increment: 'Erhöhen' }, + listbox: { + noData: 'Keine Daten', + noMatch: 'Nichts gefunden', + search: 'Suchen…' + }, modal: { close: 'Schließen' }, diff --git a/src/runtime/locale/de_ch.ts b/src/runtime/locale/de_ch.ts index 75edd162f4..78d97cda84 100644 --- a/src/runtime/locale/de_ch.ts +++ b/src/runtime/locale/de_ch.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'Verringern', increment: 'Erhöhen' }, + listbox: { + noData: 'Keine Daten', + noMatch: 'Nichts gefunden', + search: 'Suchen…' + }, modal: { close: 'Schliessen' }, diff --git a/src/runtime/locale/el.ts b/src/runtime/locale/el.ts index 7e17de7c41..d0d5704129 100644 --- a/src/runtime/locale/el.ts +++ b/src/runtime/locale/el.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'Μείωση', increment: 'Αύξηση' }, + listbox: { + noData: 'Δεν υπάρχουν δεδομένα', + noMatch: 'Δεν βρέθηκαν δεδομένα', + search: 'Αναζήτηση…' + }, modal: { close: 'Κλείσιμο' }, diff --git a/src/runtime/locale/en.ts b/src/runtime/locale/en.ts index 7eced47986..64c282bec5 100644 --- a/src/runtime/locale/en.ts +++ b/src/runtime/locale/en.ts @@ -95,6 +95,11 @@ export default defineLocale({ decrement: 'Decrement', increment: 'Increment' }, + listbox: { + noData: 'No data', + noMatch: 'No matching data', + search: 'Search…' + }, modal: { close: 'Close' }, @@ -121,7 +126,7 @@ export default defineLocale({ } }, chatReasoning: { - thinking: 'Thinking...', + thinking: 'Thinking…', thought: 'Thought', thoughtFor: 'Thought for {duration}' }, diff --git a/src/runtime/locale/es.ts b/src/runtime/locale/es.ts index 68ff948774..d699ea64b2 100644 --- a/src/runtime/locale/es.ts +++ b/src/runtime/locale/es.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'Decrementar', increment: 'Incrementar' }, + listbox: { + noData: 'Sin datos', + noMatch: 'No hay datos coincidentes', + search: 'Buscar…' + }, modal: { close: 'Cerrar' }, diff --git a/src/runtime/locale/et.ts b/src/runtime/locale/et.ts index 5eefaa1e89..a9b0145aeb 100644 --- a/src/runtime/locale/et.ts +++ b/src/runtime/locale/et.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'Vähenda', increment: 'Suurenda' }, + listbox: { + noData: 'Pole andmeid', + noMatch: 'Pole vastavaid andmeid', + search: 'Otsi…' + }, modal: { close: 'Sulge' }, diff --git a/src/runtime/locale/eu.ts b/src/runtime/locale/eu.ts index 5b9f090b65..5de431228c 100644 --- a/src/runtime/locale/eu.ts +++ b/src/runtime/locale/eu.ts @@ -29,7 +29,7 @@ export default defineLocale({ prev: 'Aurretikoa' }, chatPrompt: { - placeholder: 'Idatzi zure mezua hemen...' + placeholder: 'Idatzi zure mezua hemen…' }, chatPromptSubmit: { label: 'Bidali' @@ -51,7 +51,7 @@ export default defineLocale({ close: 'Itxi', noData: 'Daturik gabe', noMatch: 'Ez da datu bat ere aurkitu', - placeholder: 'Idatzi komando bat edo bilatu...' + placeholder: 'Idatzi komando bat edo bilatu…' }, contentSearch: { links: 'Estekak', @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'Murriztu', increment: 'Handitu' }, + listbox: { + noData: 'Daturik gabe', + noMatch: 'Ez da datu bat ere aurkitu', + search: 'Bilatu…' + }, modal: { close: 'Itxi' }, diff --git a/src/runtime/locale/fa_ir.ts b/src/runtime/locale/fa_ir.ts index 5a4bf4ae9d..56a5351575 100644 --- a/src/runtime/locale/fa_ir.ts +++ b/src/runtime/locale/fa_ir.ts @@ -101,6 +101,11 @@ export default defineLocale({ decrement: 'کاهش', increment: 'افزایش' }, + listbox: { + noData: 'داده‌ای موجود نیست', + noMatch: 'داده‌ای یافت نشد', + search: 'جستجو…' + }, modal: { close: 'بستن' }, diff --git a/src/runtime/locale/fi.ts b/src/runtime/locale/fi.ts index a256ca61f1..3ba1cc3d24 100644 --- a/src/runtime/locale/fi.ts +++ b/src/runtime/locale/fi.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'Vähennä', increment: 'Kasvata' }, + listbox: { + noData: 'Ei tietoja', + noMatch: 'Ei vastaavia tietoja', + search: 'Hae…' + }, modal: { close: 'Sulje' }, diff --git a/src/runtime/locale/fr.ts b/src/runtime/locale/fr.ts index 18c528fca7..6a15231d99 100644 --- a/src/runtime/locale/fr.ts +++ b/src/runtime/locale/fr.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'Diminuer', increment: 'Augmenter' }, + listbox: { + noData: 'Aucune donnée', + noMatch: 'Aucune donnée correspondante', + search: 'Rechercher…' + }, modal: { close: 'Fermer' }, diff --git a/src/runtime/locale/gl.ts b/src/runtime/locale/gl.ts index cfc9fc1f63..e98585fd7b 100644 --- a/src/runtime/locale/gl.ts +++ b/src/runtime/locale/gl.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'Diminuír', increment: 'Aumentar' }, + listbox: { + noData: 'Sen datos', + noMatch: 'Non hai datos coincidentes', + search: 'Buscar…' + }, modal: { close: 'Pechar' }, diff --git a/src/runtime/locale/he.ts b/src/runtime/locale/he.ts index 70b9622837..a8a2d7943b 100644 --- a/src/runtime/locale/he.ts +++ b/src/runtime/locale/he.ts @@ -101,6 +101,11 @@ export default defineLocale({ decrement: 'הפחת', increment: 'הוסף' }, + listbox: { + noData: 'אין נתונים', + noMatch: 'לא נמצאה התאמה', + search: 'חפש…' + }, modal: { close: 'סגור' }, diff --git a/src/runtime/locale/hi.ts b/src/runtime/locale/hi.ts index 48c739737b..6625c5132b 100644 --- a/src/runtime/locale/hi.ts +++ b/src/runtime/locale/hi.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'घटाना', increment: 'बढ़ाना' }, + listbox: { + noData: 'कोई डेटा नहीं', + noMatch: 'कोई मेल खाता डेटा नहीं', + search: 'खोजें…' + }, modal: { close: 'बंद करें' }, diff --git a/src/runtime/locale/hr.ts b/src/runtime/locale/hr.ts index 4c14647504..2547830962 100644 --- a/src/runtime/locale/hr.ts +++ b/src/runtime/locale/hr.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'Smanji', increment: 'Povećaj' }, + listbox: { + noData: 'Nema podataka', + noMatch: 'Nema odgovarajućih podataka', + search: 'Pretraživanje…' + }, modal: { close: 'Zatvori' }, diff --git a/src/runtime/locale/hu.ts b/src/runtime/locale/hu.ts index 379cec11b6..880e2633e1 100644 --- a/src/runtime/locale/hu.ts +++ b/src/runtime/locale/hu.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'Csökkent', increment: 'Növel' }, + listbox: { + noData: 'Nincs adat', + noMatch: 'Nincs találat', + search: 'Keresés…' + }, modal: { close: 'Bezárás' }, diff --git a/src/runtime/locale/hy.ts b/src/runtime/locale/hy.ts index 948643c8d8..41c5ff0e01 100644 --- a/src/runtime/locale/hy.ts +++ b/src/runtime/locale/hy.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'Պակասեցնել', increment: 'Ավելացնել' }, + listbox: { + noData: 'Տվյալներ չկան', + noMatch: 'Համընկնումներ չեն գտնվել', + search: 'Որոնում…' + }, modal: { close: 'Փակել' }, diff --git a/src/runtime/locale/id.ts b/src/runtime/locale/id.ts index d007dd5890..1bb11c2e7d 100644 --- a/src/runtime/locale/id.ts +++ b/src/runtime/locale/id.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'Kurangi', increment: 'Tambah' }, + listbox: { + noData: 'Tidak ada data', + noMatch: 'Tidak ada data yang cocok', + search: 'Cari…' + }, modal: { close: 'Tutup' }, diff --git a/src/runtime/locale/is.ts b/src/runtime/locale/is.ts index cbff00cb5c..a83415b805 100644 --- a/src/runtime/locale/is.ts +++ b/src/runtime/locale/is.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'Minnka', increment: 'Auka' }, + listbox: { + noData: 'Engin gögn', + noMatch: 'Engin gögn fundust', + search: 'Leita…' + }, modal: { close: 'Loka' }, diff --git a/src/runtime/locale/it.ts b/src/runtime/locale/it.ts index a6ce722282..4923819e5a 100644 --- a/src/runtime/locale/it.ts +++ b/src/runtime/locale/it.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'Diminuisci', increment: 'Aumenta' }, + listbox: { + noData: 'Nessun dato', + noMatch: 'Nessun dato corrispondente', + search: 'Cerca…' + }, modal: { close: 'Chiudi' }, diff --git a/src/runtime/locale/ja.ts b/src/runtime/locale/ja.ts index da0da85ae9..7266cf4575 100644 --- a/src/runtime/locale/ja.ts +++ b/src/runtime/locale/ja.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: '減らす', increment: '増やす' }, + listbox: { + noData: 'データがありません', + noMatch: '一致するデータがありません', + search: '検索…' + }, modal: { close: '閉じる' }, diff --git a/src/runtime/locale/ka.ts b/src/runtime/locale/ka.ts index 5357d4d336..2cf7898cf3 100644 --- a/src/runtime/locale/ka.ts +++ b/src/runtime/locale/ka.ts @@ -102,6 +102,11 @@ export default defineLocale({ decrement: 'დაკლება', increment: 'დამატება' }, + listbox: { + noData: 'მონაცემები არ არის', + noMatch: 'შესატყვისი მონაცემები არ არის', + search: 'ძიება…' + }, modal: { close: 'დახურვა' }, diff --git a/src/runtime/locale/kk.ts b/src/runtime/locale/kk.ts index dec2c31a3d..6e3a51d8df 100644 --- a/src/runtime/locale/kk.ts +++ b/src/runtime/locale/kk.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'Азайту', increment: 'Арттыру' }, + listbox: { + noData: 'Деректер жоқ', + noMatch: 'Сәйкес келетін деректер жоқ', + search: 'Іздеу…' + }, modal: { close: 'Жабу' }, diff --git a/src/runtime/locale/km.ts b/src/runtime/locale/km.ts index 87cdf37232..f58fb8b9c3 100644 --- a/src/runtime/locale/km.ts +++ b/src/runtime/locale/km.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'បន្ថយ', increment: 'បង្កើន' }, + listbox: { + noData: 'មិនមានទិន្នន័យ', + noMatch: 'មិនមានទិន្នន័យដែលត្រូវគ្នាទេ', + search: 'ស្វែងរក…' + }, modal: { close: 'បិទ' }, diff --git a/src/runtime/locale/ko.ts b/src/runtime/locale/ko.ts index b3af0cab49..42a04728b7 100644 --- a/src/runtime/locale/ko.ts +++ b/src/runtime/locale/ko.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: '감소', increment: '증가' }, + listbox: { + noData: '데이터가 없습니다.', + noMatch: '일치하는 데이터가 없습니다.', + search: '검색…' + }, modal: { close: '닫기' }, diff --git a/src/runtime/locale/ky.ts b/src/runtime/locale/ky.ts index 296eb0c67a..83426e147d 100644 --- a/src/runtime/locale/ky.ts +++ b/src/runtime/locale/ky.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'Азайтуу', increment: 'Кошуу' }, + listbox: { + noData: 'Маалымат жок', + noMatch: 'Сүйлөшкөн маалыматтар жок', + search: 'Издөө…' + }, modal: { close: 'Жабуу' }, diff --git a/src/runtime/locale/lb.ts b/src/runtime/locale/lb.ts index ae5c089e93..a7e13b3cbd 100644 --- a/src/runtime/locale/lb.ts +++ b/src/runtime/locale/lb.ts @@ -65,7 +65,7 @@ export default defineLocale({ }, dropdownMenu: { noMatch: 'Keng entspriechend Donnéeën', - search: 'Sichen..' + search: 'Sichen…' }, dashboardSearch: { theme: 'Thema' @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'Dekrementéieren', increment: 'Inkrementéieren' }, + listbox: { + noData: 'Keng Donnéeën', + noMatch: 'Keng entspriechend Donnéeën', + search: 'Sichen…' + }, modal: { close: 'Zoumaachen' }, @@ -133,7 +138,7 @@ export default defineLocale({ create: '"{label}" erstellen', noData: 'Keng Donnéeën', noMatch: 'Keng entspriechend Donnéeën', - search: 'Sichen..' + search: 'Sichen…' }, slideover: { close: 'Zoumaachen' diff --git a/src/runtime/locale/lo.ts b/src/runtime/locale/lo.ts index 4f7d333662..d64fdebf5e 100644 --- a/src/runtime/locale/lo.ts +++ b/src/runtime/locale/lo.ts @@ -29,7 +29,7 @@ export default defineLocale({ prev: 'ກ່ອນໜ້າ' }, chatPrompt: { - placeholder: 'ພິມຂໍ້ຄວາມຂອງທ່ານທີ່ນີ້...' + placeholder: 'ພິມຂໍ້ຄວາມຂອງທ່ານທີ່ນີ້…' }, chatPromptSubmit: { label: 'ສົ່ງຄຳສັ່ງ' @@ -51,27 +51,27 @@ export default defineLocale({ close: 'ປິດ', noData: 'ບໍ່ມີຂໍ້ມູນ', noMatch: 'ບໍ່ພົບຂໍ້ມູນທີ່ກົງກັນ', - placeholder: 'ພິມຄຳສັ່ງ ຫຼື ຄົ້ນຫາ...' + placeholder: 'ພິມຄຳສັ່ງ ຫຼື ຄົ້ນຫາ…' }, contentSearch: { links: 'ລິ້ງ', theme: 'ທີມ' }, contentSearchButton: { - label: 'ຄົ້ນຫາ...' + label: 'ຄົ້ນຫາ…' }, contentToc: { title: 'ໃນໜ້ານີ້' }, dropdownMenu: { noMatch: 'ບໍ່ພົບຂໍ້ມູນທີ່ກົງກັນ', - search: 'ຄົ້ນຫາ...' + search: 'ຄົ້ນຫາ…' }, dashboardSearch: { theme: 'ທີມ' }, dashboardSearchButton: { - label: 'ຄົ້ນຫາ...' + label: 'ຄົ້ນຫາ…' }, dashboardSidebarCollapse: { collapse: 'ຫຍໍ້ແຖບດ້ານຂ້າງ', @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'ຫຼຸດລົງ', increment: 'ເພີ່ມຂຶ້ນ' }, + listbox: { + noData: 'ບໍ່ມີຂໍ້ມູນ', + noMatch: 'ບໍ່ພົບຂໍ້ມູນທີ່ກົງກັນ', + search: 'ຄົ້ນຫາ…' + }, modal: { close: 'ປິດ' }, @@ -133,7 +138,7 @@ export default defineLocale({ create: 'ສ້າງ "{label}"', noData: 'ບໍ່ມີຂໍ້ມູນ', noMatch: 'ບໍ່ພົບຂໍ້ມູນທີ່ກົງກັນ', - search: 'ຄົ້ນຫາ...' + search: 'ຄົ້ນຫາ…' }, slideover: { close: 'ປິດ' diff --git a/src/runtime/locale/lt.ts b/src/runtime/locale/lt.ts index 84a9ae2193..75e1c31447 100644 --- a/src/runtime/locale/lt.ts +++ b/src/runtime/locale/lt.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'Sumažinti', increment: 'Padidinti' }, + listbox: { + noData: 'Nėra duomenų', + noMatch: 'Nėra atitinkančių duomenų', + search: 'Ieškoti…' + }, modal: { close: 'Uždaryti' }, diff --git a/src/runtime/locale/mn.ts b/src/runtime/locale/mn.ts index 3750f5e49e..a51b069168 100644 --- a/src/runtime/locale/mn.ts +++ b/src/runtime/locale/mn.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'Хасах', increment: 'Нэмэх' }, + listbox: { + noData: 'Мэдээлэл байхгүй', + noMatch: 'Тохирох мэдээлэл олдсонгүй', + search: 'Хайх…' + }, modal: { close: 'Хаах' }, diff --git a/src/runtime/locale/ms.ts b/src/runtime/locale/ms.ts index e295a0f319..fcb6a77116 100644 --- a/src/runtime/locale/ms.ts +++ b/src/runtime/locale/ms.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'Kurangkan', increment: 'Naikkan' }, + listbox: { + noData: 'Tiada data', + noMatch: 'Tiada data yang sepadan', + search: 'Cari…' + }, modal: { close: 'Tutup' }, diff --git a/src/runtime/locale/nb_no.ts b/src/runtime/locale/nb_no.ts index 2fb045ab72..4efd9bd2d8 100644 --- a/src/runtime/locale/nb_no.ts +++ b/src/runtime/locale/nb_no.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'Reduser', increment: 'Øk' }, + listbox: { + noData: 'Ingen data', + noMatch: 'Ingen samsvarende data', + search: 'Søk…' + }, modal: { close: 'Lukk' }, diff --git a/src/runtime/locale/nl.ts b/src/runtime/locale/nl.ts index 8e184d18d3..11cb16c5bc 100644 --- a/src/runtime/locale/nl.ts +++ b/src/runtime/locale/nl.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'Verlagen', increment: 'Verhogen' }, + listbox: { + noData: 'Geen gegevens', + noMatch: 'Geen overeenkomende gegevens', + search: 'Zoeken…' + }, modal: { close: 'Sluiten' }, diff --git a/src/runtime/locale/pl.ts b/src/runtime/locale/pl.ts index f0d142cea2..b502dd7058 100644 --- a/src/runtime/locale/pl.ts +++ b/src/runtime/locale/pl.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'Zmniejsz', increment: 'Zwiększ' }, + listbox: { + noData: 'Brak danych', + noMatch: 'Brak pasujących danych', + search: 'Szukaj…' + }, modal: { close: 'Zamknij' }, diff --git a/src/runtime/locale/pt.ts b/src/runtime/locale/pt.ts index 6895877831..1c3a28ef30 100644 --- a/src/runtime/locale/pt.ts +++ b/src/runtime/locale/pt.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'Decrementar', increment: 'Incrementar' }, + listbox: { + noData: 'Sem dados', + noMatch: 'Nenhum dado correspondente', + search: 'Pesquisar…' + }, modal: { close: 'Fechar' }, diff --git a/src/runtime/locale/pt_br.ts b/src/runtime/locale/pt_br.ts index 7a0d783c43..adc2404b2d 100644 --- a/src/runtime/locale/pt_br.ts +++ b/src/runtime/locale/pt_br.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'Decrementar', increment: 'Incrementar' }, + listbox: { + noData: 'Nenhum dado', + noMatch: 'Nenhum dado correspondente', + search: 'Pesquisar…' + }, modal: { close: 'Fechar' }, diff --git a/src/runtime/locale/ro.ts b/src/runtime/locale/ro.ts index 4195fb6ac5..08d8ebc559 100644 --- a/src/runtime/locale/ro.ts +++ b/src/runtime/locale/ro.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'Scade', increment: 'Crește' }, + listbox: { + noData: 'Nu există date', + noMatch: 'Nu există date corespunzătoare', + search: 'Caută…' + }, modal: { close: 'Închide' }, diff --git a/src/runtime/locale/ru.ts b/src/runtime/locale/ru.ts index 5bb7eeaf04..c823dce064 100644 --- a/src/runtime/locale/ru.ts +++ b/src/runtime/locale/ru.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'Уменьшить', increment: 'Увеличить' }, + listbox: { + noData: 'Нет данных', + noMatch: 'Совпадений не найдено', + search: 'Поиск…' + }, modal: { close: 'Закрыть' }, diff --git a/src/runtime/locale/sk.ts b/src/runtime/locale/sk.ts index cff6e0968d..78a9361a84 100644 --- a/src/runtime/locale/sk.ts +++ b/src/runtime/locale/sk.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'Znížiť', increment: 'Zvýšiť' }, + listbox: { + noData: 'Žiadne dáta', + noMatch: 'Žiadna zhoda', + search: 'Hľadať…' + }, modal: { close: 'Zatvoriť' }, diff --git a/src/runtime/locale/sl.ts b/src/runtime/locale/sl.ts index a87b9984e3..4b218bee05 100644 --- a/src/runtime/locale/sl.ts +++ b/src/runtime/locale/sl.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'Zmanjšaj', increment: 'Povišaj' }, + listbox: { + noData: 'Ni podatkov', + noMatch: 'Ni ujemanj', + search: 'Išči…' + }, modal: { close: 'Zapri' }, diff --git a/src/runtime/locale/sq.ts b/src/runtime/locale/sq.ts index 44c590bd65..9a94532914 100644 --- a/src/runtime/locale/sq.ts +++ b/src/runtime/locale/sq.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'Zvogëlo', increment: 'Rrit' }, + listbox: { + noData: 'Nuk ka të dhëna', + noMatch: 'Nuk ka të dhëna që përputhen', + search: 'Kërko…' + }, modal: { close: 'Mbyll' }, diff --git a/src/runtime/locale/sv.ts b/src/runtime/locale/sv.ts index 373dd118a1..d52031cb12 100644 --- a/src/runtime/locale/sv.ts +++ b/src/runtime/locale/sv.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'Minska', increment: 'Öka' }, + listbox: { + noData: 'Inga data', + noMatch: 'Inga matchande data', + search: 'Sök…' + }, modal: { close: 'Stäng' }, diff --git a/src/runtime/locale/th.ts b/src/runtime/locale/th.ts index f6409f0c2a..e296a344e9 100644 --- a/src/runtime/locale/th.ts +++ b/src/runtime/locale/th.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'ลด', increment: 'เพิ่ม' }, + listbox: { + noData: 'ไม่มีข้อมูล', + noMatch: 'ไม่พบข้อมูลที่ตรงกัน', + search: 'ค้นหา…' + }, modal: { close: 'ปิด' }, diff --git a/src/runtime/locale/tj.ts b/src/runtime/locale/tj.ts index 635be7565f..baa0b6af6c 100644 --- a/src/runtime/locale/tj.ts +++ b/src/runtime/locale/tj.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'Кам кардан', increment: 'Зиёд кардан' }, + listbox: { + noData: 'Маълумот нест', + noMatch: 'Маълумоти мувофиқ ёфт нашуд', + search: 'Ҷустуҷӯ…' + }, modal: { close: 'Бастан' }, diff --git a/src/runtime/locale/tr.ts b/src/runtime/locale/tr.ts index b42d222912..c101dd2aa0 100644 --- a/src/runtime/locale/tr.ts +++ b/src/runtime/locale/tr.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'Azalt', increment: 'Arttır' }, + listbox: { + noData: 'Veri yok', + noMatch: 'Eşleşen veri yok', + search: 'Ara…' + }, modal: { close: 'Kapat' }, diff --git a/src/runtime/locale/ug_cn.ts b/src/runtime/locale/ug_cn.ts index 9a6f47efa1..de09df2592 100644 --- a/src/runtime/locale/ug_cn.ts +++ b/src/runtime/locale/ug_cn.ts @@ -101,6 +101,11 @@ export default defineLocale({ decrement: 'ئازايتىش', increment: 'كۆپەيتىش' }, + listbox: { + noData: 'سانلىق مەلۇمات يوق', + noMatch: 'ماس كېلىدىغان سانلىق مەلۇمات يوق', + search: 'ئىزدەش…' + }, modal: { close: 'تاقاش' }, diff --git a/src/runtime/locale/uk.ts b/src/runtime/locale/uk.ts index 93eb45be61..dfae94f6aa 100644 --- a/src/runtime/locale/uk.ts +++ b/src/runtime/locale/uk.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'Зменшити', increment: 'Збільшити' }, + listbox: { + noData: 'Немає даних', + noMatch: 'Збігів не знайдено', + search: 'Пошук…' + }, modal: { close: 'Закрити' }, diff --git a/src/runtime/locale/ur.ts b/src/runtime/locale/ur.ts index 7f509e5c9c..85e58ae619 100644 --- a/src/runtime/locale/ur.ts +++ b/src/runtime/locale/ur.ts @@ -101,6 +101,11 @@ export default defineLocale({ decrement: 'کمی', increment: 'اضافہ' }, + listbox: { + noData: 'کوئی ڈیٹا نہیں', + noMatch: 'کوئی ملتا جلتا ڈیٹا نہیں ملا', + search: 'تلاش کریں…' + }, modal: { close: 'بند کریں' }, diff --git a/src/runtime/locale/uz.ts b/src/runtime/locale/uz.ts index c8315f02bb..4eea4aabf0 100644 --- a/src/runtime/locale/uz.ts +++ b/src/runtime/locale/uz.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'Ayirish', increment: 'Qoʻshish' }, + listbox: { + noData: 'Maʼlumot yoʻq', + noMatch: 'Mos keluvchi natija topilmadi', + search: 'Qidirish…' + }, modal: { close: 'Yopish' }, diff --git a/src/runtime/locale/vi.ts b/src/runtime/locale/vi.ts index 5c65594b0c..2b4c475804 100644 --- a/src/runtime/locale/vi.ts +++ b/src/runtime/locale/vi.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: 'Giảm', increment: 'Tăng' }, + listbox: { + noData: 'Không có dữ liệu', + noMatch: 'Không có kết quả phù hợp', + search: 'Tìm kiếm…' + }, modal: { close: 'Đóng' }, diff --git a/src/runtime/locale/zh_cn.ts b/src/runtime/locale/zh_cn.ts index 727cdf36d3..e6202e2bf1 100644 --- a/src/runtime/locale/zh_cn.ts +++ b/src/runtime/locale/zh_cn.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: '减少', increment: '增加' }, + listbox: { + noData: '没有数据', + noMatch: '没有匹配的数据', + search: '搜索…' + }, modal: { close: '关闭' }, diff --git a/src/runtime/locale/zh_tw.ts b/src/runtime/locale/zh_tw.ts index d99f8821e2..82bb7d1cda 100644 --- a/src/runtime/locale/zh_tw.ts +++ b/src/runtime/locale/zh_tw.ts @@ -100,6 +100,11 @@ export default defineLocale({ decrement: '減少', increment: '增加' }, + listbox: { + noData: '沒有資料', + noMatch: '沒有相符的資料', + search: '搜尋…' + }, modal: { close: '關閉' }, diff --git a/src/runtime/types/index.ts b/src/runtime/types/index.ts index b6f4ed48cd..21b988e419 100644 --- a/src/runtime/types/index.ts +++ b/src/runtime/types/index.ts @@ -67,6 +67,7 @@ export * from '../components/InputTags.vue' export * from '../components/InputTime.vue' export * from '../components/Kbd.vue' export * from '../components/Link.vue' +export * from '../components/Listbox.vue' export * from '../components/Main.vue' export * from '../components/Marquee.vue' export * from '../components/Modal.vue' diff --git a/src/runtime/types/locale.ts b/src/runtime/types/locale.ts index de30698a20..fa7e8e777c 100644 --- a/src/runtime/types/locale.ts +++ b/src/runtime/types/locale.ts @@ -99,6 +99,11 @@ export type Messages = { decrement: string increment: string } + listbox: { + noData: string + noMatch: string + search: string + } modal: { close: string } diff --git a/src/theme/index.ts b/src/theme/index.ts index ed663a9549..2b076f6d0c 100644 --- a/src/theme/index.ts +++ b/src/theme/index.ts @@ -65,6 +65,7 @@ export { default as inputTags } from './input-tags' export { default as inputTime } from './input-time' export { default as kbd } from './kbd' export { default as link } from './link' +export { default as listbox } from './listbox' export { default as main } from './main' export { default as marquee } from './marquee' export { default as modal } from './modal' diff --git a/src/theme/listbox.ts b/src/theme/listbox.ts new file mode 100644 index 0000000000..25508b7149 --- /dev/null +++ b/src/theme/listbox.ts @@ -0,0 +1,127 @@ +import type { ModuleOptions } from '../module' + +export default (options: Required) => ({ + slots: { + root: 'flex flex-col min-h-0 min-w-0 ring ring-inset ring-default rounded-lg overflow-hidden', + input: 'border-b border-default', + content: 'relative overflow-y-auto flex-1 max-h-60 scroll-py-1 focus:outline-none', + group: 'p-1 isolate', + label: 'font-semibold text-highlighted', + separator: '-mx-1 my-1 h-px bg-border', + empty: 'text-center text-muted', + loading: 'flex items-center justify-center text-muted', + loadingIcon: 'animate-spin shrink-0', + item: ['group relative w-full flex items-start select-none outline-none before:absolute before:z-[-1] before:inset-px before:rounded-md data-disabled:cursor-not-allowed data-disabled:opacity-75 text-default data-highlighted:not-data-disabled:text-highlighted data-highlighted:not-data-disabled:before:bg-elevated/50', options.theme.transitions && 'transition-colors before:transition-colors'], + itemLeadingIcon: ['shrink-0 text-dimmed group-data-highlighted:not-group-data-disabled:text-default', options.theme.transitions && 'transition-colors'], + itemLeadingAvatar: 'shrink-0', + itemLeadingAvatarSize: '', + itemLeadingChip: 'shrink-0', + itemLeadingChipSize: '', + itemWrapper: 'flex-1 flex flex-col min-w-0', + itemLabel: 'truncate', + itemDescription: 'truncate text-muted', + itemTrailing: 'ms-auto inline-flex gap-1.5 items-center', + itemTrailingIcon: 'shrink-0' + }, + variants: { + size: { + xs: { + label: 'p-1 text-[10px]/3 gap-1', + empty: 'py-3 text-xs', + loading: 'py-3', + loadingIcon: 'size-4', + item: 'p-1 text-xs gap-1', + itemLeadingIcon: 'size-4', + itemLeadingAvatarSize: '3xs', + itemLeadingChip: 'size-4', + itemLeadingChipSize: 'sm', + itemTrailingIcon: 'size-4' + }, + sm: { + label: 'p-1.5 text-[10px]/3 gap-1.5', + empty: 'py-4 text-xs', + loading: 'py-4', + loadingIcon: 'size-4', + item: 'p-1.5 text-xs gap-1.5', + itemLeadingIcon: 'size-4', + itemLeadingAvatarSize: '3xs', + itemLeadingChip: 'size-4', + itemLeadingChipSize: 'sm', + itemTrailingIcon: 'size-4' + }, + md: { + label: 'p-1.5 text-xs gap-1.5', + empty: 'py-6 text-sm', + loading: 'py-6', + loadingIcon: 'size-5', + item: 'p-1.5 text-sm gap-1.5', + itemLeadingIcon: 'size-5', + itemLeadingAvatarSize: '2xs', + itemLeadingChip: 'size-5', + itemLeadingChipSize: 'md', + itemTrailingIcon: 'size-5' + }, + lg: { + label: 'p-2 text-xs gap-2', + empty: 'py-7 text-sm', + loading: 'py-7', + loadingIcon: 'size-5', + item: 'p-2 text-sm gap-2', + itemLeadingIcon: 'size-5', + itemLeadingAvatarSize: '2xs', + itemLeadingChip: 'size-5', + itemLeadingChipSize: 'md', + itemTrailingIcon: 'size-5' + }, + xl: { + label: 'p-2 text-sm gap-2', + empty: 'py-8 text-base', + loading: 'py-8', + loadingIcon: 'size-6', + item: 'p-2 text-base gap-2', + itemLeadingIcon: 'size-6', + itemLeadingAvatarSize: 'xs', + itemLeadingChip: 'size-6', + itemLeadingChipSize: 'lg', + itemTrailingIcon: 'size-6', + itemDescription: 'text-sm' + } + }, + color: { + ...Object.fromEntries((options.theme.colors || []).map((color: string) => [color, ''])), + neutral: '' + }, + virtualize: { + true: { + content: 'p-1 isolate' + }, + false: { + content: 'divide-y divide-default' + } + }, + disabled: { + true: { + root: 'opacity-75 cursor-not-allowed' + } + }, + highlight: { + true: '' + } + }, + compoundVariants: [...(options.theme.colors || []).map((color: string) => ({ + color, + highlight: true, + class: { + root: `ring ring-inset ring-${color}` + } + })), { + color: 'neutral', + highlight: true, + class: { + root: 'ring ring-inset ring-inverted' + } + }], + defaultVariants: { + size: 'md' + } +}) diff --git a/test/components/Listbox.spec.ts b/test/components/Listbox.spec.ts new file mode 100644 index 0000000000..4490a97087 --- /dev/null +++ b/test/components/Listbox.spec.ts @@ -0,0 +1,226 @@ +import { describe, it, expect, test } from 'vitest' +import { axe } from 'vitest-axe' +import { mountSuspended } from '@nuxt/test-utils/runtime' +import { flushPromises, mount } from '@vue/test-utils' +import { renderEach } from '../component-render' +import { renderForm } from '../utils/form' +import { expectEmitPayloadType } from '../utils/types' +import theme from '#build/ui/listbox' +import type { FormInputEvents } from '../../src/module' +import Listbox from '../../src/runtime/components/Listbox.vue' + +describe('Listbox', () => { + const sizes = Object.keys(theme.variants.size) as any + + const items = [{ + label: 'France', + icon: 'i-lucide-map-pin', + value: 'FR' + }, { + label: 'Germany', + icon: 'i-lucide-map-pin', + value: 'DE' + }, { + label: 'Italy', + icon: 'i-lucide-map-pin', + value: 'IT' + }, { + label: 'Spain', + icon: 'i-lucide-map-pin', + value: 'ES' + }] + + const itemsWithDescription = items.map(item => ({ ...item, description: 'Description' })) + + const props = { items } + + renderEach(Listbox, [ + // Props + ['with items', { props }], + ['with items with description', { props: { ...props, items: itemsWithDescription } }], + ['with modelValue', { props: { ...props, modelValue: items[0] } }], + ['with defaultValue', { props: { ...props, defaultValue: items[0] } }], + ['with valueKey', { props: { ...props, valueKey: 'value', defaultValue: 'FR' } }], + ['with by', { props: { ...props, by: 'value', defaultValue: items[0] } }], + ['with labelKey', { props: { ...props, labelKey: 'value' } }], + ['with descriptionKey', { props: { ...props, descriptionKey: 'description' } }], + ['with multiple', { props: { ...props, multiple: true } }], + ['with multiple and modelValue', { props: { ...props, multiple: true, modelValue: [items[0], items[1]] } }], + ['with id', { props: { ...props, id: 'id' } }], + ['with name', { props: { ...props, name: 'name' } }], + ['with required', { props: { ...props, required: true } }], + ['with filter', { props: { ...props, filter: true } }], + ['with filter and placeholder', { props: { ...props, filter: { placeholder: 'Filter...' } } }], + ['with disabled', { props: { ...props, disabled: true } }], + ['with loading', { props: { ...props, loading: true } }], + ['with loadingIcon', { props: { ...props, loading: true, loadingIcon: 'i-lucide-loader' } }], + ['with selectedIcon', { props: { ...props, selectedIcon: 'i-lucide-check' } }], + ['with virtualize', { props: { ...props, virtualize: true } }], + ...sizes.map((size: string) => [`with size ${size}`, { props: { ...props, size } }]), + ['with class', { props: { ...props, class: 'max-h-64' } }], + ['with ui', { props: { ...props, ui: { content: 'p-2' } } }], + // Slots + ['with item slot', { props, slots: { item: () => 'Item slot' } }], + ['with item-leading slot', { props, slots: { 'item-leading': () => 'Item leading slot' } }], + ['with item-label slot', { props, slots: { 'item-label': () => 'Item label slot' } }], + ['with item-description slot', { props: { ...props, items: itemsWithDescription }, slots: { 'item-description': () => 'Item description slot' } }], + ['with item-trailing slot', { props, slots: { 'item-trailing': () => 'Item trailing slot' } }] + ]) + + renderEach( + Listbox, + [ + ['with .trim modifier', { props: { ...props, modelModifiers: { trim: true } } }, { input: 'input ', expected: 'input' }], + ['with .number modifier', { props: { ...props, modelModifiers: { number: true } } }, { input: '42', expected: 42 }], + ['with .nullable modifier', { props: { ...props, modelModifiers: { nullable: true } } }, { input: null, expected: null }], + ['with .optional modifier', { props: { ...props, modelModifiers: { optional: true } } }, { input: undefined, expected: undefined }] + ], + '%s works', async (_, options, spec) => { + const wrapper = mount(Listbox, { + ...options + }) + + const listbox = wrapper.findComponent({ name: 'ListboxRoot' }) + await listbox.setValue(spec.input) + + expect(wrapper.emitted()).toMatchObject({ 'update:modelValue': [[spec.expected]] }) + } + ) + + it('passes accessibility tests', async () => { + const wrapper = await mountSuspended(Listbox, { + props: { + ...props, + modelValue: items[0] + }, + attrs: { + ariaLabel: 'Countries' + } + }) + expect(await axe(wrapper.element, { + rules: { + 'aria-input-field-name': { enabled: false } + } + })).toHaveNoViolations() + }) + + describe('emits', () => { + test('update:modelValue event', async () => { + const wrapper = mount(Listbox, { props }) + const input = wrapper.findComponent({ name: 'ListboxRoot' }) + await input.setValue(items[0]) + + expect(wrapper.emitted()).toMatchObject({ 'update:modelValue': [[items[0]]] }) + }) + + test('change event', async () => { + const wrapper = mount(Listbox, { props }) + const input = wrapper.findComponent({ name: 'ListboxRoot' }) + await input.setValue(items[0]) + expect(wrapper.emitted()).toMatchObject({ change: [[{ type: 'change' }]] }) + }) + }) + + describe('form integration', async () => { + const item1 = { label: 'Option 1', value: 'opt1' } + const item2 = { label: 'Option 2', value: 'opt2' } + + async function createForm(validateOn?: FormInputEvents[]) { + const wrapper = await renderForm({ + props: { + validateOn, + validateOnInputDelay: 0, + async validate(state: any) { + if (!state.value?.some((i: any) => i.value === 'opt2')) + return [{ name: 'value', message: 'Error message' }] + return [] + } + }, + slotVars: { + items: [item1, item2] + }, + slotTemplate: ` + + + + ` + }) + const input = wrapper.findComponent({ name: 'ListboxRoot' }) + return { wrapper, input } + } + + test('validate on change works', async () => { + const { input, wrapper } = await createForm(['change']) + + input.setValue([item1]) + await flushPromises() + expect(wrapper.text()).toContain('Error message') + + input.setValue([item2]) + await flushPromises() + expect(wrapper.text()).not.toContain('Error message') + }) + + test('validate on input works', async () => { + const { input, wrapper } = await createForm(['input']) + + input.setValue([item1]) + await flushPromises() + expect(wrapper.text()).toContain('Error message') + + input.setValue([item2]) + await flushPromises() + expect(wrapper.text()).not.toContain('Error message') + }) + + test('should have the correct types', () => { + // with object item + expectEmitPayloadType('update:modelValue', () => Listbox({ + items: [{ label: 'foo', value: 'bar' }] + })).toEqualTypeOf<[{ label: string, value: string }]>() + + // with object item and multiple + expectEmitPayloadType('update:modelValue', () => Listbox({ + items: [{ label: 'foo', value: 1 }], + multiple: true + })).toEqualTypeOf<[{ label: string, value: number }[]]>() + + // with object item and valueKey + expectEmitPayloadType('update:modelValue', () => Listbox({ + items: [{ label: 'foo', value: 'bar' }], + valueKey: 'value' + })).toEqualTypeOf<[string]>() + + // with object item and multiple and valueKey + expectEmitPayloadType('update:modelValue', () => Listbox({ + items: [{ label: 'foo', value: 1 }], + multiple: true, + valueKey: 'value' + })).toEqualTypeOf<[number[]]>() + + // with object item and object valueKey + expectEmitPayloadType('update:modelValue', () => Listbox({ + items: [{ label: 'foo', value: { id: 1, name: 'bar' } }], + valueKey: 'value' + })).toEqualTypeOf<[{ id: number, name: string }]>() + + // with groups + expectEmitPayloadType('update:modelValue', () => Listbox({ + items: [[{ label: 'foo', value: 'bar' }]] + })).toEqualTypeOf<[{ label: string, value: string }]>() + + // with groups and multiple + expectEmitPayloadType('update:modelValue', () => Listbox({ + items: [[{ label: 'foo', value: 1 }]], + multiple: true + })).toEqualTypeOf<[{ label: string, value: number }[]]>() + + // with groups, multiple and valueKey + expectEmitPayloadType('update:modelValue', () => Listbox({ + items: [[{ label: 'foo', value: 'bar' }]], + multiple: true, + valueKey: 'value' + })).toEqualTypeOf<[string[]]>() + }) + }) +}) diff --git a/test/components/__snapshots__/ChatReasoning-vue.spec.ts.snap b/test/components/__snapshots__/ChatReasoning-vue.spec.ts.snap index 604bf4497b..524d88bc61 100644 --- a/test/components/__snapshots__/ChatReasoning-vue.spec.ts.snap +++ b/test/components/__snapshots__/ChatReasoning-vue.spec.ts.snap @@ -70,7 +70,7 @@ exports[`ChatReasoning > renders with icon correctly 1`] = ` exports[`ChatReasoning > renders with streaming correctly 1`] = ` "
diff --git a/test/components/__snapshots__/ChatReasoning.spec.ts.snap b/test/components/__snapshots__/ChatReasoning.spec.ts.snap index cab9cbb5d8..2f17dbfa26 100644 --- a/test/components/__snapshots__/ChatReasoning.spec.ts.snap +++ b/test/components/__snapshots__/ChatReasoning.spec.ts.snap @@ -72,7 +72,7 @@ exports[`ChatReasoning > renders with icon correctly 1`] = ` exports[`ChatReasoning > renders with streaming correctly 1`] = ` "
diff --git a/test/components/__snapshots__/Listbox-vue.spec.ts.snap b/test/components/__snapshots__/Listbox-vue.spec.ts.snap new file mode 100644 index 0000000000..45a2456ab7 --- /dev/null +++ b/test/components/__snapshots__/Listbox-vue.spec.ts.snap @@ -0,0 +1,680 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`Listbox > renders with by correctly 1`] = ` +"
+ +
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with class correctly 1`] = ` +"
+ +
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with defaultValue correctly 1`] = ` +"
+ +
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with descriptionKey correctly 1`] = ` +"
+ +
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with disabled correctly 1`] = ` +"
+ +
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with filter and placeholder correctly 1`] = ` +"
+
+ + +
+
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with filter correctly 1`] = ` +"
+
+ + +
+
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with id correctly 1`] = ` +"
+ +
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with item slot correctly 1`] = ` +"
+ +
+
+
Item slot
+
Item slot
+
Item slot
+
Item slot
+
+
+ +
" +`; + +exports[`Listbox > renders with item-description slot correctly 1`] = ` +"
+ +
+
+
FranceItem description slot
+
GermanyItem description slot
+
ItalyItem description slot
+
SpainItem description slot
+
+
+ +
" +`; + +exports[`Listbox > renders with item-label slot correctly 1`] = ` +"
+ +
+
+
Item label slot + +
+
Item label slot + +
+
Item label slot + +
+
Item label slot + +
+
+
+ +
" +`; + +exports[`Listbox > renders with item-leading slot correctly 1`] = ` +"
+ +
+
+
Item leading slotFrance + +
+
Item leading slotGermany + +
+
Item leading slotItaly + +
+
Item leading slotSpain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with item-trailing slot correctly 1`] = ` +"
+ +
+
+
France + Item trailing slot +
+
Germany + Item trailing slot +
+
Italy + Item trailing slot +
+
Spain + Item trailing slot +
+
+
+ +
" +`; + +exports[`Listbox > renders with items correctly 1`] = ` +"
+ +
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with items with description correctly 1`] = ` +"
+ +
+
+
FranceDescription
+
GermanyDescription
+
ItalyDescription
+
SpainDescription
+
+
+ +
" +`; + +exports[`Listbox > renders with labelKey correctly 1`] = ` +"
+ +
+
+
FR + +
+
DE + +
+
IT + +
+
ES + +
+
+
+ +
" +`; + +exports[`Listbox > renders with loading correctly 1`] = ` +"
+ +
+
+
+ +
" +`; + +exports[`Listbox > renders with loadingIcon correctly 1`] = ` +"
+ +
+
+
+ +
" +`; + +exports[`Listbox > renders with modelValue correctly 1`] = ` +"
+ +
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with multiple and modelValue correctly 1`] = ` +"
+ +
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with multiple correctly 1`] = ` +"
+ +
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with name correctly 1`] = ` +"
+ +
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with required correctly 1`] = ` +"
+ +
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with selectedIcon correctly 1`] = ` +"
+ +
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with size lg correctly 1`] = ` +"
+ +
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with size md correctly 1`] = ` +"
+ +
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with size sm correctly 1`] = ` +"
+ +
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with size xl correctly 1`] = ` +"
+ +
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with size xs correctly 1`] = ` +"
+ +
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with ui correctly 1`] = ` +"
+ +
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with valueKey correctly 1`] = ` +"
+ +
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with virtualize correctly 1`] = ` +"
+ +
+
+
+ +
" +`; diff --git a/test/components/__snapshots__/Listbox.spec.ts.snap b/test/components/__snapshots__/Listbox.spec.ts.snap new file mode 100644 index 0000000000..75118f21b9 --- /dev/null +++ b/test/components/__snapshots__/Listbox.spec.ts.snap @@ -0,0 +1,680 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`Listbox > renders with by correctly 1`] = ` +"
+ +
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with class correctly 1`] = ` +"
+ +
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with defaultValue correctly 1`] = ` +"
+ +
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with descriptionKey correctly 1`] = ` +"
+ +
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with disabled correctly 1`] = ` +"
+ +
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with filter and placeholder correctly 1`] = ` +"
+
+ + +
+
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with filter correctly 1`] = ` +"
+
+ + +
+
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with id correctly 1`] = ` +"
+ +
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with item slot correctly 1`] = ` +"
+ +
+
+
Item slot
+
Item slot
+
Item slot
+
Item slot
+
+
+ +
" +`; + +exports[`Listbox > renders with item-description slot correctly 1`] = ` +"
+ +
+
+
FranceItem description slot
+
GermanyItem description slot
+
ItalyItem description slot
+
SpainItem description slot
+
+
+ +
" +`; + +exports[`Listbox > renders with item-label slot correctly 1`] = ` +"
+ +
+
+
Item label slot + +
+
Item label slot + +
+
Item label slot + +
+
Item label slot + +
+
+
+ +
" +`; + +exports[`Listbox > renders with item-leading slot correctly 1`] = ` +"
+ +
+
+
Item leading slotFrance + +
+
Item leading slotGermany + +
+
Item leading slotItaly + +
+
Item leading slotSpain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with item-trailing slot correctly 1`] = ` +"
+ +
+
+
France + Item trailing slot +
+
Germany + Item trailing slot +
+
Italy + Item trailing slot +
+
Spain + Item trailing slot +
+
+
+ +
" +`; + +exports[`Listbox > renders with items correctly 1`] = ` +"
+ +
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with items with description correctly 1`] = ` +"
+ +
+
+
FranceDescription
+
GermanyDescription
+
ItalyDescription
+
SpainDescription
+
+
+ +
" +`; + +exports[`Listbox > renders with labelKey correctly 1`] = ` +"
+ +
+
+
FR + +
+
DE + +
+
IT + +
+
ES + +
+
+
+ +
" +`; + +exports[`Listbox > renders with loading correctly 1`] = ` +"
+ +
+
+
+ +
" +`; + +exports[`Listbox > renders with loadingIcon correctly 1`] = ` +"
+ +
+
+
+ +
" +`; + +exports[`Listbox > renders with modelValue correctly 1`] = ` +"
+ +
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with multiple and modelValue correctly 1`] = ` +"
+ +
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with multiple correctly 1`] = ` +"
+ +
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with name correctly 1`] = ` +"
+ +
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with required correctly 1`] = ` +"
+ +
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with selectedIcon correctly 1`] = ` +"
+ +
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with size lg correctly 1`] = ` +"
+ +
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with size md correctly 1`] = ` +"
+ +
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with size sm correctly 1`] = ` +"
+ +
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with size xl correctly 1`] = ` +"
+ +
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with size xs correctly 1`] = ` +"
+ +
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with ui correctly 1`] = ` +"
+ +
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with valueKey correctly 1`] = ` +"
+ +
+
+
France + +
+
Germany + +
+
Italy + +
+
Spain + +
+
+
+ +
" +`; + +exports[`Listbox > renders with virtualize correctly 1`] = ` +"
+ +
+
+
+ +
" +`; diff --git a/test/utils/form.ts b/test/utils/form.ts index 492c501187..a89593de58 100644 --- a/test/utils/form.ts +++ b/test/utils/form.ts @@ -17,7 +17,8 @@ import { USlider, UPinInput, UCheckboxGroup, - UFileUpload + UFileUpload, + UListbox } from '#components' export async function renderForm(options: { @@ -63,7 +64,8 @@ export async function renderForm(options: { USlider, UPinInput, UCheckboxGroup, - UFileUpload + UFileUpload, + UListbox }, template: options.slotTemplate }