mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-16 21:18:05 +01:00
chore: uniformize icons in Button / Input / Select / SelectMenu
Also adds `loading` to `Select` and `SelectMenu`
This commit is contained in:
@@ -166,6 +166,7 @@ export default defineAppConfig({
|
||||
},
|
||||
select: {
|
||||
default: {
|
||||
loadingIcon: 'i-octicon-sync-24',
|
||||
trailingIcon: 'i-octicon-chevron-down-24'
|
||||
}
|
||||
},
|
||||
|
||||
@@ -157,6 +157,29 @@ props:
|
||||
---
|
||||
::
|
||||
|
||||
### Loading
|
||||
|
||||
Use the `loading` prop to show a loading icon and disable the Input.
|
||||
|
||||
Use the `loading-icon` prop to set a different icon or change it globally in `ui.select.default.loadingIcon`. Defaults to `i-heroicons-arrow-path-20-solid`.
|
||||
|
||||
::component-card
|
||||
---
|
||||
baseProps:
|
||||
name: 'select'
|
||||
options:
|
||||
- 'United States'
|
||||
- 'Canada'
|
||||
- 'Mexico'
|
||||
placeholder: 'Search...'
|
||||
props:
|
||||
loading: true
|
||||
icon: 'i-heroicons-magnifying-glass-20-solid'
|
||||
excludedProps:
|
||||
- icon
|
||||
---
|
||||
::
|
||||
|
||||
## Props
|
||||
|
||||
:component-props
|
||||
|
||||
@@ -162,10 +162,6 @@ const selected = ref(people[0])
|
||||
|
||||
### Icon
|
||||
|
||||
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 `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 `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
|
||||
@@ -175,16 +171,16 @@ baseProps:
|
||||
placeholder: 'Select a person'
|
||||
options: ['Wade Cooper', 'Arlene Mccoy', 'Devon Webb', 'Tom Cook', 'Tanya Fox', 'Hellen Schmidt', 'Caroline Schultz', 'Mason Heaney', 'Claudie Smitham', 'Emil Schaefer']
|
||||
props:
|
||||
icon: 'i-heroicons-magnifying-glass-20-solid'
|
||||
color: 'white'
|
||||
extraColors:
|
||||
- white
|
||||
- gray
|
||||
selectedIcon: 'i-heroicons-hand-thumb-up-solid'
|
||||
excludedProps:
|
||||
- icon
|
||||
- selectedIcon
|
||||
---
|
||||
::
|
||||
|
||||
::alert{icon="i-heroicons-light-bulb"}
|
||||
Learn how to customize icons from the [Select](/forms/select#icon) component.
|
||||
::
|
||||
|
||||
### Search
|
||||
|
||||
Use the `searchable` prop to enable search.
|
||||
|
||||
@@ -399,6 +399,7 @@ const select = {
|
||||
size: 'sm',
|
||||
color: 'white',
|
||||
variant: 'outline',
|
||||
loadingIcon: 'i-heroicons-arrow-path-20-solid',
|
||||
trailingIcon: 'i-heroicons-chevron-down-20-solid'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,11 +18,11 @@
|
||||
@blur="$emit('blur', $event)"
|
||||
>
|
||||
<slot />
|
||||
<div v-if="isLeading && leadingIconName" :class="leadingIconClass">
|
||||
<UIcon :name="leadingIconName" :class="iconClass" />
|
||||
<div v-if="isLeading && leadingIconName" :class="leadingWrapperIconClass">
|
||||
<UIcon :name="leadingIconName" :class="leadingIconClass" />
|
||||
</div>
|
||||
<div v-if="isTrailing && trailingIconName" :class="trailingIconClass">
|
||||
<UIcon :name="trailingIconName" :class="iconClass" />
|
||||
<div v-if="isTrailing && trailingIconName" :class="trailingWrapperIconClass">
|
||||
<UIcon :name="trailingIconName" :class="trailingIconClass" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -211,7 +211,14 @@ export default defineComponent({
|
||||
return props.trailingIcon || props.icon
|
||||
})
|
||||
|
||||
const iconClass = computed(() => {
|
||||
const leadingWrapperIconClass = computed(() => {
|
||||
return classNames(
|
||||
ui.value.icon.leading.wrapper,
|
||||
ui.value.icon.leading.padding[props.size]
|
||||
)
|
||||
})
|
||||
|
||||
const leadingIconClass = computed(() => {
|
||||
return classNames(
|
||||
ui.value.icon.base,
|
||||
appConfig.ui.colors.includes(props.color) && ui.value.icon.color.replaceAll('{color}', props.color),
|
||||
@@ -220,17 +227,19 @@ export default defineComponent({
|
||||
)
|
||||
})
|
||||
|
||||
const leadingIconClass = computed(() => {
|
||||
const trailingWrapperIconClass = computed(() => {
|
||||
return classNames(
|
||||
ui.value.icon.leading.wrapper,
|
||||
ui.value.icon.leading.padding[props.size]
|
||||
ui.value.icon.trailing.wrapper,
|
||||
ui.value.icon.trailing.padding[props.size]
|
||||
)
|
||||
})
|
||||
|
||||
const trailingIconClass = computed(() => {
|
||||
return classNames(
|
||||
ui.value.icon.trailing.wrapper,
|
||||
ui.value.icon.trailing.padding[props.size]
|
||||
ui.value.icon.base,
|
||||
appConfig.ui.colors.includes(props.color) && ui.value.icon.color.replaceAll('{color}', props.color),
|
||||
ui.value.icon.size[props.size],
|
||||
props.loading && !isLeading.value && 'animate-spin'
|
||||
)
|
||||
})
|
||||
|
||||
@@ -241,11 +250,12 @@ export default defineComponent({
|
||||
isLeading,
|
||||
isTrailing,
|
||||
inputClass,
|
||||
iconClass,
|
||||
leadingIconName,
|
||||
leadingIconClass,
|
||||
leadingWrapperIconClass,
|
||||
trailingIconName,
|
||||
trailingIconClass,
|
||||
trailingWrapperIconClass,
|
||||
onInput
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
:name="name"
|
||||
:value="modelValue"
|
||||
:required="required"
|
||||
:disabled="disabled"
|
||||
:disabled="disabled || loading"
|
||||
:class="selectClass"
|
||||
@input="onInput"
|
||||
>
|
||||
@@ -36,12 +36,12 @@
|
||||
</template>
|
||||
</select>
|
||||
|
||||
<div v-if="icon" :class="leadingIconClass">
|
||||
<UIcon :name="icon" :class="iconClass" />
|
||||
<div v-if="isLeading && leadingIconName" :class="leadingWrapperIconClass">
|
||||
<UIcon :name="leadingIconName" :class="leadingIconClass" />
|
||||
</div>
|
||||
|
||||
<span v-if="trailingIcon" :class="trailingIconClass">
|
||||
<UIcon :name="trailingIcon" :class="iconClass" aria-hidden="true" />
|
||||
<span v-if="isTrailing && trailingIconName" :class="trailingWrapperIconClass">
|
||||
<UIcon :name="trailingIconName" :class="trailingIconClass" aria-hidden="true" />
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
@@ -89,18 +89,38 @@ export default defineComponent({
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
loadingIcon: {
|
||||
type: String,
|
||||
default: () => appConfig.ui.input.default.loadingIcon
|
||||
},
|
||||
leadingIcon: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
trailingIcon: {
|
||||
type: String,
|
||||
default: () => appConfig.ui.select.default.trailingIcon
|
||||
},
|
||||
options: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
trailing: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
leading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
padded: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
options: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
size: {
|
||||
type: String,
|
||||
default: () => appConfig.ui.select.default.size,
|
||||
@@ -210,43 +230,82 @@ export default defineComponent({
|
||||
ui.value.size[props.size],
|
||||
props.padded && ui.value.padding[props.size],
|
||||
variant?.replaceAll('{color}', props.color),
|
||||
!!props.icon && ui.value.leading.padding[props.size],
|
||||
ui.value.trailing.padding[props.size],
|
||||
isLeading.value && ui.value.leading.padding[props.size],
|
||||
isTrailing.value && ui.value.trailing.padding[props.size],
|
||||
ui.value.custom
|
||||
)
|
||||
})
|
||||
|
||||
const iconClass = computed(() => {
|
||||
return classNames(
|
||||
ui.value.icon.base,
|
||||
appConfig.ui.colors.includes(props.color) && ui.value.icon.color.replaceAll('{color}', props.color),
|
||||
ui.value.icon.size[props.size]
|
||||
)
|
||||
const isLeading = computed(() => {
|
||||
return (props.icon && props.leading) || (props.icon && !props.trailing) || (props.loading && !props.trailing) || props.leadingIcon
|
||||
})
|
||||
|
||||
const leadingIconClass = computed(() => {
|
||||
const isTrailing = computed(() => {
|
||||
return (props.icon && props.trailing) || (props.loading && props.trailing) || props.trailingIcon
|
||||
})
|
||||
|
||||
const leadingIconName = computed(() => {
|
||||
if (props.loading) {
|
||||
return props.loadingIcon
|
||||
}
|
||||
|
||||
return props.leadingIcon || props.icon
|
||||
})
|
||||
|
||||
const trailingIconName = computed(() => {
|
||||
if (props.loading && !isLeading.value) {
|
||||
return props.loadingIcon
|
||||
}
|
||||
|
||||
return props.trailingIcon || props.icon
|
||||
})
|
||||
|
||||
const leadingWrapperIconClass = computed(() => {
|
||||
return classNames(
|
||||
ui.value.icon.leading.wrapper,
|
||||
ui.value.icon.leading.padding[props.size]
|
||||
)
|
||||
})
|
||||
|
||||
const trailingIconClass = computed(() => {
|
||||
const leadingIconClass = computed(() => {
|
||||
return classNames(
|
||||
ui.value.icon.base,
|
||||
appConfig.ui.colors.includes(props.color) && ui.value.icon.color.replaceAll('{color}', props.color),
|
||||
ui.value.icon.size[props.size],
|
||||
props.loading && 'animate-spin'
|
||||
)
|
||||
})
|
||||
|
||||
const trailingWrapperIconClass = computed(() => {
|
||||
return classNames(
|
||||
ui.value.icon.trailing.wrapper,
|
||||
ui.value.icon.trailing.padding[props.size]
|
||||
)
|
||||
})
|
||||
|
||||
const trailingIconClass = computed(() => {
|
||||
return classNames(
|
||||
ui.value.icon.base,
|
||||
appConfig.ui.colors.includes(props.color) && ui.value.icon.color.replaceAll('{color}', props.color),
|
||||
ui.value.icon.size[props.size],
|
||||
props.loading && !isLeading.value && 'animate-spin'
|
||||
)
|
||||
})
|
||||
|
||||
return {
|
||||
// eslint-disable-next-line vue/no-dupe-keys
|
||||
ui,
|
||||
normalizedOptionsWithPlaceholder,
|
||||
normalizedValue,
|
||||
isLeading,
|
||||
isTrailing,
|
||||
selectClass,
|
||||
iconClass,
|
||||
leadingIconName,
|
||||
leadingIconClass,
|
||||
leadingWrapperIconClass,
|
||||
trailingIconName,
|
||||
trailingIconClass,
|
||||
trailingWrapperIconClass,
|
||||
onInput
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,10 +27,10 @@
|
||||
role="button"
|
||||
class="inline-flex w-full"
|
||||
>
|
||||
<slot :open="open" :disabled="disabled">
|
||||
<button :class="selectMenuClass" :disabled="disabled" type="button">
|
||||
<span v-if="icon" :class="leadingIconClass">
|
||||
<UIcon :name="icon" :class="iconClass" />
|
||||
<slot :open="open" :disabled="disabled" :loading="loading">
|
||||
<button :class="selectMenuClass" :disabled="disabled || loading" type="button">
|
||||
<span v-if="isLeading && leadingIconName" :class="leadingWrapperIconClass">
|
||||
<UIcon :name="leadingIconName" :class="leadingIconClass" />
|
||||
</span>
|
||||
|
||||
<slot name="label">
|
||||
@@ -39,8 +39,8 @@
|
||||
<span v-else class="block truncate" :class="ui.placeholder">{{ placeholder || ' ' }}</span>
|
||||
</slot>
|
||||
|
||||
<span v-if="trailingIcon" :class="trailingIconClass">
|
||||
<UIcon :name="trailingIcon" :class="iconClass" aria-hidden="true" />
|
||||
<span v-if="isTrailing && trailingIconName" :class="trailingWrapperIconClass">
|
||||
<UIcon :name="trailingIconName" :class="trailingIconClass" aria-hidden="true" />
|
||||
</span>
|
||||
</button>
|
||||
</slot>
|
||||
@@ -167,10 +167,30 @@ export default defineComponent({
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
loadingIcon: {
|
||||
type: String,
|
||||
default: () => appConfig.ui.input.default.loadingIcon
|
||||
},
|
||||
leadingIcon: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
trailingIcon: {
|
||||
type: String,
|
||||
default: () => appConfig.ui.select.default.trailingIcon
|
||||
},
|
||||
trailing: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
leading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
selectedIcon: {
|
||||
type: String,
|
||||
default: () => appConfig.ui.selectMenu.default.selectedIcon
|
||||
@@ -274,35 +294,69 @@ export default defineComponent({
|
||||
uiSelect.value.gap[props.size],
|
||||
props.padded && uiSelect.value.padding[props.size],
|
||||
variant?.replaceAll('{color}', props.color),
|
||||
!!props.icon && uiSelect.value.leading.padding[props.size],
|
||||
uiSelect.value.trailing.padding[props.size],
|
||||
isLeading.value && uiSelect.value.leading.padding[props.size],
|
||||
isTrailing.value && uiSelect.value.trailing.padding[props.size],
|
||||
uiSelect.value.custom,
|
||||
'inline-flex items-center'
|
||||
)
|
||||
})
|
||||
|
||||
const iconClass = computed(() => {
|
||||
return classNames(
|
||||
uiSelect.value.icon.base,
|
||||
appConfig.ui.colors.includes(props.color) && uiSelect.value.icon.color.replaceAll('{color}', props.color),
|
||||
uiSelect.value.icon.size[props.size]
|
||||
)
|
||||
const isLeading = computed(() => {
|
||||
return (props.icon && props.leading) || (props.icon && !props.trailing) || (props.loading && !props.trailing) || props.leadingIcon
|
||||
})
|
||||
|
||||
const leadingIconClass = computed(() => {
|
||||
const isTrailing = computed(() => {
|
||||
return (props.icon && props.trailing) || (props.loading && props.trailing) || props.trailingIcon
|
||||
})
|
||||
|
||||
const leadingIconName = computed(() => {
|
||||
if (props.loading) {
|
||||
return props.loadingIcon
|
||||
}
|
||||
|
||||
return props.leadingIcon || props.icon
|
||||
})
|
||||
|
||||
const trailingIconName = computed(() => {
|
||||
if (props.loading && !isLeading.value) {
|
||||
return props.loadingIcon
|
||||
}
|
||||
|
||||
return props.trailingIcon || props.icon
|
||||
})
|
||||
|
||||
const leadingWrapperIconClass = computed(() => {
|
||||
return classNames(
|
||||
uiSelect.value.icon.leading.wrapper,
|
||||
uiSelect.value.icon.leading.padding[props.size]
|
||||
)
|
||||
})
|
||||
|
||||
const trailingIconClass = computed(() => {
|
||||
const leadingIconClass = computed(() => {
|
||||
return classNames(
|
||||
uiSelect.value.icon.base,
|
||||
appConfig.ui.colors.includes(props.color) && uiSelect.value.icon.color.replaceAll('{color}', props.color),
|
||||
uiSelect.value.icon.size[props.size],
|
||||
props.loading && 'animate-spin'
|
||||
)
|
||||
})
|
||||
|
||||
const trailingWrapperIconClass = computed(() => {
|
||||
return classNames(
|
||||
uiSelect.value.icon.trailing.wrapper,
|
||||
uiSelect.value.icon.trailing.padding[props.size]
|
||||
)
|
||||
})
|
||||
|
||||
const trailingIconClass = computed(() => {
|
||||
return classNames(
|
||||
uiSelect.value.icon.base,
|
||||
appConfig.ui.colors.includes(props.color) && uiSelect.value.icon.color.replaceAll('{color}', props.color),
|
||||
uiSelect.value.icon.size[props.size],
|
||||
props.loading && !isLeading.value && 'animate-spin'
|
||||
)
|
||||
})
|
||||
|
||||
const filteredOptions = computed(() =>
|
||||
query.value === ''
|
||||
? props.options
|
||||
@@ -339,10 +393,15 @@ export default defineComponent({
|
||||
ui,
|
||||
trigger,
|
||||
container,
|
||||
isLeading,
|
||||
isTrailing,
|
||||
selectMenuClass,
|
||||
iconClass,
|
||||
leadingIconName,
|
||||
leadingIconClass,
|
||||
leadingWrapperIconClass,
|
||||
trailingIconName,
|
||||
trailingIconClass,
|
||||
trailingWrapperIconClass,
|
||||
filteredOptions,
|
||||
queryOption,
|
||||
query,
|
||||
|
||||
Reference in New Issue
Block a user