mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-14 12:14:41 +01:00
feat(CommandPalette): handle children in items (#4226)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
This commit is contained in:
@@ -83,7 +83,7 @@ const groups = [
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template #billing-label="{ item }">
|
<template #billing-label="{ item }">
|
||||||
{{ item.label }}
|
<span class="font-medium text-primary">{{ item.label }}</span>
|
||||||
|
|
||||||
<UBadge variant="subtle" size="sm">
|
<UBadge variant="subtle" size="sm">
|
||||||
50% off
|
50% off
|
||||||
|
|||||||
@@ -0,0 +1,119 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
const toast = useToast()
|
||||||
|
|
||||||
|
const groups = [{
|
||||||
|
id: 'actions',
|
||||||
|
label: 'Actions',
|
||||||
|
items: [{
|
||||||
|
label: 'Create new',
|
||||||
|
icon: 'i-lucide-plus',
|
||||||
|
children: [{
|
||||||
|
label: 'New file',
|
||||||
|
icon: 'i-lucide-file-plus',
|
||||||
|
suffix: 'Create a new file in the current directory',
|
||||||
|
onSelect(e: Event) {
|
||||||
|
e.preventDefault()
|
||||||
|
toast.add({ title: 'New file created!' })
|
||||||
|
},
|
||||||
|
kbds: ['meta', 'N']
|
||||||
|
}, {
|
||||||
|
label: 'New folder',
|
||||||
|
icon: 'i-lucide-folder-plus',
|
||||||
|
suffix: 'Create a new folder in the current directory',
|
||||||
|
onSelect(e: Event) {
|
||||||
|
e.preventDefault()
|
||||||
|
toast.add({ title: 'New folder created!' })
|
||||||
|
},
|
||||||
|
kbds: ['meta', 'F']
|
||||||
|
}, {
|
||||||
|
label: 'New project',
|
||||||
|
icon: 'i-lucide-folder-git',
|
||||||
|
suffix: 'Create a new project from a template',
|
||||||
|
onSelect(e: Event) {
|
||||||
|
e.preventDefault()
|
||||||
|
toast.add({ title: 'New project created!' })
|
||||||
|
},
|
||||||
|
kbds: ['meta', 'P']
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
label: 'Share',
|
||||||
|
icon: 'i-lucide-share',
|
||||||
|
children: [{
|
||||||
|
label: 'Copy link',
|
||||||
|
icon: 'i-lucide-link',
|
||||||
|
suffix: 'Copy a link to the current item',
|
||||||
|
onSelect(e: Event) {
|
||||||
|
e.preventDefault()
|
||||||
|
toast.add({ title: 'Link copied to clipboard!' })
|
||||||
|
},
|
||||||
|
kbds: ['meta', 'L']
|
||||||
|
}, {
|
||||||
|
label: 'Share via email',
|
||||||
|
icon: 'i-lucide-mail',
|
||||||
|
suffix: 'Share the current item via email',
|
||||||
|
onSelect(e: Event) {
|
||||||
|
e.preventDefault()
|
||||||
|
toast.add({ title: 'Share via email dialog opened!' })
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
label: 'Share on social',
|
||||||
|
icon: 'i-lucide-share-2',
|
||||||
|
suffix: 'Share the current item on social media',
|
||||||
|
children: [{
|
||||||
|
label: 'Twitter',
|
||||||
|
icon: 'i-simple-icons-twitter',
|
||||||
|
onSelect(e: Event) {
|
||||||
|
e.preventDefault()
|
||||||
|
toast.add({ title: 'Shared on Twitter!' })
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
label: 'LinkedIn',
|
||||||
|
icon: 'i-simple-icons-linkedin',
|
||||||
|
onSelect(e: Event) {
|
||||||
|
e.preventDefault()
|
||||||
|
toast.add({ title: 'Shared on LinkedIn!' })
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
label: 'Facebook',
|
||||||
|
icon: 'i-simple-icons-facebook',
|
||||||
|
onSelect(e: Event) {
|
||||||
|
e.preventDefault()
|
||||||
|
toast.add({ title: 'Shared on Facebook!' })
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
label: 'Settings',
|
||||||
|
icon: 'i-lucide-settings',
|
||||||
|
children: [{
|
||||||
|
label: 'General',
|
||||||
|
icon: 'i-lucide-sliders',
|
||||||
|
suffix: 'Configure general settings',
|
||||||
|
onSelect(e: Event) {
|
||||||
|
e.preventDefault()
|
||||||
|
toast.add({ title: 'General settings opened!' })
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
label: 'Appearance',
|
||||||
|
icon: 'i-lucide-palette',
|
||||||
|
suffix: 'Customize the appearance',
|
||||||
|
onSelect(e: Event) {
|
||||||
|
e.preventDefault()
|
||||||
|
toast.add({ title: 'Appearance settings opened!' })
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
label: 'Security',
|
||||||
|
icon: 'i-lucide-shield',
|
||||||
|
suffix: 'Manage security settings',
|
||||||
|
onSelect(e: Event) {
|
||||||
|
e.preventDefault()
|
||||||
|
toast.add({ title: 'Security settings opened!' })
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<UCommandPalette :groups="groups" class="flex-1" />
|
||||||
|
</template>
|
||||||
@@ -52,9 +52,11 @@ Each group contains an `items` array of objects that define the commands. Each i
|
|||||||
- `loading?: boolean`{lang="ts-type"}
|
- `loading?: boolean`{lang="ts-type"}
|
||||||
- `disabled?: boolean`{lang="ts-type"}
|
- `disabled?: boolean`{lang="ts-type"}
|
||||||
- [`slot?: string`{lang="ts-type"}](#with-custom-slot)
|
- [`slot?: string`{lang="ts-type"}](#with-custom-slot)
|
||||||
|
- `placeholder?: string`{lang="ts-type"} :badge{label="Soon"}
|
||||||
|
- `children?: CommandPaletteItem[]`{lang="ts-type"} :badge{label="Soon"}
|
||||||
- `onSelect?(e?: Event): void`{lang="ts-type"}
|
- `onSelect?(e?: Event): void`{lang="ts-type"}
|
||||||
- `class?: any`{lang="ts-type"}
|
- `class?: any`{lang="ts-type"}
|
||||||
- `ui?: { item?: ClassNameValue, itemLeadingIcon?: ClassNameValue, itemLeadingAvatarSize?: ClassNameValue, itemLeadingAvatar?: ClassNameValue, itemLeadingChipSize?: ClassNameValue, itemLeadingChip?: ClassNameValue, itemLabel?: ClassNameValue, itemLabelPrefix?: ClassNameValue, itemLabelBase?: ClassNameValue, itemLabelSuffix?: ClassNameValue, itemTrailing?: ClassNameValue, itemTrailingKbds?: ClassNameValue, itemTrailingKbdsSize?: ClassNameValue, itemTrailingHighlightedIcon?: ClassNameValue, itemTrailingIcon?: ClassNameValue,}`{lang="ts-type"}
|
- `ui?: { item?: ClassNameValue, itemLeadingIcon?: ClassNameValue, itemLeadingAvatarSize?: ClassNameValue, itemLeadingAvatar?: ClassNameValue, itemLeadingChipSize?: ClassNameValue, itemLeadingChip?: ClassNameValue, itemLabel?: ClassNameValue, itemLabelPrefix?: ClassNameValue, itemLabelBase?: ClassNameValue, itemLabelSuffix?: ClassNameValue, itemTrailing?: ClassNameValue, itemTrailingKbds?: ClassNameValue, itemTrailingKbdsSize?: ClassNameValue, itemTrailingHighlightedIcon?: ClassNameValue, itemTrailingIcon?: ClassNameValue }`{lang="ts-type"}
|
||||||
|
|
||||||
You can pass any property from the [Link](/components/link#props) component such as `to`, `target`, etc.
|
You can pass any property from the [Link](/components/link#props) component such as `to`, `target`, etc.
|
||||||
|
|
||||||
@@ -110,6 +112,10 @@ props:
|
|||||||
---
|
---
|
||||||
::
|
::
|
||||||
|
|
||||||
|
::tip{to="#with-children-in-items"}
|
||||||
|
Each item can take a `children` array of objects with the following properties to create submenus:
|
||||||
|
::
|
||||||
|
|
||||||
### Multiple
|
### Multiple
|
||||||
|
|
||||||
Use the `multiple` prop to allow multiple selections.
|
Use the `multiple` prop to allow multiple selections.
|
||||||
@@ -246,6 +252,128 @@ You can customize this icon globally in your `vite.config.ts` under `ui.icons.se
|
|||||||
:::
|
:::
|
||||||
::
|
::
|
||||||
|
|
||||||
|
### Selected Icon
|
||||||
|
|
||||||
|
Use the `selected-icon` prop to customize the selected item [Icon](/components/icon). Defaults to `i-lucide-check`.
|
||||||
|
|
||||||
|
::component-code
|
||||||
|
---
|
||||||
|
collapse: true
|
||||||
|
hide:
|
||||||
|
- autofocus
|
||||||
|
ignore:
|
||||||
|
- groups
|
||||||
|
- modelValue
|
||||||
|
- multiple
|
||||||
|
- class
|
||||||
|
external:
|
||||||
|
- groups
|
||||||
|
- modelValue
|
||||||
|
class: '!p-0'
|
||||||
|
props:
|
||||||
|
multiple: true
|
||||||
|
autofocus: false
|
||||||
|
modelValue:
|
||||||
|
- label: 'Benjamin Canac'
|
||||||
|
suffix: 'benjamincanac'
|
||||||
|
avatar:
|
||||||
|
src: 'https://github.com/benjamincanac.png'
|
||||||
|
selectedIcon: 'i-lucide-circle-check'
|
||||||
|
groups:
|
||||||
|
- id: 'users'
|
||||||
|
label: 'Users'
|
||||||
|
items:
|
||||||
|
- label: 'Benjamin Canac'
|
||||||
|
suffix: 'benjamincanac'
|
||||||
|
avatar:
|
||||||
|
src: 'https://github.com/benjamincanac.png'
|
||||||
|
- label: 'Sylvain Marroufin'
|
||||||
|
suffix: 'smarroufin'
|
||||||
|
avatar:
|
||||||
|
src: 'https://github.com/smarroufin.png'
|
||||||
|
- label: 'Sébastien Chopin'
|
||||||
|
suffix: 'atinux'
|
||||||
|
avatar:
|
||||||
|
src: 'https://github.com/atinux.png'
|
||||||
|
- label: 'Romain Hamel'
|
||||||
|
suffix: 'romhml'
|
||||||
|
avatar:
|
||||||
|
src: 'https://github.com/romhml.png'
|
||||||
|
- label: 'Haytham A. Salama'
|
||||||
|
suffix: 'Haythamasalama'
|
||||||
|
avatar:
|
||||||
|
src: 'https://github.com/Haythamasalama.png'
|
||||||
|
- label: 'Daniel Roe'
|
||||||
|
suffix: 'danielroe'
|
||||||
|
avatar:
|
||||||
|
src: 'https://github.com/danielroe.png'
|
||||||
|
- label: 'Neil Richter'
|
||||||
|
suffix: 'noook'
|
||||||
|
avatar:
|
||||||
|
src: 'https://github.com/noook.png'
|
||||||
|
class: 'flex-1'
|
||||||
|
---
|
||||||
|
::
|
||||||
|
|
||||||
|
::framework-only
|
||||||
|
#nuxt
|
||||||
|
:::tip{to="/getting-started/icons/nuxt#theme"}
|
||||||
|
You can customize this icon globally in your `app.config.ts` under `ui.icons.check` key.
|
||||||
|
:::
|
||||||
|
|
||||||
|
#vue
|
||||||
|
:::tip{to="/getting-started/icons/vue#theme"}
|
||||||
|
You can customize this icon globally in your `vite.config.ts` under `ui.icons.check` key.
|
||||||
|
:::
|
||||||
|
::
|
||||||
|
|
||||||
|
### Trailing Icon :badge{label="Soon" class="align-text-top"}
|
||||||
|
|
||||||
|
Use the `trailing-icon` prop to customize the trailing [Icon](/components/icon) when an item has children. Defaults to `i-lucide-chevron-right`.
|
||||||
|
|
||||||
|
::component-code
|
||||||
|
---
|
||||||
|
collapse: true
|
||||||
|
prettier: true
|
||||||
|
hide:
|
||||||
|
- autofocus
|
||||||
|
ignore:
|
||||||
|
- groups
|
||||||
|
- class
|
||||||
|
external:
|
||||||
|
- groups
|
||||||
|
class: '!p-0'
|
||||||
|
props:
|
||||||
|
autofocus: false
|
||||||
|
trailingIcon: 'i-lucide-arrow-right'
|
||||||
|
groups:
|
||||||
|
- id: 'actions'
|
||||||
|
items:
|
||||||
|
- label: 'Share'
|
||||||
|
icon: 'i-lucide-share'
|
||||||
|
children:
|
||||||
|
- label: 'Email'
|
||||||
|
icon: 'i-lucide-mail'
|
||||||
|
- label: 'Copy'
|
||||||
|
icon: 'i-lucide-copy'
|
||||||
|
- label: 'Link'
|
||||||
|
icon: 'i-lucide-link'
|
||||||
|
class: 'flex-1'
|
||||||
|
---
|
||||||
|
::
|
||||||
|
|
||||||
|
::framework-only
|
||||||
|
#nuxt
|
||||||
|
:::tip{to="/getting-started/icons/nuxt#theme"}
|
||||||
|
You can customize this icon globally in your `app.config.ts` under `ui.icons.chevronRight` key.
|
||||||
|
:::
|
||||||
|
|
||||||
|
#vue
|
||||||
|
:::tip{to="/getting-started/icons/vue#theme"}
|
||||||
|
You can customize this icon globally in your `vite.config.ts` under `ui.icons.chevronRight` key.
|
||||||
|
:::
|
||||||
|
::
|
||||||
|
|
||||||
### Loading
|
### Loading
|
||||||
|
|
||||||
Use the `loading` prop to show a loading icon on the CommandPalette.
|
Use the `loading` prop to show a loading icon on the CommandPalette.
|
||||||
@@ -321,37 +449,6 @@ You can customize this icon globally in your `vite.config.ts` under `ui.icons.lo
|
|||||||
:::
|
:::
|
||||||
::
|
::
|
||||||
|
|
||||||
### Disabled
|
|
||||||
|
|
||||||
Use the `disabled` prop to disable the CommandPalette.
|
|
||||||
|
|
||||||
::component-code
|
|
||||||
---
|
|
||||||
collapse: true
|
|
||||||
hide:
|
|
||||||
- autofocus
|
|
||||||
ignore:
|
|
||||||
- groups
|
|
||||||
- class
|
|
||||||
external:
|
|
||||||
- groups
|
|
||||||
class: '!p-0'
|
|
||||||
props:
|
|
||||||
autofocus: false
|
|
||||||
disabled: true
|
|
||||||
groups:
|
|
||||||
- id: 'apps'
|
|
||||||
items:
|
|
||||||
- label: 'Calendar'
|
|
||||||
icon: 'i-lucide-calendar'
|
|
||||||
- label: 'Music'
|
|
||||||
icon: 'i-lucide-music'
|
|
||||||
- label: 'Maps'
|
|
||||||
icon: 'i-lucide-map'
|
|
||||||
class: 'flex-1'
|
|
||||||
---
|
|
||||||
::
|
|
||||||
|
|
||||||
### Close
|
### Close
|
||||||
|
|
||||||
Use the `close` prop to display a [Button](/components/button) to dismiss the CommandPalette.
|
Use the `close` prop to display a [Button](/components/button) to dismiss the CommandPalette.
|
||||||
@@ -468,6 +565,124 @@ You can customize this icon globally in your `vite.config.ts` under `ui.icons.cl
|
|||||||
:::
|
:::
|
||||||
::
|
::
|
||||||
|
|
||||||
|
### Back :badge{label="Soon" class="align-text-top"}
|
||||||
|
|
||||||
|
Use the `back` prop to customize or hide the back button (with `false` value) displayed when navigating into a submenu.
|
||||||
|
|
||||||
|
You can pass any property from the [Button](/components/button) component to customize it.
|
||||||
|
|
||||||
|
::component-code
|
||||||
|
---
|
||||||
|
collapse: true
|
||||||
|
prettier: true
|
||||||
|
hide:
|
||||||
|
- autofocus
|
||||||
|
ignore:
|
||||||
|
- back.color
|
||||||
|
- groups
|
||||||
|
- class
|
||||||
|
external:
|
||||||
|
- groups
|
||||||
|
class: '!p-0'
|
||||||
|
props:
|
||||||
|
autofocus: false
|
||||||
|
back:
|
||||||
|
color: primary
|
||||||
|
groups:
|
||||||
|
- id: 'actions'
|
||||||
|
items:
|
||||||
|
- label: 'Share'
|
||||||
|
icon: 'i-lucide-share'
|
||||||
|
children:
|
||||||
|
- label: 'Email'
|
||||||
|
icon: 'i-lucide-mail'
|
||||||
|
- label: 'Copy'
|
||||||
|
icon: 'i-lucide-copy'
|
||||||
|
- label: 'Link'
|
||||||
|
icon: 'i-lucide-link'
|
||||||
|
class: 'flex-1'
|
||||||
|
---
|
||||||
|
::
|
||||||
|
|
||||||
|
### Back Icon :badge{label="Soon" class="align-text-top"}
|
||||||
|
|
||||||
|
Use the `back-icon` prop to customize the back button [Icon](/components/icon). Defaults to `i-lucide-arrow-left`.
|
||||||
|
|
||||||
|
::component-code
|
||||||
|
---
|
||||||
|
collapse: true
|
||||||
|
hide:
|
||||||
|
- autofocus
|
||||||
|
ignore:
|
||||||
|
- class
|
||||||
|
- groups
|
||||||
|
- back
|
||||||
|
external:
|
||||||
|
- groups
|
||||||
|
class: '!p-0'
|
||||||
|
props:
|
||||||
|
autofocus: false
|
||||||
|
back: true
|
||||||
|
backIcon: 'i-lucide-house'
|
||||||
|
groups:
|
||||||
|
- id: 'actions'
|
||||||
|
items:
|
||||||
|
- label: 'Share'
|
||||||
|
icon: 'i-lucide-share'
|
||||||
|
children:
|
||||||
|
- label: 'Email'
|
||||||
|
icon: 'i-lucide-mail'
|
||||||
|
- label: 'Copy'
|
||||||
|
icon: 'i-lucide-copy'
|
||||||
|
- label: 'Link'
|
||||||
|
icon: 'i-lucide-link'
|
||||||
|
class: 'flex-1'
|
||||||
|
---
|
||||||
|
::
|
||||||
|
|
||||||
|
::framework-only
|
||||||
|
#nuxt
|
||||||
|
:::tip{to="/getting-started/icons/nuxt#theme"}
|
||||||
|
You can customize this icon globally in your `app.config.ts` under `ui.icons.arrowLeft` key.
|
||||||
|
:::
|
||||||
|
|
||||||
|
#vue
|
||||||
|
:::tip{to="/getting-started/icons/vue#theme"}
|
||||||
|
You can customize this icon globally in your `vite.config.ts` under `ui.icons.arrowLeft` key.
|
||||||
|
:::
|
||||||
|
::
|
||||||
|
|
||||||
|
### Disabled
|
||||||
|
|
||||||
|
Use the `disabled` prop to disable the CommandPalette.
|
||||||
|
|
||||||
|
::component-code
|
||||||
|
---
|
||||||
|
collapse: true
|
||||||
|
hide:
|
||||||
|
- autofocus
|
||||||
|
ignore:
|
||||||
|
- groups
|
||||||
|
- class
|
||||||
|
external:
|
||||||
|
- groups
|
||||||
|
class: '!p-0'
|
||||||
|
props:
|
||||||
|
autofocus: false
|
||||||
|
disabled: true
|
||||||
|
groups:
|
||||||
|
- id: 'apps'
|
||||||
|
items:
|
||||||
|
- label: 'Calendar'
|
||||||
|
icon: 'i-lucide-calendar'
|
||||||
|
- label: 'Music'
|
||||||
|
icon: 'i-lucide-music'
|
||||||
|
- label: 'Maps'
|
||||||
|
icon: 'i-lucide-map'
|
||||||
|
class: 'flex-1'
|
||||||
|
---
|
||||||
|
::
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
### Control selected item(s)
|
### Control selected item(s)
|
||||||
@@ -502,6 +717,28 @@ props:
|
|||||||
This example uses the `@update:model-value` event to reset the search term when an item is selected.
|
This example uses the `@update:model-value` event to reset the search term when an item is selected.
|
||||||
::
|
::
|
||||||
|
|
||||||
|
### With children in items :badge{label="Soon" class="align-text-top"}
|
||||||
|
|
||||||
|
You can create hierarchical menus by using the `children` property in items. When an item has children, it will automatically display a chevron icon and enable navigation into a submenu.
|
||||||
|
|
||||||
|
::component-example
|
||||||
|
---
|
||||||
|
collapse: true
|
||||||
|
prettier: true
|
||||||
|
name: 'command-palette-items-children-example'
|
||||||
|
class: '!p-0'
|
||||||
|
props:
|
||||||
|
autofocus: false
|
||||||
|
---
|
||||||
|
::
|
||||||
|
|
||||||
|
::note
|
||||||
|
When navigating into a submenu:
|
||||||
|
- The search term is reset
|
||||||
|
- A back button appears in the input
|
||||||
|
- You can go back to the previous group by pressing the :kbd{value="backspace"} key
|
||||||
|
::
|
||||||
|
|
||||||
### With fetched items
|
### With fetched items
|
||||||
|
|
||||||
You can fetch items from an API and use them in the CommandPalette.
|
You can fetch items from an API and use them in the CommandPalette.
|
||||||
@@ -658,6 +895,7 @@ You will have access to the following slots:
|
|||||||
|
|
||||||
::component-example
|
::component-example
|
||||||
---
|
---
|
||||||
|
collapse: true
|
||||||
name: 'command-palette-custom-slot-example'
|
name: 'command-palette-custom-slot-example'
|
||||||
class: '!p-0'
|
class: '!p-0'
|
||||||
props:
|
props:
|
||||||
|
|||||||
@@ -74,6 +74,51 @@ const groups = computed(() => [{
|
|||||||
toast.add({ title: 'Label added!' })
|
toast.add({ title: 'Label added!' })
|
||||||
},
|
},
|
||||||
kbds: ['meta', 'L']
|
kbds: ['meta', 'L']
|
||||||
|
}, {
|
||||||
|
label: 'More actions',
|
||||||
|
placeholder: 'Search actions...',
|
||||||
|
children: [{
|
||||||
|
label: 'Create new file',
|
||||||
|
suffix: 'Create a new file in the current directory or workspace.',
|
||||||
|
icon: 'i-lucide-file-plus',
|
||||||
|
onSelect(e: Event) {
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
|
toast.add({ title: 'New file added!' })
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
label: 'Create new folder',
|
||||||
|
suffix: 'Create a new folder in the current directory or workspace.',
|
||||||
|
icon: 'i-lucide-folder-plus',
|
||||||
|
onSelect(e: Event) {
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
|
toast.add({ title: 'New folder added!' })
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
label: 'Share',
|
||||||
|
placeholder: 'Search share options...',
|
||||||
|
icon: 'i-lucide-share',
|
||||||
|
children: [{
|
||||||
|
label: 'Share with everyone',
|
||||||
|
suffix: 'Share with everyone in the current directory or workspace.',
|
||||||
|
icon: 'i-lucide-share',
|
||||||
|
onSelect(e: Event) {
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
|
toast.add({ title: 'Shared with everyone!' })
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
label: 'Share with team',
|
||||||
|
suffix: 'Share with the team in the current directory or workspace.',
|
||||||
|
icon: 'i-lucide-users',
|
||||||
|
onSelect(e: Event) {
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
|
toast.add({ title: 'Shared with team!' })
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}]
|
||||||
}]
|
}]
|
||||||
}])
|
}])
|
||||||
|
|
||||||
|
|||||||
@@ -26,13 +26,18 @@ export interface CommandPaletteItem extends Omit<LinkProps, 'type' | 'raw' | 'cu
|
|||||||
loading?: boolean
|
loading?: boolean
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
slot?: string
|
slot?: string
|
||||||
|
/**
|
||||||
|
* The placeholder to display when the item has children.
|
||||||
|
*/
|
||||||
|
placeholder?: string
|
||||||
|
children?: CommandPaletteItem[]
|
||||||
onSelect?(e?: Event): void
|
onSelect?(e?: Event): void
|
||||||
class?: any
|
class?: any
|
||||||
ui?: Pick<CommandPalette['slots'], 'item' | 'itemLeadingIcon' | 'itemLeadingAvatarSize' | 'itemLeadingAvatar' | 'itemLeadingChipSize' | 'itemLeadingChip' | 'itemLabel' | 'itemLabelPrefix' | 'itemLabelBase' | 'itemLabelSuffix' | 'itemTrailing' | 'itemTrailingKbds' | 'itemTrailingKbdsSize' | 'itemTrailingHighlightedIcon' | 'itemTrailingIcon'>
|
ui?: Pick<CommandPalette['slots'], 'item' | 'itemLeadingIcon' | 'itemLeadingAvatarSize' | 'itemLeadingAvatar' | 'itemLeadingChipSize' | 'itemLeadingChip' | 'itemLabel' | 'itemLabelPrefix' | 'itemLabelBase' | 'itemLabelSuffix' | 'itemTrailing' | 'itemTrailingKbds' | 'itemTrailingKbdsSize' | 'itemTrailingHighlightedIcon' | 'itemTrailingIcon'>
|
||||||
[key: string]: any
|
[key: string]: any
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CommandPaletteGroup<T> {
|
export interface CommandPaletteGroup<T extends CommandPaletteItem = CommandPaletteItem> {
|
||||||
id: string
|
id: string
|
||||||
label?: string
|
label?: string
|
||||||
slot?: string
|
slot?: string
|
||||||
@@ -52,7 +57,7 @@ export interface CommandPaletteGroup<T> {
|
|||||||
highlightedIcon?: string
|
highlightedIcon?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CommandPaletteProps<G, T> extends Pick<ListboxRootProps, 'multiple' | 'disabled' | 'modelValue' | 'defaultValue' | 'highlightOnHover'>, Pick<UseComponentIconsProps, 'loading' | 'loadingIcon'> {
|
export interface CommandPaletteProps<G extends CommandPaletteGroup<T> = CommandPaletteGroup<any>, T extends CommandPaletteItem = CommandPaletteItem> extends Pick<ListboxRootProps, 'multiple' | 'disabled' | 'modelValue' | 'defaultValue' | 'highlightOnHover' | 'selectionBehavior'>, Pick<UseComponentIconsProps, 'loading' | 'loadingIcon'> {
|
||||||
/**
|
/**
|
||||||
* The element or component this component should render as.
|
* The element or component this component should render as.
|
||||||
* @defaultValue 'div'
|
* @defaultValue 'div'
|
||||||
@@ -70,6 +75,12 @@ export interface CommandPaletteProps<G, T> extends Pick<ListboxRootProps, 'multi
|
|||||||
* @IconifyIcon
|
* @IconifyIcon
|
||||||
*/
|
*/
|
||||||
selectedIcon?: string
|
selectedIcon?: string
|
||||||
|
/**
|
||||||
|
* The icon displayed when an item has children.
|
||||||
|
* @defaultValue appConfig.ui.icons.chevronRight
|
||||||
|
* @IconifyIcon
|
||||||
|
*/
|
||||||
|
trailingIcon?: string
|
||||||
/**
|
/**
|
||||||
* The placeholder text for the input.
|
* The placeholder text for the input.
|
||||||
* @defaultValue t('commandPalette.placeholder')
|
* @defaultValue t('commandPalette.placeholder')
|
||||||
@@ -93,6 +104,18 @@ export interface CommandPaletteProps<G, T> extends Pick<ListboxRootProps, 'multi
|
|||||||
* @IconifyIcon
|
* @IconifyIcon
|
||||||
*/
|
*/
|
||||||
closeIcon?: string
|
closeIcon?: string
|
||||||
|
/**
|
||||||
|
* Display a button to navigate back in history.
|
||||||
|
* `{ size: 'md', color: 'neutral', variant: 'link' }`{lang="ts-type"}
|
||||||
|
* @defaultValue true
|
||||||
|
*/
|
||||||
|
back?: boolean | ButtonProps
|
||||||
|
/**
|
||||||
|
* The icon displayed in the back button.
|
||||||
|
* @defaultValue appConfig.ui.icons.arrowLeft
|
||||||
|
* @IconifyIcon
|
||||||
|
*/
|
||||||
|
backIcon?: string
|
||||||
groups?: G[]
|
groups?: G[]
|
||||||
/**
|
/**
|
||||||
* Options for [useFuse](https://vueuse.org/integrations/useFuse).
|
* Options for [useFuse](https://vueuse.org/integrations/useFuse).
|
||||||
@@ -116,14 +139,15 @@ export interface CommandPaletteProps<G, T> extends Pick<ListboxRootProps, 'multi
|
|||||||
ui?: CommandPalette['slots']
|
ui?: CommandPalette['slots']
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CommandPaletteEmits<T> = ListboxRootEmits<T> & {
|
export type CommandPaletteEmits<T extends CommandPaletteItem = CommandPaletteItem> = ListboxRootEmits<T> & {
|
||||||
'update:open': [value: boolean]
|
'update:open': [value: boolean]
|
||||||
}
|
}
|
||||||
|
|
||||||
type SlotProps<T> = (props: { item: T, index: number }) => any
|
type SlotProps<T> = (props: { item: T, index: number }) => any
|
||||||
|
|
||||||
export type CommandPaletteSlots<G extends { slot?: string }, T extends { slot?: string }> = {
|
export type CommandPaletteSlots<G extends CommandPaletteGroup<T> = CommandPaletteGroup<any>, T extends CommandPaletteItem = CommandPaletteItem> = {
|
||||||
'empty'(props: { searchTerm?: string }): any
|
'empty'(props: { searchTerm?: string }): any
|
||||||
|
'back'(props: { ui: { [K in keyof Required<CommandPalette['slots']>]: (props?: Record<string, any>) => string } }): any
|
||||||
'close'(props: { ui: { [K in keyof Required<CommandPalette['slots']>]: (props?: Record<string, any>) => string } }): any
|
'close'(props: { ui: { [K in keyof Required<CommandPalette['slots']>]: (props?: Record<string, any>) => string } }): any
|
||||||
'item': SlotProps<T>
|
'item': SlotProps<T>
|
||||||
'item-leading': SlotProps<T>
|
'item-leading': SlotProps<T>
|
||||||
@@ -134,7 +158,7 @@ export type CommandPaletteSlots<G extends { slot?: string }, T extends { slot?:
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script setup lang="ts" generic="G extends CommandPaletteGroup<T>, T extends CommandPaletteItem">
|
<script setup lang="ts" generic="G extends CommandPaletteGroup<T>, T extends CommandPaletteItem">
|
||||||
import { computed } from 'vue'
|
import { computed, ref, useTemplateRef } from 'vue'
|
||||||
import { ListboxRoot, ListboxFilter, ListboxContent, ListboxGroup, ListboxGroupLabel, ListboxItem, ListboxItemIndicator, useForwardProps, useForwardPropsEmits } from 'reka-ui'
|
import { ListboxRoot, ListboxFilter, ListboxContent, ListboxGroup, ListboxGroupLabel, ListboxItem, ListboxItemIndicator, useForwardProps, useForwardPropsEmits } from 'reka-ui'
|
||||||
import { defu } from 'defu'
|
import { defu } from 'defu'
|
||||||
import { reactivePick } from '@vueuse/core'
|
import { reactivePick } from '@vueuse/core'
|
||||||
@@ -157,7 +181,8 @@ import UKbd from './Kbd.vue'
|
|||||||
const props = withDefaults(defineProps<CommandPaletteProps<G, T>>(), {
|
const props = withDefaults(defineProps<CommandPaletteProps<G, T>>(), {
|
||||||
modelValue: '',
|
modelValue: '',
|
||||||
labelKey: 'label',
|
labelKey: 'label',
|
||||||
autofocus: true
|
autofocus: true,
|
||||||
|
back: true
|
||||||
})
|
})
|
||||||
const emits = defineEmits<CommandPaletteEmits<T>>()
|
const emits = defineEmits<CommandPaletteEmits<T>>()
|
||||||
const slots = defineSlots<CommandPaletteSlots<G, T>>()
|
const slots = defineSlots<CommandPaletteSlots<G, T>>()
|
||||||
@@ -167,7 +192,7 @@ const searchTerm = defineModel<string>('searchTerm', { default: '' })
|
|||||||
const { t } = useLocale()
|
const { t } = useLocale()
|
||||||
const appConfig = useAppConfig() as CommandPalette['AppConfig']
|
const appConfig = useAppConfig() as CommandPalette['AppConfig']
|
||||||
|
|
||||||
const rootProps = useForwardPropsEmits(reactivePick(props, 'as', 'disabled', 'multiple', 'modelValue', 'defaultValue', 'highlightOnHover'), emits)
|
const rootProps = useForwardPropsEmits(reactivePick(props, 'as', 'disabled', 'multiple', 'modelValue', 'defaultValue', 'highlightOnHover', 'selectionBehavior'), emits)
|
||||||
const inputProps = useForwardProps(reactivePick(props, 'loading', 'loadingIcon'))
|
const inputProps = useForwardProps(reactivePick(props, 'loading', 'loadingIcon'))
|
||||||
|
|
||||||
// eslint-disable-next-line vue/no-dupe-keys
|
// eslint-disable-next-line vue/no-dupe-keys
|
||||||
@@ -183,18 +208,22 @@ const fuse = computed(() => defu({}, props.fuse, {
|
|||||||
matchAllWhenSearchEmpty: true
|
matchAllWhenSearchEmpty: true
|
||||||
}))
|
}))
|
||||||
|
|
||||||
const items = computed(() => props.groups?.filter((group) => {
|
const history = ref<(CommandPaletteGroup & { placeholder?: string })[]>([])
|
||||||
|
|
||||||
|
const placeholder = computed(() => history.value[history.value.length - 1]?.placeholder || props.placeholder || t('commandPalette.placeholder'))
|
||||||
|
|
||||||
|
const groups = computed(() => history.value?.length ? [history.value[history.value.length - 1] as G] : props.groups)
|
||||||
|
|
||||||
|
const items = computed(() => groups.value?.filter((group) => {
|
||||||
if (!group.id) {
|
if (!group.id) {
|
||||||
console.warn(`[@nuxt/ui] CommandPalette group is missing an \`id\` property`)
|
console.warn(`[@nuxt/ui] CommandPalette group is missing an \`id\` property`)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if (group.ignoreFilter) {
|
if (group.ignoreFilter) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}).flatMap(group => group.items?.map(item => ({ ...item, group: group.id })) || []) || [])
|
})?.flatMap(group => group.items?.map(item => ({ ...item, group: group.id })) || []) || [])
|
||||||
|
|
||||||
const { results: fuseResults } = useFuse<typeof items.value[number]>(searchTerm, items, fuse)
|
const { results: fuseResults } = useFuse<typeof items.value[number]>(searchTerm, items, fuse)
|
||||||
|
|
||||||
@@ -215,7 +244,7 @@ function getGroupWithItems(group: G, items: (T & { matches?: FuseResult<T>['matc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const groups = computed(() => {
|
const filteredGroups = computed(() => {
|
||||||
const groupsById = fuseResults.value.reduce((acc, result) => {
|
const groupsById = fuseResults.value.reduce((acc, result) => {
|
||||||
const { item, matches } = result
|
const { item, matches } = result
|
||||||
if (!item.group) {
|
if (!item.group) {
|
||||||
@@ -229,7 +258,7 @@ const groups = computed(() => {
|
|||||||
}, {} as Record<string, (T & { matches?: FuseResult<T>['matches'] })[]>)
|
}, {} as Record<string, (T & { matches?: FuseResult<T>['matches'] })[]>)
|
||||||
|
|
||||||
const fuseGroups = Object.entries(groupsById).map(([id, items]) => {
|
const fuseGroups = Object.entries(groupsById).map(([id, items]) => {
|
||||||
const group = props.groups?.find(group => group.id === id)
|
const group = groups.value?.find(group => group.id === id)
|
||||||
if (!group) {
|
if (!group) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -237,7 +266,7 @@ const groups = computed(() => {
|
|||||||
return getGroupWithItems(group, items)
|
return getGroupWithItems(group, items)
|
||||||
}).filter(group => !!group)
|
}).filter(group => !!group)
|
||||||
|
|
||||||
const nonFuseGroups = props.groups
|
const nonFuseGroups = groups.value
|
||||||
?.map((group, index) => ({ ...group, index }))
|
?.map((group, index) => ({ ...group, index }))
|
||||||
?.filter(group => group.ignoreFilter && group.items?.length)
|
?.filter(group => group.ignoreFilter && group.items?.length)
|
||||||
?.map(group => ({ ...getGroupWithItems(group, group.items || []), index: group.index })) || []
|
?.map(group => ({ ...getGroupWithItems(group, group.items || []), index: group.index })) || []
|
||||||
@@ -247,20 +276,84 @@ const groups = computed(() => {
|
|||||||
return acc
|
return acc
|
||||||
}, [...fuseGroups])
|
}, [...fuseGroups])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const listboxRootRef = useTemplateRef('listboxRootRef')
|
||||||
|
|
||||||
|
function navigate(item: T) {
|
||||||
|
if (!item.children?.length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
history.value.push({
|
||||||
|
id: `history-${history.value.length}`,
|
||||||
|
label: item.label,
|
||||||
|
slot: item.slot,
|
||||||
|
placeholder: item.placeholder,
|
||||||
|
items: item.children
|
||||||
|
} as any)
|
||||||
|
|
||||||
|
searchTerm.value = ''
|
||||||
|
|
||||||
|
listboxRootRef.value?.highlightFirstItem()
|
||||||
|
}
|
||||||
|
|
||||||
|
function navigateBack() {
|
||||||
|
if (!history.value.length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
history.value.pop()
|
||||||
|
|
||||||
|
searchTerm.value = ''
|
||||||
|
|
||||||
|
listboxRootRef.value?.highlightFirstItem()
|
||||||
|
}
|
||||||
|
|
||||||
|
function onBackspace() {
|
||||||
|
if (!searchTerm.value) {
|
||||||
|
navigateBack()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onSelect(e: Event, item: T) {
|
||||||
|
if (item.children?.length) {
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
|
navigate(item)
|
||||||
|
} else {
|
||||||
|
item.onSelect?.(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<!-- eslint-disable vue/no-v-html -->
|
<!-- eslint-disable vue/no-v-html -->
|
||||||
<template>
|
<template>
|
||||||
<ListboxRoot v-bind="rootProps" :class="ui.root({ class: [props.ui?.root, props.class] })">
|
<ListboxRoot v-bind="rootProps" ref="listboxRootRef" :class="ui.root({ class: [props.ui?.root, props.class] })">
|
||||||
<ListboxFilter v-model="searchTerm" as-child>
|
<ListboxFilter v-model="searchTerm" as-child>
|
||||||
<UInput
|
<UInput
|
||||||
:placeholder="placeholder || t('commandPalette.placeholder')"
|
:placeholder="placeholder"
|
||||||
variant="none"
|
variant="none"
|
||||||
:autofocus="autofocus"
|
:autofocus="autofocus"
|
||||||
v-bind="inputProps"
|
v-bind="inputProps"
|
||||||
:icon="icon || appConfig.ui.icons.search"
|
:icon="icon || appConfig.ui.icons.search"
|
||||||
:class="ui.input({ class: props.ui?.input })"
|
:class="ui.input({ class: props.ui?.input })"
|
||||||
|
@keydown.backspace="onBackspace"
|
||||||
>
|
>
|
||||||
|
<template v-if="history?.length && (back || !!slots.back)" #leading>
|
||||||
|
<slot name="back" :ui="ui">
|
||||||
|
<UButton
|
||||||
|
:icon="backIcon || appConfig.ui.icons.arrowLeft"
|
||||||
|
size="md"
|
||||||
|
color="neutral"
|
||||||
|
variant="link"
|
||||||
|
:aria-label="t('commandPalette.back')"
|
||||||
|
v-bind="(typeof back === 'object' ? back as Partial<ButtonProps> : {})"
|
||||||
|
:class="ui.back({ class: props.ui?.back })"
|
||||||
|
@click="navigateBack"
|
||||||
|
/>
|
||||||
|
</slot>
|
||||||
|
</template>
|
||||||
|
|
||||||
<template v-if="close || !!slots.close" #trailing>
|
<template v-if="close || !!slots.close" #trailing>
|
||||||
<slot name="close" :ui="ui">
|
<slot name="close" :ui="ui">
|
||||||
<UButton
|
<UButton
|
||||||
@@ -280,8 +373,8 @@ const groups = computed(() => {
|
|||||||
</ListboxFilter>
|
</ListboxFilter>
|
||||||
|
|
||||||
<ListboxContent :class="ui.content({ class: props.ui?.content })">
|
<ListboxContent :class="ui.content({ class: props.ui?.content })">
|
||||||
<div v-if="groups?.length" role="presentation" :class="ui.viewport({ class: props.ui?.viewport })">
|
<div v-if="filteredGroups?.length" role="presentation" :class="ui.viewport({ class: props.ui?.viewport })">
|
||||||
<ListboxGroup v-for="group in groups" :key="`group-${group.id}`" :class="ui.group({ class: props.ui?.group })">
|
<ListboxGroup v-for="group in filteredGroups" :key="`group-${group.id}`" :class="ui.group({ class: props.ui?.group })">
|
||||||
<ListboxGroupLabel v-if="get(group, props.labelKey as string)" :class="ui.label({ class: props.ui?.label })">
|
<ListboxGroupLabel v-if="get(group, props.labelKey as string)" :class="ui.label({ class: props.ui?.label })">
|
||||||
{{ get(group, props.labelKey as string) }}
|
{{ get(group, props.labelKey as string) }}
|
||||||
</ListboxGroupLabel>
|
</ListboxGroupLabel>
|
||||||
@@ -289,10 +382,10 @@ const groups = computed(() => {
|
|||||||
<ListboxItem
|
<ListboxItem
|
||||||
v-for="(item, index) in group.items"
|
v-for="(item, index) in group.items"
|
||||||
:key="`group-${group.id}-${index}`"
|
:key="`group-${group.id}-${index}`"
|
||||||
:value="omit(item, ['matches' as any, 'group' as any, 'onSelect', 'labelHtml', 'suffixHtml'])"
|
:value="omit(item, ['matches' as any, 'group' as any, 'onSelect', 'labelHtml', 'suffixHtml', 'children'])"
|
||||||
:disabled="item.disabled"
|
:disabled="item.disabled"
|
||||||
as-child
|
as-child
|
||||||
@select="item.onSelect"
|
@select="onSelect($event, item)"
|
||||||
>
|
>
|
||||||
<ULink v-slot="{ active, ...slotProps }" v-bind="pickLinkProps(item)" custom>
|
<ULink v-slot="{ active, ...slotProps }" v-bind="pickLinkProps(item)" custom>
|
||||||
<ULinkBase v-bind="slotProps" :class="ui.item({ class: [props.ui?.item, item.ui?.item, item.class], active: active || item.active })">
|
<ULinkBase v-bind="slotProps" :class="ui.item({ class: [props.ui?.item, item.ui?.item, item.class], active: active || item.active })">
|
||||||
@@ -323,13 +416,20 @@ const groups = computed(() => {
|
|||||||
|
|
||||||
<span :class="ui.itemTrailing({ class: [props.ui?.itemTrailing, item.ui?.itemTrailing] })">
|
<span :class="ui.itemTrailing({ class: [props.ui?.itemTrailing, item.ui?.itemTrailing] })">
|
||||||
<slot :name="((item.slot ? `${item.slot}-trailing` : group.slot ? `${group.slot}-trailing` : `item-trailing`) as keyof CommandPaletteSlots<G, T>)" :item="(item as any)" :index="index">
|
<slot :name="((item.slot ? `${item.slot}-trailing` : group.slot ? `${group.slot}-trailing` : `item-trailing`) as keyof CommandPaletteSlots<G, T>)" :item="(item as any)" :index="index">
|
||||||
<span v-if="item.kbds?.length" :class="ui.itemTrailingKbds({ class: [props.ui?.itemTrailingKbds, item.ui?.itemTrailingKbds] })">
|
<UIcon
|
||||||
|
v-if="item.children && item.children.length > 0"
|
||||||
|
:name="trailingIcon || appConfig.ui.icons.chevronRight"
|
||||||
|
:class="ui.itemTrailingIcon({ class: [props.ui?.itemTrailingIcon, item.ui?.itemTrailingIcon] })"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<span v-else-if="item.kbds?.length" :class="ui.itemTrailingKbds({ class: [props.ui?.itemTrailingKbds, item.ui?.itemTrailingKbds] })">
|
||||||
<UKbd v-for="(kbd, kbdIndex) in item.kbds" :key="kbdIndex" :size="((item.ui?.itemTrailingKbdsSize || props.ui?.itemTrailingKbdsSize || ui.itemTrailingKbdsSize()) as KbdProps['size'])" v-bind="typeof kbd === 'string' ? { value: kbd } : kbd" />
|
<UKbd v-for="(kbd, kbdIndex) in item.kbds" :key="kbdIndex" :size="((item.ui?.itemTrailingKbdsSize || props.ui?.itemTrailingKbdsSize || ui.itemTrailingKbdsSize()) as KbdProps['size'])" v-bind="typeof kbd === 'string' ? { value: kbd } : kbd" />
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<UIcon v-else-if="group.highlightedIcon" :name="group.highlightedIcon" :class="ui.itemTrailingHighlightedIcon({ class: [props.ui?.itemTrailingHighlightedIcon, item.ui?.itemTrailingHighlightedIcon] })" />
|
<UIcon v-else-if="group.highlightedIcon" :name="group.highlightedIcon" :class="ui.itemTrailingHighlightedIcon({ class: [props.ui?.itemTrailingHighlightedIcon, item.ui?.itemTrailingHighlightedIcon] })" />
|
||||||
</slot>
|
</slot>
|
||||||
|
|
||||||
<ListboxItemIndicator as-child>
|
<ListboxItemIndicator v-if="!item.children?.length" as-child>
|
||||||
<UIcon :name="selectedIcon || appConfig.ui.icons.check" :class="ui.itemTrailingIcon({ class: [props.ui?.itemTrailingIcon, item.ui?.itemTrailingIcon] })" />
|
<UIcon :name="selectedIcon || appConfig.ui.icons.check" :class="ui.itemTrailingIcon({ class: [props.ui?.itemTrailingIcon, item.ui?.itemTrailingIcon] })" />
|
||||||
</ListboxItemIndicator>
|
</ListboxItemIndicator>
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -61,13 +61,13 @@ export type TableRow<T> = Row<T>
|
|||||||
export type TableData = RowData
|
export type TableData = RowData
|
||||||
export type TableColumn<T extends TableData, D = unknown> = ColumnDef<T, D>
|
export type TableColumn<T extends TableData, D = unknown> = ColumnDef<T, D>
|
||||||
|
|
||||||
export interface TableOptions<T extends TableData> extends Omit<CoreOptions<T>, 'data' | 'columns' | 'getCoreRowModel' | 'state' | 'onStateChange' | 'renderFallbackValue'> {
|
export interface TableOptions<T extends TableData = TableData> extends Omit<CoreOptions<T>, 'data' | 'columns' | 'getCoreRowModel' | 'state' | 'onStateChange' | 'renderFallbackValue'> {
|
||||||
state?: CoreOptions<T>['state']
|
state?: CoreOptions<T>['state']
|
||||||
onStateChange?: CoreOptions<T>['onStateChange']
|
onStateChange?: CoreOptions<T>['onStateChange']
|
||||||
renderFallbackValue?: CoreOptions<T>['renderFallbackValue']
|
renderFallbackValue?: CoreOptions<T>['renderFallbackValue']
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TableProps<T extends TableData> extends TableOptions<T> {
|
export interface TableProps<T extends TableData = TableData> extends TableOptions<T> {
|
||||||
/**
|
/**
|
||||||
* The element or component this component should render as.
|
* The element or component this component should render as.
|
||||||
* @defaultValue 'div'
|
* @defaultValue 'div'
|
||||||
@@ -172,7 +172,7 @@ export interface TableProps<T extends TableData> extends TableOptions<T> {
|
|||||||
type DynamicHeaderSlots<T, K = keyof T> = Record<string, (props: HeaderContext<T, unknown>) => any> & Record<`${K extends string ? K : never}-header`, (props: HeaderContext<T, unknown>) => any>
|
type DynamicHeaderSlots<T, K = keyof T> = Record<string, (props: HeaderContext<T, unknown>) => any> & Record<`${K extends string ? K : never}-header`, (props: HeaderContext<T, unknown>) => any>
|
||||||
type DynamicCellSlots<T, K = keyof T> = Record<string, (props: CellContext<T, unknown>) => any> & Record<`${K extends string ? K : never}-cell`, (props: CellContext<T, unknown>) => any>
|
type DynamicCellSlots<T, K = keyof T> = Record<string, (props: CellContext<T, unknown>) => any> & Record<`${K extends string ? K : never}-cell`, (props: CellContext<T, unknown>) => any>
|
||||||
|
|
||||||
export type TableSlots<T> = {
|
export type TableSlots<T extends TableData = TableData> = {
|
||||||
expanded: (props: { row: Row<T> }) => any
|
expanded: (props: { row: Row<T> }) => any
|
||||||
empty: (props?: {}) => any
|
empty: (props?: {}) => any
|
||||||
loading: (props?: {}) => any
|
loading: (props?: {}) => any
|
||||||
|
|||||||
@@ -25,7 +25,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'اكتب أمرًا أو ابحث...',
|
placeholder: 'اكتب أمرًا أو ابحث...',
|
||||||
noMatch: 'لا توجد نتائج مطابقة',
|
noMatch: 'لا توجد نتائج مطابقة',
|
||||||
noData: 'لا توجد بيانات',
|
noData: 'لا توجد بيانات',
|
||||||
close: 'إغلاق'
|
close: 'إغلاق',
|
||||||
|
back: 'رجوع'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'لا توجد نتائج مطابقة',
|
noMatch: 'لا توجد نتائج مطابقة',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'Əmr daxil edin və ya axtarın...',
|
placeholder: 'Əmr daxil edin və ya axtarın...',
|
||||||
noMatch: 'Uyğun məlumat tapılmadı',
|
noMatch: 'Uyğun məlumat tapılmadı',
|
||||||
noData: 'Məlumat yoxdur',
|
noData: 'Məlumat yoxdur',
|
||||||
close: 'Bağla'
|
close: 'Bağla',
|
||||||
|
back: 'Geri'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'Uyğun məlumat tapılmadı',
|
noMatch: 'Uyğun məlumat tapılmadı',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'Въведете команда или потърсете...',
|
placeholder: 'Въведете команда или потърсете...',
|
||||||
noMatch: 'Няма съвпадение на данни',
|
noMatch: 'Няма съвпадение на данни',
|
||||||
noData: 'Няма данни',
|
noData: 'Няма данни',
|
||||||
close: 'Затворете'
|
close: 'Затворете',
|
||||||
|
back: 'Назад'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'Няма съвпадение на данни',
|
noMatch: 'Няма съвпадение на данни',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'কমান্ড টাইপ করুন বা অনুসন্ধান করুন...',
|
placeholder: 'কমান্ড টাইপ করুন বা অনুসন্ধান করুন...',
|
||||||
noMatch: 'কোন মিল পাওয়া যায়নি',
|
noMatch: 'কোন মিল পাওয়া যায়নি',
|
||||||
noData: 'কোন তথ্য নেই',
|
noData: 'কোন তথ্য নেই',
|
||||||
close: 'বন্ধ করুন'
|
close: 'বন্ধ করুন',
|
||||||
|
back: 'পেছনে'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'কোন মিল পাওয়া যায়নি',
|
noMatch: 'কোন মিল পাওয়া যায়নি',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'Escriu una ordre o cerca...',
|
placeholder: 'Escriu una ordre o cerca...',
|
||||||
noMatch: 'No hi ha dades coincidents',
|
noMatch: 'No hi ha dades coincidents',
|
||||||
noData: 'Sense dades',
|
noData: 'Sense dades',
|
||||||
close: 'Tancar'
|
close: 'Tancar',
|
||||||
|
back: 'Enrere'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'No hi ha dades coincidents',
|
noMatch: 'No hi ha dades coincidents',
|
||||||
|
|||||||
@@ -25,7 +25,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'فەرمانێک بنووسە یان بگەڕێ...',
|
placeholder: 'فەرمانێک بنووسە یان بگەڕێ...',
|
||||||
noMatch: 'هیچ ئەنجامێک نەدۆزرایەوە',
|
noMatch: 'هیچ ئەنجامێک نەدۆزرایەوە',
|
||||||
noData: 'هیچ داتایەک نییە',
|
noData: 'هیچ داتایەک نییە',
|
||||||
close: 'داخستن'
|
close: 'داخستن',
|
||||||
|
back: 'گەڕانەوە'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'هیچ ئەنجامێک نەدۆزرایەوە',
|
noMatch: 'هیچ ئەنجامێک نەدۆزرایەوە',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'Zadejte příkaz nebo hledejte...',
|
placeholder: 'Zadejte příkaz nebo hledejte...',
|
||||||
noMatch: 'Žádná shoda',
|
noMatch: 'Žádná shoda',
|
||||||
noData: 'Žádná data',
|
noData: 'Žádná data',
|
||||||
close: 'Zavřít'
|
close: 'Zavřít',
|
||||||
|
back: 'Zpět'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'Žádná shoda',
|
noMatch: 'Žádná shoda',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'Skriv en kommando eller søg...',
|
placeholder: 'Skriv en kommando eller søg...',
|
||||||
noMatch: 'Ingen matchende data',
|
noMatch: 'Ingen matchende data',
|
||||||
noData: 'Ingen data',
|
noData: 'Ingen data',
|
||||||
close: 'Luk'
|
close: 'Luk',
|
||||||
|
back: 'Tilbage'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'Ingen matchende data',
|
noMatch: 'Ingen matchende data',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'Geben Sie einen Befehl ein oder suchen Sie...',
|
placeholder: 'Geben Sie einen Befehl ein oder suchen Sie...',
|
||||||
noMatch: 'Nichts gefunden',
|
noMatch: 'Nichts gefunden',
|
||||||
noData: 'Keine Daten',
|
noData: 'Keine Daten',
|
||||||
close: 'Schließen'
|
close: 'Schließen',
|
||||||
|
back: 'Zurück'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'Nichts gefunden',
|
noMatch: 'Nichts gefunden',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'Πληκτρολογήστε μια εντολή ή αναζητήστε...',
|
placeholder: 'Πληκτρολογήστε μια εντολή ή αναζητήστε...',
|
||||||
noMatch: 'Δεν βρέθηκαν δεδομένα',
|
noMatch: 'Δεν βρέθηκαν δεδομένα',
|
||||||
noData: 'Δεν υπάρχουν δεδομένα',
|
noData: 'Δεν υπάρχουν δεδομένα',
|
||||||
close: 'Κλείσιμο'
|
close: 'Κλείσιμο',
|
||||||
|
back: 'Πίσω'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'Δεν βρέθηκαν δεδομένα',
|
noMatch: 'Δεν βρέθηκαν δεδομένα',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'Type a command or search...',
|
placeholder: 'Type a command or search...',
|
||||||
noMatch: 'No matching data',
|
noMatch: 'No matching data',
|
||||||
noData: 'No data',
|
noData: 'No data',
|
||||||
close: 'Close'
|
close: 'Close',
|
||||||
|
back: 'Back'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'No matching data',
|
noMatch: 'No matching data',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'Escribe un comando o busca...',
|
placeholder: 'Escribe un comando o busca...',
|
||||||
noMatch: 'No hay datos coincidentes',
|
noMatch: 'No hay datos coincidentes',
|
||||||
noData: 'Sin datos',
|
noData: 'Sin datos',
|
||||||
close: 'Cerrar'
|
close: 'Cerrar',
|
||||||
|
back: 'Atrás'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'No hay datos coincidentes',
|
noMatch: 'No hay datos coincidentes',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'Sisesta käsk või otsi...',
|
placeholder: 'Sisesta käsk või otsi...',
|
||||||
noMatch: 'Pole vastavaid andmeid',
|
noMatch: 'Pole vastavaid andmeid',
|
||||||
noData: 'Pole andmeid',
|
noData: 'Pole andmeid',
|
||||||
close: 'Sulge'
|
close: 'Sulge',
|
||||||
|
back: 'Tagasi'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'Pole vastavaid andmeid',
|
noMatch: 'Pole vastavaid andmeid',
|
||||||
|
|||||||
@@ -25,7 +25,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'یک دستور وارد کنید یا جستجو کنید...',
|
placeholder: 'یک دستور وارد کنید یا جستجو کنید...',
|
||||||
noMatch: 'دادهای یافت نشد',
|
noMatch: 'دادهای یافت نشد',
|
||||||
noData: 'دادهای موجود نیست',
|
noData: 'دادهای موجود نیست',
|
||||||
close: 'بستن'
|
close: 'بستن',
|
||||||
|
back: 'بازگشت'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'دادهای یافت نشد',
|
noMatch: 'دادهای یافت نشد',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'Kirjoita komento tai hae...',
|
placeholder: 'Kirjoita komento tai hae...',
|
||||||
noMatch: 'Ei vastaavia tietoja',
|
noMatch: 'Ei vastaavia tietoja',
|
||||||
noData: 'Ei tietoja',
|
noData: 'Ei tietoja',
|
||||||
close: 'Sulje'
|
close: 'Sulje',
|
||||||
|
back: 'Takaisin'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'Ei vastaavia tietoja',
|
noMatch: 'Ei vastaavia tietoja',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'Tapez une commande ou recherchez...',
|
placeholder: 'Tapez une commande ou recherchez...',
|
||||||
noMatch: 'Aucune donnée correspondante',
|
noMatch: 'Aucune donnée correspondante',
|
||||||
noData: 'Aucune donnée',
|
noData: 'Aucune donnée',
|
||||||
close: 'Fermer'
|
close: 'Fermer',
|
||||||
|
back: 'Retour'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'Aucune donnée correspondante',
|
noMatch: 'Aucune donnée correspondante',
|
||||||
|
|||||||
@@ -25,7 +25,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'הקלד פקודה...',
|
placeholder: 'הקלד פקודה...',
|
||||||
noMatch: 'לא נמצאה התאמה',
|
noMatch: 'לא נמצאה התאמה',
|
||||||
noData: 'אין נתונים זמינים',
|
noData: 'אין נתונים זמינים',
|
||||||
close: 'סגור'
|
close: 'סגור',
|
||||||
|
back: 'חזור'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'לא נמצאה התאמה',
|
noMatch: 'לא נמצאה התאמה',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'एक आदेश या खोज टाइप करें...',
|
placeholder: 'एक आदेश या खोज टाइप करें...',
|
||||||
noMatch: 'कोई मेल खाता डेटा नहीं',
|
noMatch: 'कोई मेल खाता डेटा नहीं',
|
||||||
noData: 'कोई डेटा नहीं',
|
noData: 'कोई डेटा नहीं',
|
||||||
close: 'बंद करें'
|
close: 'बंद करें',
|
||||||
|
back: 'वापस'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'कोई मेल खाता डेटा नहीं',
|
noMatch: 'कोई मेल खाता डेटा नहीं',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'Írjon be egy parancsot vagy keressen...',
|
placeholder: 'Írjon be egy parancsot vagy keressen...',
|
||||||
noMatch: 'Nincs találat',
|
noMatch: 'Nincs találat',
|
||||||
noData: 'Nincs adat',
|
noData: 'Nincs adat',
|
||||||
close: 'Bezárás'
|
close: 'Bezárás',
|
||||||
|
back: 'Vissza'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'Nincs találat',
|
noMatch: 'Nincs találat',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'Մուտքագրեք հրաման կամ որոնեք...',
|
placeholder: 'Մուտքագրեք հրաման կամ որոնեք...',
|
||||||
noMatch: 'Համընկնումներ չեն գտնվել',
|
noMatch: 'Համընկնումներ չեն գտնվել',
|
||||||
noData: 'Տվյալներ չկան',
|
noData: 'Տվյալներ չկան',
|
||||||
close: 'Փակել'
|
close: 'Փակել',
|
||||||
|
back: 'Հետ'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'Համընկնումներ չեն գտնվել',
|
noMatch: 'Համընկնումներ չեն գտնվել',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'Ketik perintah atau cari...',
|
placeholder: 'Ketik perintah atau cari...',
|
||||||
noMatch: 'Tidak ada data yang cocok',
|
noMatch: 'Tidak ada data yang cocok',
|
||||||
noData: 'Tidak ada data',
|
noData: 'Tidak ada data',
|
||||||
close: 'Tutup'
|
close: 'Tutup',
|
||||||
|
back: 'Kembali'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'Tidak ada data yang cocok',
|
noMatch: 'Tidak ada data yang cocok',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'Digita un comando o cerca...',
|
placeholder: 'Digita un comando o cerca...',
|
||||||
noMatch: 'Nessun dato corrispondente',
|
noMatch: 'Nessun dato corrispondente',
|
||||||
noData: 'Nessun dato',
|
noData: 'Nessun dato',
|
||||||
close: 'Chiudi'
|
close: 'Chiudi',
|
||||||
|
back: 'Indietro'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'Nessun dato corrispondente',
|
noMatch: 'Nessun dato corrispondente',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'コマンドを入力するか検索...',
|
placeholder: 'コマンドを入力するか検索...',
|
||||||
noMatch: '一致するデータがありません',
|
noMatch: '一致するデータがありません',
|
||||||
noData: 'データがありません',
|
noData: 'データがありません',
|
||||||
close: '閉じる'
|
close: '閉じる',
|
||||||
|
back: '戻る'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: '一致するデータがありません',
|
noMatch: '一致するデータがありません',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'Команда енгізіңіз немесе іздеңіз...',
|
placeholder: 'Команда енгізіңіз немесе іздеңіз...',
|
||||||
noMatch: 'Сәйкес келетін деректер жоқ',
|
noMatch: 'Сәйкес келетін деректер жоқ',
|
||||||
noData: 'Деректер жоқ',
|
noData: 'Деректер жоқ',
|
||||||
close: 'Жабу'
|
close: 'Жабу',
|
||||||
|
back: 'Артқа'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'Сәйкес келетін деректер жоқ',
|
noMatch: 'Сәйкес келетін деректер жоқ',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'វាយពាក្យបញ្ជា ឬស្វែងរក...',
|
placeholder: 'វាយពាក្យបញ្ជា ឬស្វែងរក...',
|
||||||
noMatch: 'មិនមានទិន្នន័យដែលត្រូវគ្នាទេ',
|
noMatch: 'មិនមានទិន្នន័យដែលត្រូវគ្នាទេ',
|
||||||
noData: 'មិនមានទិន្នន័យ',
|
noData: 'មិនមានទិន្នន័យ',
|
||||||
close: 'បិទ'
|
close: 'បិទ',
|
||||||
|
back: 'ត្រឡប់'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'មិនមានទិន្នន័យដែលត្រូវគ្នាទេ',
|
noMatch: 'មិនមានទិន្នន័យដែលត្រូវគ្នាទេ',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: '명령을 입력하거나 검색...',
|
placeholder: '명령을 입력하거나 검색...',
|
||||||
noMatch: '일치하는 데이터가 없습니다.',
|
noMatch: '일치하는 데이터가 없습니다.',
|
||||||
noData: '데이터가 없습니다.',
|
noData: '데이터가 없습니다.',
|
||||||
close: '닫기'
|
close: '닫기',
|
||||||
|
back: '뒤로'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: '일치하는 데이터가 없습니다.',
|
noMatch: '일치하는 데이터가 없습니다.',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'Буйрук киргизиңиз же издөө…',
|
placeholder: 'Буйрук киргизиңиз же издөө…',
|
||||||
noMatch: 'Эч нерсе табылган жок',
|
noMatch: 'Эч нерсе табылган жок',
|
||||||
noData: 'Маалымат жок',
|
noData: 'Маалымат жок',
|
||||||
close: 'Жабуу'
|
close: 'Жабуу',
|
||||||
|
back: 'Артка'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'Сүйлөшкөн маалыматтар жок',
|
noMatch: 'Сүйлөшкөн маалыматтар жок',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'Tippt e Befeel oder sicht...',
|
placeholder: 'Tippt e Befeel oder sicht...',
|
||||||
noMatch: 'Keng entspriechend Donnéeën',
|
noMatch: 'Keng entspriechend Donnéeën',
|
||||||
noData: 'Keng Donnéeën',
|
noData: 'Keng Donnéeën',
|
||||||
close: 'Zoumaachen'
|
close: 'Zoumaachen',
|
||||||
|
back: 'Zréck'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'Keng entspriechend Donnéeën',
|
noMatch: 'Keng entspriechend Donnéeën',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'Įveskite komandą arba ieškokite...',
|
placeholder: 'Įveskite komandą arba ieškokite...',
|
||||||
noMatch: 'Nėra atitinkančių duomenų',
|
noMatch: 'Nėra atitinkančių duomenų',
|
||||||
noData: 'Nėra duomenų',
|
noData: 'Nėra duomenų',
|
||||||
close: 'Uždaryti'
|
close: 'Uždaryti',
|
||||||
|
back: 'Atgal'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'Nėra atitinkančių duomenų',
|
noMatch: 'Nėra atitinkančių duomenų',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'Комманд бичих эсвэл хайлт хийх...',
|
placeholder: 'Комманд бичих эсвэл хайлт хийх...',
|
||||||
noMatch: 'Тохирох мэдээлэл олдсонгүй',
|
noMatch: 'Тохирох мэдээлэл олдсонгүй',
|
||||||
noData: 'Мэдээлэл байхгүй',
|
noData: 'Мэдээлэл байхгүй',
|
||||||
close: 'Хаах'
|
close: 'Хаах',
|
||||||
|
back: 'Буцах'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'Тохирох мэдээлэл олдсонгүй',
|
noMatch: 'Тохирох мэдээлэл олдсонгүй',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'Taip arahan atau carian...',
|
placeholder: 'Taip arahan atau carian...',
|
||||||
noMatch: 'Tiada data yang sepadan',
|
noMatch: 'Tiada data yang sepadan',
|
||||||
noData: 'Tiada data',
|
noData: 'Tiada data',
|
||||||
close: 'Tutup'
|
close: 'Tutup',
|
||||||
|
back: 'Kembali'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'Tiada data yang sepadan',
|
noMatch: 'Tiada data yang sepadan',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'Skriv inn en kommando eller søk...',
|
placeholder: 'Skriv inn en kommando eller søk...',
|
||||||
noMatch: 'Ingen samsvarende data',
|
noMatch: 'Ingen samsvarende data',
|
||||||
noData: 'Ingen data',
|
noData: 'Ingen data',
|
||||||
close: 'Lukk'
|
close: 'Lukk',
|
||||||
|
back: 'Tilbake'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'Ingen samsvarende data',
|
noMatch: 'Ingen samsvarende data',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'Typ een commando of zoek...',
|
placeholder: 'Typ een commando of zoek...',
|
||||||
noMatch: 'Geen overeenkomende gegevens',
|
noMatch: 'Geen overeenkomende gegevens',
|
||||||
noData: 'Geen gegevens',
|
noData: 'Geen gegevens',
|
||||||
close: 'Sluiten'
|
close: 'Sluiten',
|
||||||
|
back: 'Terug'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'Geen overeenkomende gegevens',
|
noMatch: 'Geen overeenkomende gegevens',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'Wpisz polecenie lub wyszukaj...',
|
placeholder: 'Wpisz polecenie lub wyszukaj...',
|
||||||
noMatch: 'Brak pasujących danych',
|
noMatch: 'Brak pasujących danych',
|
||||||
noData: 'Brak danych',
|
noData: 'Brak danych',
|
||||||
close: 'Zamknij'
|
close: 'Zamknij',
|
||||||
|
back: 'Wstecz'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'Brak pasujących danych',
|
noMatch: 'Brak pasujących danych',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'Digite um comando ou pesquise...',
|
placeholder: 'Digite um comando ou pesquise...',
|
||||||
noMatch: 'Nenhum dado correspondente',
|
noMatch: 'Nenhum dado correspondente',
|
||||||
noData: 'Sem dados',
|
noData: 'Sem dados',
|
||||||
close: 'Fechar'
|
close: 'Fechar',
|
||||||
|
back: 'Voltar'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'Nenhum dado correspondente',
|
noMatch: 'Nenhum dado correspondente',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'Digite um comando ou pesquise...',
|
placeholder: 'Digite um comando ou pesquise...',
|
||||||
noMatch: 'Nenhum dado correspondente',
|
noMatch: 'Nenhum dado correspondente',
|
||||||
noData: 'Nenhum dado',
|
noData: 'Nenhum dado',
|
||||||
close: 'Fechar'
|
close: 'Fechar',
|
||||||
|
back: 'Voltar'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'Nenhum dado correspondente',
|
noMatch: 'Nenhum dado correspondente',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'Tastează o comandă sau caută...',
|
placeholder: 'Tastează o comandă sau caută...',
|
||||||
noMatch: 'Nu există date corespunzătoare',
|
noMatch: 'Nu există date corespunzătoare',
|
||||||
noData: 'Nu există date',
|
noData: 'Nu există date',
|
||||||
close: 'Închide'
|
close: 'Închide',
|
||||||
|
back: 'Înapoi'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'Nu există date corespunzătoare',
|
noMatch: 'Nu există date corespunzătoare',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'Введите команду или выполните поиск...',
|
placeholder: 'Введите команду или выполните поиск...',
|
||||||
noMatch: 'Совпадений не найдено',
|
noMatch: 'Совпадений не найдено',
|
||||||
noData: 'Нет данных',
|
noData: 'Нет данных',
|
||||||
close: 'Закрыть'
|
close: 'Закрыть',
|
||||||
|
back: 'Назад'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'Совпадений не найдено',
|
noMatch: 'Совпадений не найдено',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'Zadajte príkaz alebo vyhľadajte...',
|
placeholder: 'Zadajte príkaz alebo vyhľadajte...',
|
||||||
noMatch: 'Žiadna zhoda',
|
noMatch: 'Žiadna zhoda',
|
||||||
noData: 'Žiadne dáta',
|
noData: 'Žiadne dáta',
|
||||||
close: 'Zatvoriť'
|
close: 'Zavrieť',
|
||||||
|
back: 'Späť'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'Žiadna zhoda',
|
noMatch: 'Žiadna zhoda',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'Vpiši ukaz ali išči...',
|
placeholder: 'Vpiši ukaz ali išči...',
|
||||||
noMatch: 'Ni ujemanj',
|
noMatch: 'Ni ujemanj',
|
||||||
noData: 'Ni podatkov',
|
noData: 'Ni podatkov',
|
||||||
close: 'Zapri'
|
close: 'Zapri',
|
||||||
|
back: 'Nazaj'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'Ni ujemanj',
|
noMatch: 'Ni ujemanj',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'Skriv ett kommando eller sök...',
|
placeholder: 'Skriv ett kommando eller sök...',
|
||||||
noMatch: 'Inga matchande data',
|
noMatch: 'Inga matchande data',
|
||||||
noData: 'Inga data',
|
noData: 'Inga data',
|
||||||
close: 'Stäng'
|
close: 'Stäng',
|
||||||
|
back: 'Tillbaka'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'Inga matchande data',
|
noMatch: 'Inga matchande data',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'พิมพ์คำสั่งหรือค้นหา...',
|
placeholder: 'พิมพ์คำสั่งหรือค้นหา...',
|
||||||
noMatch: 'ไม่พบข้อมูลที่ตรงกัน',
|
noMatch: 'ไม่พบข้อมูลที่ตรงกัน',
|
||||||
noData: 'ไม่มีข้อมูล',
|
noData: 'ไม่มีข้อมูล',
|
||||||
close: 'ปิด'
|
close: 'ปิด',
|
||||||
|
back: 'ย้อนกลับ'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'ไม่พบข้อมูลที่ตรงกัน',
|
noMatch: 'ไม่พบข้อมูลที่ตรงกัน',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'Фармонро нависед ё ҷустуҷӯ кунед...',
|
placeholder: 'Фармонро нависед ё ҷустуҷӯ кунед...',
|
||||||
noMatch: 'Маълумоти мувофиқ ёфт нашуд',
|
noMatch: 'Маълумоти мувофиқ ёфт нашуд',
|
||||||
noData: 'Маълумот нест',
|
noData: 'Маълумот нест',
|
||||||
close: 'Бастан'
|
close: 'Бастан',
|
||||||
|
back: 'Бозгашт'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'Маълумоти мувофиқ ёфт нашуд',
|
noMatch: 'Маълумоти мувофиқ ёфт нашуд',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'Bir komut yazın veya arama yapın...',
|
placeholder: 'Bir komut yazın veya arama yapın...',
|
||||||
noMatch: 'Eşleşen veri yok',
|
noMatch: 'Eşleşen veri yok',
|
||||||
noData: 'Veri yok',
|
noData: 'Veri yok',
|
||||||
close: 'Kapat'
|
close: 'Kapat',
|
||||||
|
back: 'Geri'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'Eşleşen veri yok',
|
noMatch: 'Eşleşen veri yok',
|
||||||
|
|||||||
@@ -25,7 +25,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'بۇيرۇق كىرگۈزۈڭ ياكى ئىزدەڭ...',
|
placeholder: 'بۇيرۇق كىرگۈزۈڭ ياكى ئىزدەڭ...',
|
||||||
noMatch: 'ماس كېلىدىغان سانلىق مەلۇمات يوق',
|
noMatch: 'ماس كېلىدىغان سانلىق مەلۇمات يوق',
|
||||||
noData: 'سانلىق مەلۇمات يوق',
|
noData: 'سانلىق مەلۇمات يوق',
|
||||||
close: 'تاقاش'
|
close: 'تاقاش',
|
||||||
|
back: 'قايتىش'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'ماس كېلىدىغان سانلىق مەلۇمات يوق',
|
noMatch: 'ماس كېلىدىغان سانلىق مەلۇمات يوق',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'Введіть команду або шукайте...',
|
placeholder: 'Введіть команду або шукайте...',
|
||||||
noMatch: 'Збігів не знайдено',
|
noMatch: 'Збігів не знайдено',
|
||||||
noData: 'Немає даних',
|
noData: 'Немає даних',
|
||||||
close: 'Закрити'
|
close: 'Закрити',
|
||||||
|
back: 'Назад'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'Збігів не знайдено',
|
noMatch: 'Збігів не знайдено',
|
||||||
|
|||||||
@@ -25,7 +25,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'کمانڈ ٹائپ کریں یا تلاش کریں...',
|
placeholder: 'کمانڈ ٹائپ کریں یا تلاش کریں...',
|
||||||
noMatch: 'کوئی ملتا جلتا ڈیٹا نہیں ملا',
|
noMatch: 'کوئی ملتا جلتا ڈیٹا نہیں ملا',
|
||||||
noData: 'کوئی ڈیٹا نہیں',
|
noData: 'کوئی ڈیٹا نہیں',
|
||||||
close: 'بند کریں'
|
close: 'بند کریں',
|
||||||
|
back: 'واپس'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'کوئی ملتا جلتا ڈیٹا نہیں ملا',
|
noMatch: 'کوئی ملتا جلتا ڈیٹا نہیں ملا',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'Buyruq kiriting yoki qidiring...',
|
placeholder: 'Buyruq kiriting yoki qidiring...',
|
||||||
noMatch: 'Mos keluvchi natija topilmadi',
|
noMatch: 'Mos keluvchi natija topilmadi',
|
||||||
noData: 'Maʼlumot yoʻq',
|
noData: 'Maʼlumot yoʻq',
|
||||||
close: 'Yopish'
|
close: 'Yopish',
|
||||||
|
back: 'Orqaga'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'Mos keluvchi natija topilmadi',
|
noMatch: 'Mos keluvchi natija topilmadi',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: 'Nhập lệnh hoặc tìm kiếm...',
|
placeholder: 'Nhập lệnh hoặc tìm kiếm...',
|
||||||
noMatch: 'Không có kết quả phù hợp',
|
noMatch: 'Không có kết quả phù hợp',
|
||||||
noData: 'Không có dữ liệu',
|
noData: 'Không có dữ liệu',
|
||||||
close: 'Đóng'
|
close: 'Đóng',
|
||||||
|
back: 'Quay lại'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: 'Không có kết quả phù hợp',
|
noMatch: 'Không có kết quả phù hợp',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: '输入命令或搜索...',
|
placeholder: '输入命令或搜索...',
|
||||||
noMatch: '没有匹配的数据',
|
noMatch: '没有匹配的数据',
|
||||||
noData: '没有数据',
|
noData: '没有数据',
|
||||||
close: '关闭'
|
close: '关闭',
|
||||||
|
back: '返回'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: '没有匹配的数据',
|
noMatch: '没有匹配的数据',
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export default defineLocale<Messages>({
|
|||||||
placeholder: '輸入命令或搜尋...',
|
placeholder: '輸入命令或搜尋...',
|
||||||
noMatch: '沒有相符的資料',
|
noMatch: '沒有相符的資料',
|
||||||
noData: '沒有資料',
|
noData: '沒有資料',
|
||||||
close: '關閉'
|
close: '關閉',
|
||||||
|
back: '返回'
|
||||||
},
|
},
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: '沒有相符的資料',
|
noMatch: '沒有相符的資料',
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ export type Messages = {
|
|||||||
noMatch: string
|
noMatch: string
|
||||||
noData: string
|
noData: string
|
||||||
close: string
|
close: string
|
||||||
|
back: string
|
||||||
}
|
}
|
||||||
selectMenu: {
|
selectMenu: {
|
||||||
noMatch: string
|
noMatch: string
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ export default (options: Required<ModuleOptions>) => ({
|
|||||||
root: 'flex flex-col min-h-0 min-w-0 divide-y divide-default',
|
root: 'flex flex-col min-h-0 min-w-0 divide-y divide-default',
|
||||||
input: '[&>input]:h-12',
|
input: '[&>input]:h-12',
|
||||||
close: '',
|
close: '',
|
||||||
|
back: 'p-0',
|
||||||
content: 'relative overflow-hidden flex flex-col',
|
content: 'relative overflow-hidden flex flex-col',
|
||||||
viewport: 'relative divide-y divide-default scroll-py-1 overflow-y-auto flex-1 focus:outline-none',
|
viewport: 'relative divide-y divide-default scroll-py-1 overflow-y-auto flex-1 focus:outline-none',
|
||||||
group: 'p-1 isolate',
|
group: 'p-1 isolate',
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { describe, it, expect } from 'vitest'
|
import { describe, it, expect } from 'vitest'
|
||||||
import CommandPalette, { type CommandPaletteProps } from '../../src/runtime/components/CommandPalette.vue'
|
import CommandPalette, { type CommandPaletteProps, type CommandPaletteSlots } from '../../src/runtime/components/CommandPalette.vue'
|
||||||
import ComponentRender from '../component-render'
|
import ComponentRender from '../component-render'
|
||||||
|
|
||||||
describe('CommandPalette', () => {
|
describe('CommandPalette', () => {
|
||||||
@@ -89,7 +89,7 @@ describe('CommandPalette', () => {
|
|||||||
['with item-trailing slot', { props, slots: { 'item-trailing': () => 'Item trailing slot' } }],
|
['with item-trailing slot', { props, slots: { 'item-trailing': () => 'Item trailing slot' } }],
|
||||||
['with custom slot', { props, slots: { custom: () => 'Custom slot' } }],
|
['with custom slot', { props, slots: { custom: () => 'Custom slot' } }],
|
||||||
['with close slot', { props: { ...props, close: true }, slots: { close: () => 'Close slot' } }]
|
['with close slot', { props: { ...props, close: true }, slots: { close: () => 'Close slot' } }]
|
||||||
])('renders %s correctly', async (nameOrHtml: string, options: { props?: CommandPaletteProps<typeof groups[number], typeof groups[number]['items'][number]>, slots?: Partial<any> }) => {
|
])('renders %s correctly', async (nameOrHtml: string, options: { props?: CommandPaletteProps, slots?: Partial<CommandPaletteSlots> }) => {
|
||||||
const html = await ComponentRender(nameOrHtml, options, CommandPalette)
|
const html = await ComponentRender(nameOrHtml, options, CommandPalette)
|
||||||
expect(html).toMatchSnapshot()
|
expect(html).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ describe('Table', () => {
|
|||||||
['with empty slot', { props: { columns }, slots: { empty: () => 'Empty slot' } }],
|
['with empty slot', { props: { columns }, slots: { empty: () => 'Empty slot' } }],
|
||||||
['with loading slot', { props: { columns, loading: true }, slots: { loading: () => 'Loading slot' } }],
|
['with loading slot', { props: { columns, loading: true }, slots: { loading: () => 'Loading slot' } }],
|
||||||
['with caption slot', { props, slots: { caption: () => 'Caption slot' } }]
|
['with caption slot', { props, slots: { caption: () => 'Caption slot' } }]
|
||||||
])('renders %s correctly', async (nameOrHtml: string, options: { props?: TableProps<typeof data[number]>, slots?: Partial<TableSlots<typeof data[number]>> }) => {
|
])('renders %s correctly', async (nameOrHtml: string, options: { props?: TableProps, slots?: Partial<TableSlots> }) => {
|
||||||
const html = await ComponentRender(nameOrHtml, options, Table)
|
const html = await ComponentRender(nameOrHtml, options, Table)
|
||||||
expect(html).toMatchSnapshot()
|
expect(html).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user