mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-29 03:10:42 +01:00
chore(CommandPalette): handle loading state (#221)
This commit is contained in:
@@ -184,6 +184,7 @@ export default defineAppConfig({
|
|||||||
commandPalette: {
|
commandPalette: {
|
||||||
default: {
|
default: {
|
||||||
icon: 'i-octicon-search-24',
|
icon: 'i-octicon-search-24',
|
||||||
|
loadingIcon: 'i-octicon-sync-24',
|
||||||
selectedIcon: 'i-octicon-check-24',
|
selectedIcon: 'i-octicon-check-24',
|
||||||
empty: {
|
empty: {
|
||||||
icon: 'i-octicon-search-24'
|
icon: 'i-octicon-search-24'
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ baseProps:
|
|||||||
|
|
||||||
### Chip
|
### Chip
|
||||||
|
|
||||||
Use the `chipColor`, `chipVariant` and `chipPosition` props to display a chip on the Avatar.
|
Use the `chip-color`, `chip-variant` and `chip-position` props to display a chip on the Avatar.
|
||||||
|
|
||||||
::component-card
|
::component-card
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ Button
|
|||||||
|
|
||||||
Use any icon from [Iconify](https://icones.js.org) by setting the `icon` prop by using this pattern: `i-{collection_name}-{icon_name}`.
|
Use any icon from [Iconify](https://icones.js.org) by setting the `icon` prop by using this pattern: `i-{collection_name}-{icon_name}`.
|
||||||
|
|
||||||
Use the `leading` and `trailing` props to set the icon position or the `leadingIcon` and `trailingIcon` props to set a different icon for each position.
|
Use the `leading` and `trailing` props to set the icon position or the `leading-icon` and `trailing-icon` props to set a different icon for each position.
|
||||||
|
|
||||||
::component-card
|
::component-card
|
||||||
---
|
---
|
||||||
@@ -163,7 +163,7 @@ Button
|
|||||||
|
|
||||||
Use the `loading` prop to show a loading icon and disable the Button.
|
Use the `loading` prop to show a loading icon and disable the Button.
|
||||||
|
|
||||||
Use the `loadingIcon` prop to set a different icon or change it globally in `ui.button.default.loadingIcon`. Defaults to `i-heroicons-arrow-path-20-solid`.
|
Use the `loading-icon` prop to set a different icon or change it globally in `ui.button.default.loadingIcon`. Defaults to `i-heroicons-arrow-path-20-solid`.
|
||||||
|
|
||||||
::component-card
|
::component-card
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ props:
|
|||||||
|
|
||||||
Use any icon from [Iconify](https://icones.js.org) by setting the `icon` prop by using this pattern: `i-{collection_name}-{icon_name}`.
|
Use any icon from [Iconify](https://icones.js.org) by setting the `icon` prop by using this pattern: `i-{collection_name}-{icon_name}`.
|
||||||
|
|
||||||
Use the `leading` and `trailing` props to set the icon position or the `leadingIcon` and `trailingIcon` props to set a different icon for each position.
|
Use the `leading` and `trailing` props to set the icon position or the `leading-icon` and `trailing-icon` props to set a different icon for each position.
|
||||||
|
|
||||||
::component-card
|
::component-card
|
||||||
---
|
---
|
||||||
@@ -94,7 +94,7 @@ excludedProps:
|
|||||||
|
|
||||||
Use the `loading` prop to show a loading icon and disable the Input.
|
Use the `loading` prop to show a loading icon and disable the Input.
|
||||||
|
|
||||||
Use the `loadingIcon` prop to set a different icon or change it globally in `ui.input.default.loadingIcon`. Defaults to `i-heroicons-arrow-path-20-solid`.
|
Use the `loading-icon` prop to set a different icon or change it globally in `ui.input.default.loadingIcon`. Defaults to `i-heroicons-arrow-path-20-solid`.
|
||||||
|
|
||||||
::component-card
|
::component-card
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ props:
|
|||||||
|
|
||||||
Use any icon from [Iconify](https://icones.js.org) by setting the `icon` prop by using this pattern: `i-{collection_name}-{icon_name}`.
|
Use any icon from [Iconify](https://icones.js.org) by setting the `icon` prop by using this pattern: `i-{collection_name}-{icon_name}`.
|
||||||
|
|
||||||
Use the `trailingIcon` prop to set a different icon or change it globally in `ui.select.default.trailingIcon`. Defaults to `i-heroicons-chevron-down-20-solid`.
|
Use the `trailing-icon` prop to set a different icon or change it globally in `ui.select.default.trailingIcon`. Defaults to `i-heroicons-chevron-down-20-solid`.
|
||||||
|
|
||||||
::component-card
|
::component-card
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -136,9 +136,9 @@ const selected = ref(people[0])
|
|||||||
|
|
||||||
Use any icon from [Iconify](https://icones.js.org) by setting the `icon` prop by using this pattern: `i-{collection_name}-{icon_name}`.
|
Use any icon from [Iconify](https://icones.js.org) by setting the `icon` prop by using this pattern: `i-{collection_name}-{icon_name}`.
|
||||||
|
|
||||||
Use the `trailingIcon` prop to set a different icon or change it globally in `ui.select.default.trailingIcon`. Defaults to `i-heroicons-chevron-down-20-solid`.
|
Use the `trailing-icon` prop to set a different icon or change it globally in `ui.select.default.trailingIcon`. Defaults to `i-heroicons-chevron-down-20-solid`.
|
||||||
|
|
||||||
Use the `selectedIcon` prop to set a different icon or change it globally in `ui.selectMenu.default.selectedIcon`. Defaults to `i-heroicons-check-20-solid`.
|
Use the `selected-icon` prop to set a different icon or change it globally in `ui.selectMenu.default.selectedIcon`. Defaults to `i-heroicons-check-20-solid`.
|
||||||
|
|
||||||
::component-card
|
::component-card
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ function onSelect (option) {
|
|||||||
|
|
||||||
Use any icon from [Iconify](https://icones.js.org) by setting the `icon` prop by using this pattern: `i-{collection_name}-{icon_name}`.
|
Use any icon from [Iconify](https://icones.js.org) by setting the `icon` prop by using this pattern: `i-{collection_name}-{icon_name}`.
|
||||||
|
|
||||||
Use the `selectedIcon` prop to set a different icon or change it globally in `ui.commandPalette.default.selectedIcon`. Defaults to `i-heroicons-check-20-solid`.
|
Use the `selected-icon` prop to set a different icon or change it globally in `ui.commandPalette.default.selectedIcon`. Defaults to `i-heroicons-check-20-solid`.
|
||||||
|
|
||||||
::component-card
|
::component-card
|
||||||
---
|
---
|
||||||
@@ -174,6 +174,24 @@ excludedProps:
|
|||||||
---
|
---
|
||||||
::
|
::
|
||||||
|
|
||||||
|
### Loading
|
||||||
|
|
||||||
|
Use the `loading` prop to show a loading icon.
|
||||||
|
|
||||||
|
Use the `loading-icon` prop to set a different icon or change it globally in `ui.commandPalette.default.loadingIcon`. Defaults to `i-heroicons-arrow-path-20-solid`.
|
||||||
|
|
||||||
|
::component-card
|
||||||
|
---
|
||||||
|
padding: false
|
||||||
|
baseProps:
|
||||||
|
empty: null
|
||||||
|
props:
|
||||||
|
loading: true
|
||||||
|
excludedProps:
|
||||||
|
- icon
|
||||||
|
---
|
||||||
|
::
|
||||||
|
|
||||||
### Placeholder
|
### Placeholder
|
||||||
|
|
||||||
Use the `placeholder` prop to change the input placeholder
|
Use the `placeholder` prop to change the input placeholder
|
||||||
@@ -218,6 +236,8 @@ Use the `empty` prop to display a message when there are no results.
|
|||||||
|
|
||||||
You can pass an `object` through the `empty` prop or globally through `ui.commandPalette.default.empty`. Here is the default:
|
You can pass an `object` through the `empty` prop or globally through `ui.commandPalette.default.empty`. Here is the default:
|
||||||
|
|
||||||
|
You can also set it to `null` to hide the empty label.
|
||||||
|
|
||||||
::component-card
|
::component-card
|
||||||
---
|
---
|
||||||
padding: false
|
padding: false
|
||||||
@@ -299,6 +319,10 @@ const groups = computed(() => {
|
|||||||
```
|
```
|
||||||
::
|
::
|
||||||
|
|
||||||
|
::alert{icon="i-heroicons-light-bulb"}
|
||||||
|
The `loading` state will automatically be enabled when a `search` function is loading. You can disable this behaviour by setting the `loading-icon` prop to `null` or globally in `ui.commandPalette.default.loadingIcon`.
|
||||||
|
::
|
||||||
|
|
||||||
## Themes
|
## Themes
|
||||||
|
|
||||||
Our theming system provides a lot of flexibility to customize the component. Here is some examples of what you can do.
|
Our theming system provides a lot of flexibility to customize the component. Here is some examples of what you can do.
|
||||||
|
|||||||
@@ -546,6 +546,7 @@ const commandPalette = {
|
|||||||
},
|
},
|
||||||
default: {
|
default: {
|
||||||
icon: 'i-heroicons-magnifying-glass-20-solid',
|
icon: 'i-heroicons-magnifying-glass-20-solid',
|
||||||
|
loadingIcon: 'i-heroicons-arrow-path-20-solid',
|
||||||
empty: {
|
empty: {
|
||||||
icon: 'i-heroicons-magnifying-glass-20-solid',
|
icon: 'i-heroicons-magnifying-glass-20-solid',
|
||||||
label: 'We couldn\'t find any items.',
|
label: 'We couldn\'t find any items.',
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
>
|
>
|
||||||
<div :class="ui.wrapper">
|
<div :class="ui.wrapper">
|
||||||
<div v-show="searchable" :class="ui.input.wrapper">
|
<div v-show="searchable" :class="ui.input.wrapper">
|
||||||
<UIcon v-if="icon" :name="icon" :class="[ui.input.icon.base, ui.input.icon.size]" aria-hidden="true" />
|
<UIcon v-if="iconName" :name="iconName" :class="iconClass" aria-hidden="true" />
|
||||||
<ComboboxInput
|
<ComboboxInput
|
||||||
ref="comboboxInput"
|
ref="comboboxInput"
|
||||||
:value="query"
|
:value="query"
|
||||||
@@ -74,6 +74,7 @@ import type { Group, Command } from '../../types/command-palette'
|
|||||||
import UIcon from '../elements/Icon.vue'
|
import UIcon from '../elements/Icon.vue'
|
||||||
import UButton from '../elements/Button.vue'
|
import UButton from '../elements/Button.vue'
|
||||||
import type { Button as ButtonType } from '../../types/button'
|
import type { Button as ButtonType } from '../../types/button'
|
||||||
|
import { classNames } from '../../utils'
|
||||||
import CommandPaletteGroup from './CommandPaletteGroup.vue'
|
import CommandPaletteGroup from './CommandPaletteGroup.vue'
|
||||||
import { useAppConfig } from '#imports'
|
import { useAppConfig } from '#imports'
|
||||||
// TODO: Remove
|
// TODO: Remove
|
||||||
@@ -112,6 +113,10 @@ export default defineComponent({
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true
|
||||||
},
|
},
|
||||||
|
loading: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
groups: {
|
groups: {
|
||||||
type: Array as PropType<Group[]>,
|
type: Array as PropType<Group[]>,
|
||||||
default: () => []
|
default: () => []
|
||||||
@@ -120,6 +125,10 @@ export default defineComponent({
|
|||||||
type: String,
|
type: String,
|
||||||
default: () => appConfig.ui.commandPalette.default.icon
|
default: () => appConfig.ui.commandPalette.default.icon
|
||||||
},
|
},
|
||||||
|
loadingIcon: {
|
||||||
|
type: String,
|
||||||
|
default: () => appConfig.ui.commandPalette.default.loadingIcon
|
||||||
|
},
|
||||||
selectedIcon: {
|
selectedIcon: {
|
||||||
type: String,
|
type: String,
|
||||||
default: () => appConfig.ui.commandPalette.default.selectedIcon
|
default: () => appConfig.ui.commandPalette.default.selectedIcon
|
||||||
@@ -175,6 +184,7 @@ export default defineComponent({
|
|||||||
const query = ref('')
|
const query = ref('')
|
||||||
const comboboxInput = ref<ComponentPublicInstance<HTMLInputElement>>()
|
const comboboxInput = ref<ComponentPublicInstance<HTMLInputElement>>()
|
||||||
const comboboxApi = ref(null)
|
const comboboxApi = ref(null)
|
||||||
|
const isLoading = ref(false)
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (props.autoselect) {
|
if (props.autoselect) {
|
||||||
@@ -231,10 +241,17 @@ export default defineComponent({
|
|||||||
|
|
||||||
const debouncedSearch = useDebounceFn(async () => {
|
const debouncedSearch = useDebounceFn(async () => {
|
||||||
const searchableGroups = props.groups.filter(group => !!group.search)
|
const searchableGroups = props.groups.filter(group => !!group.search)
|
||||||
|
if (!searchableGroups.length) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
isLoading.value = true
|
||||||
|
|
||||||
await Promise.all(searchableGroups.map(async (group) => {
|
await Promise.all(searchableGroups.map(async (group) => {
|
||||||
searchResults.value[group.key] = await group.search(query.value)
|
searchResults.value[group.key] = await group.search(query.value)
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
isLoading.value = false
|
||||||
}, props.debounce)
|
}, props.debounce)
|
||||||
|
|
||||||
watch(query, () => {
|
watch(query, () => {
|
||||||
@@ -247,6 +264,22 @@ export default defineComponent({
|
|||||||
}, 0)
|
}, 0)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const iconName = computed(() => {
|
||||||
|
if ((props.loading || isLoading.value) && props.loadingIcon) {
|
||||||
|
return props.loadingIcon
|
||||||
|
}
|
||||||
|
|
||||||
|
return props.icon
|
||||||
|
})
|
||||||
|
|
||||||
|
const iconClass = computed(() => {
|
||||||
|
return classNames(
|
||||||
|
ui.value.input.icon.base,
|
||||||
|
ui.value.input.icon.size,
|
||||||
|
((props.loading || isLoading.value) && props.loadingIcon) && 'animate-spin'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
// Methods
|
// Methods
|
||||||
|
|
||||||
function activateFirstOption () {
|
function activateFirstOption () {
|
||||||
@@ -292,6 +325,8 @@ export default defineComponent({
|
|||||||
groups,
|
groups,
|
||||||
comboboxInput,
|
comboboxInput,
|
||||||
query,
|
query,
|
||||||
|
iconName,
|
||||||
|
iconClass,
|
||||||
onSelect,
|
onSelect,
|
||||||
onClear
|
onClear
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user