feat(types): support custom values from app.config.ts (#863)

This commit is contained in:
Benjamin Canac
2023-11-17 18:48:50 +01:00
committed by GitHub
parent bcc46b87f5
commit 7339324355
26 changed files with 132 additions and 57 deletions

View File

@@ -39,12 +39,11 @@ import UIcon from '../elements/Icon.vue'
import UAvatar from '../elements/Avatar.vue'
import UButton from '../elements/Button.vue'
import { useUI } from '../../composables/useUI'
import type { Avatar, Button, NestedKeyOf, Strategy } from '../../types'
import type { Avatar, Button, AlertColor, AlertVariant, Strategy } from '../../types'
import { mergeConfig } from '../../utils'
// @ts-expect-error
import appConfig from '#build/app.config'
import { alert } from '#ui/ui.config'
import colors from '#ui-colors'
const config = mergeConfig<typeof alert>(appConfig.ui.strategy, appConfig.ui.alert, alert)
@@ -81,14 +80,14 @@ export default defineComponent({
default: () => []
},
color: {
type: String as PropType<keyof typeof config.color | typeof colors[number]>,
type: String as PropType<AlertColor>,
default: () => config.default.color,
validator (value: string) {
return [...appConfig.ui.colors, ...Object.keys(config.color)].includes(value)
}
},
variant: {
type: String as PropType<keyof typeof config.variant | NestedKeyOf<typeof config.color>>,
type: String as PropType<AlertVariant>,
default: () => config.default.variant,
validator (value: string) {
return [

View File

@@ -17,7 +17,7 @@ export default defineComponent({
inheritAttrs: false,
props: {
size: {
type: String as PropType<keyof typeof avatarConfig.size>,
type: String as PropType<AvatarSize>,
default: null,
validator (value: string) {
return Object.keys(avatarConfig.size).includes(value)

View File

@@ -10,7 +10,7 @@ import type { PropType } from 'vue'
import { twMerge, twJoin } from 'tailwind-merge'
import { useUI } from '../../composables/useUI'
import { mergeConfig } from '../../utils'
import type { Strategy } from '../../types'
import type { KbdSize, Strategy } from '../../types'
// @ts-expect-error
import appConfig from '#build/app.config'
import { kbd } from '#ui/ui.config'
@@ -25,7 +25,7 @@ export default defineComponent({
default: null
},
size: {
type: String as PropType<keyof typeof config.size>,
type: String as PropType<KbdSize>,
default: () => config.default.size,
validator (value: string) {
return Object.keys(config.size).includes(value)

View File

@@ -42,7 +42,7 @@ import { computed, defineComponent, provide, inject, ref, toRef } from 'vue'
import type { Ref, PropType } from 'vue'
import { useUI } from '../../composables/useUI'
import { mergeConfig } from '../../utils'
import type { FormError, InjectedFormGroupValue, Strategy } from '../../types'
import type { FormError, InjectedFormGroupValue, FormGroupSize, Strategy } from '../../types'
// @ts-expect-error
import appConfig from '#build/app.config'
import { formGroup } from '#ui/ui.config'
@@ -57,7 +57,7 @@ export default defineComponent({
default: null
},
size: {
type: String as PropType<keyof typeof config.size>,
type: String as PropType<FormGroupSize>,
default: null,
validator (value: string) {
return Object.keys(config.size).includes(value)

View File

@@ -41,11 +41,10 @@ import { defu } from 'defu'
import { useUI } from '../../composables/useUI'
import { useFormGroup } from '../../composables/useFormGroup'
import { mergeConfig, looseToNumber } from '../../utils'
import type { NestedKeyOf, Strategy } from '../../types'
import type { InputSize, InputColor, InputVariant, Strategy } from '../../types'
// @ts-expect-error
import appConfig from '#build/app.config'
import { input } from '#ui/ui.config'
import colors from '#ui-colors'
const config = mergeConfig<typeof input>(appConfig.ui.strategy, appConfig.ui.input, input)
@@ -124,21 +123,21 @@ export default defineComponent({
default: true
},
size: {
type: String as PropType<keyof typeof config.size>,
type: String as PropType<InputSize>,
default: null,
validator (value: string) {
return Object.keys(config.size).includes(value)
}
},
color: {
type: String as PropType<keyof typeof config.color | typeof colors[number]>,
type: String as PropType<InputColor>,
default: () => config.default.color,
validator (value: string) {
return [...appConfig.ui.colors, ...Object.keys(config.color)].includes(value)
}
},
variant: {
type: String as PropType<keyof typeof config.variant | NestedKeyOf<typeof config.color>>,
type: String as PropType<InputVariant>,
default: () => config.default.variant,
validator (value: string) {
return [
@@ -171,7 +170,7 @@ export default defineComponent({
const { emitFormBlur, emitFormInput, size, color, inputId, name } = useFormGroup(props, config)
const modelModifiers = ref(defu({}, props.modelModifiers, { trim: false, lazy: false, number: false }))
const input = ref<HTMLInputElement | null>(null)
const autoFocus = () => {

View File

@@ -26,7 +26,7 @@ import { twMerge, twJoin } from 'tailwind-merge'
import { useUI } from '../../composables/useUI'
import { useFormGroup } from '../../composables/useFormGroup'
import { mergeConfig } from '../../utils'
import type { Strategy } from '../../types'
import type { RangeSize, Strategy } from '../../types'
// @ts-expect-error
import appConfig from '#build/app.config'
import { range } from '#ui/ui.config'
@@ -66,7 +66,7 @@ export default defineComponent({
default: 1
},
size: {
type: String as PropType<keyof typeof config.size>,
type: String as PropType<RangeSize>,
default: null,
validator (value: string) {
return Object.keys(config.size).includes(value)

View File

@@ -61,11 +61,10 @@ import UIcon from '../elements/Icon.vue'
import { useUI } from '../../composables/useUI'
import { useFormGroup } from '../../composables/useFormGroup'
import { mergeConfig, get } from '../../utils'
import type { NestedKeyOf, Strategy } from '../../types'
import type { SelectSize, SelectColor, SelectVariant, Strategy } from '../../types'
// @ts-expect-error
import appConfig from '#build/app.config'
import { select } from '#ui/ui.config'
import colors from '#ui-colors'
const config = mergeConfig<typeof select>(appConfig.ui.strategy, appConfig.ui.select, select)
@@ -136,21 +135,21 @@ export default defineComponent({
default: () => []
},
size: {
type: String as PropType<keyof typeof config.size>,
type: String as PropType<SelectSize>,
default: null,
validator (value: string) {
return Object.keys(config.size).includes(value)
}
},
color: {
type: String as PropType<keyof typeof config.color | typeof colors[number]>,
type: String as PropType<SelectColor>,
default: () => config.default.color,
validator (value: string) {
return [...appConfig.ui.colors, ...Object.keys(config.color)].includes(value)
}
},
variant: {
type: String as PropType<keyof typeof config.variant | NestedKeyOf<typeof config.color>>,
type: String as PropType<SelectVariant>,
default: () => config.default.variant,
validator (value: string) {
return [

View File

@@ -86,17 +86,17 @@
aria-hidden="true"
/>
<span v-else-if="option.chip" :class="uiMenu.option.chip.base" :style="{ background: `#${option.chip}` }" />
<span class="truncate">{{ ['string', 'number'].includes(typeof option) ? option : option[optionAttribute] }}</span>
</slot>
</div>
<span v-if="selected" :class="[uiMenu.option.selectedIcon.wrapper, uiMenu.option.selectedIcon.padding]">
<UIcon :name="selectedIcon" :class="uiMenu.option.selectedIcon.base" aria-hidden="true" />
</span>
</li>
</component>
<component :is="searchable ? 'HComboboxOption' : 'HListboxOption'" v-if="creatable && queryOption && !filteredOptions.length" v-slot="{ active, selected }" :value="queryOption" as="template">
<li :class="[uiMenu.option.base, uiMenu.option.rounded, uiMenu.option.padding, uiMenu.option.size, uiMenu.option.color, active ? uiMenu.option.active : uiMenu.option.inactive]">
<div :class="uiMenu.option.container">
@@ -141,11 +141,10 @@ import { useUI } from '../../composables/useUI'
import { usePopper } from '../../composables/usePopper'
import { useFormGroup } from '../../composables/useFormGroup'
import { mergeConfig } from '../../utils'
import type { PopperOptions, NestedKeyOf, Strategy } from '../../types'
import type { SelectSize, SelectColor, SelectVariant, PopperOptions, Strategy } from '../../types'
// @ts-expect-error
import appConfig from '#build/app.config'
import { select, selectMenu } from '#ui/ui.config'
import colors from '#ui-colors'
const config = mergeConfig<typeof select>(appConfig.ui.strategy, appConfig.ui.select, select)
@@ -256,21 +255,21 @@ export default defineComponent({
default: true
},
size: {
type: String as PropType<keyof typeof config.size>,
type: String as PropType<SelectSize>,
default: null,
validator (value: string) {
return Object.keys(config.size).includes(value)
}
},
color: {
type: String as PropType<keyof typeof config.color | typeof colors[number]>,
type: String as PropType<SelectColor>,
default: () => config.default.color,
validator (value: string) {
return [...appConfig.ui.colors, ...Object.keys(config.color)].includes(value)
}
},
variant: {
type: String as PropType<keyof typeof config.variant | NestedKeyOf<typeof config.color>>,
type: String as PropType<SelectVariant>,
default: () => config.default.variant,
validator (value: string) {
return [

View File

@@ -27,11 +27,10 @@ import { defu } from 'defu'
import { useUI } from '../../composables/useUI'
import { useFormGroup } from '../../composables/useFormGroup'
import { mergeConfig, looseToNumber } from '../../utils'
import type { NestedKeyOf, Strategy } from '../../types'
import type { TextareaSize, TextareaColor, TextareaVariant, Strategy } from '../../types'
// @ts-expect-error
import appConfig from '#build/app.config'
import { textarea } from '#ui/ui.config'
import colors from '#ui-colors'
const config = mergeConfig<typeof textarea>(appConfig.ui.strategy, appConfig.ui.textarea, textarea)
@@ -87,21 +86,21 @@ export default defineComponent({
default: true
},
size: {
type: String as PropType<keyof typeof config.size>,
type: String as PropType<TextareaSize>,
default: null,
validator (value: string) {
return Object.keys(config.size).includes(value)
}
},
color: {
type: String as PropType<keyof typeof config.color | typeof colors[number]>,
type: String as PropType<TextareaColor>,
default: () => config.default.color,
validator (value: string) {
return [...appConfig.ui.colors, ...Object.keys(config.color)].includes(value)
}
},
variant: {
type: String as PropType<keyof typeof config.variant | NestedKeyOf<typeof config.color>>,
type: String as PropType<TextareaVariant>,
default: () => config.default.variant,
validator (value: string) {
return [
@@ -181,7 +180,7 @@ export default defineComponent({
const onInput = (event: InputEvent) => {
autoResize()
if (!modelModifiers.value.lazy) {
if (!modelModifiers.value.lazy) {
updateInput((event.target as HTMLInputElement).value)
}
}

View File

@@ -27,7 +27,7 @@ import UIcon from '../elements/Icon.vue'
import { useUI } from '../../composables/useUI'
import { useFormGroup } from '../../composables/useFormGroup'
import { mergeConfig } from '../../utils'
import type { Strategy } from '../../types'
import type { ToggleSize, Strategy } from '../../types'
// @ts-expect-error
import appConfig from '#build/app.config'
import { toggle } from '#ui/ui.config'
@@ -78,7 +78,7 @@ export default defineComponent({
default: undefined
},
size: {
type: String as PropType<keyof typeof config.size>,
type: String as PropType<ToggleSize>,
default: config.default.size,
validator (value: string) {
return Object.keys(config.size).includes(value)

View File

@@ -71,7 +71,7 @@ import type { PropType } from 'vue'
import UButton from '../elements/Button.vue'
import { useUI } from '../../composables/useUI'
import { mergeConfig } from '../../utils'
import type { Button, Strategy } from '../../types'
import type { Button, ButtonSize, Strategy } from '../../types'
// @ts-expect-error
import appConfig from '#build/app.config'
import { pagination, button } from '#ui/ui.config'
@@ -106,7 +106,7 @@ export default defineComponent({
}
},
size: {
type: String as PropType<keyof typeof buttonConfig.size>,
type: String as PropType<ButtonSize>,
default: () => config.default.size,
validator (value: string) {
return Object.keys(buttonConfig.size).includes(value)

7
src/runtime/types/alert.d.ts vendored Normal file
View File

@@ -0,0 +1,7 @@
import { alert } from '../ui.config'
import type { NestedKeyOf, ExtractDeepKey, ExtractDeepObject } from '.'
import colors from '#ui-colors'
import type { AppConfig } from 'nuxt/schema'
export type AlertColor = keyof typeof alert.color | ExtractDeepKey<AppConfig, ['ui', 'alert', 'color']> | typeof colors[number]
export type AlertVariant = keyof typeof alert.variant | ExtractDeepKey<AppConfig, ['ui', 'alert', 'variant']> | NestedKeyOf<typeof alert.color> | NestedKeyOf<ExtractDeepObject<AppConfig, ['ui', 'alert', 'color']>>

View File

@@ -1,7 +1,9 @@
import { avatar } from '../ui.config'
import type { ExtractDeepKey } from '.'
import colors from '#ui-colors'
import type { AppConfig } from 'nuxt/schema'
export type AvatarSize = keyof typeof avatar.size
export type AvatarSize = keyof typeof avatar.size | ExtractDeepKey<AppConfig, ['ui', 'avatar', 'size']>
export type AvatarChipColor = 'gray' | typeof colors[number]
export type AvatarChipPosition = keyof typeof avatar.chip.position

View File

@@ -1,10 +1,11 @@
import { badge } from '../ui.config'
import type { NestedKeyOf } from '.'
import type { NestedKeyOf, ExtractDeepKey, ExtractDeepObject } from '.'
import colors from '#ui-colors'
import type { AppConfig } from 'nuxt/schema'
export type BadgeSize = keyof typeof badge.size
export type BadgeColor = keyof typeof badge.color | typeof colors[number]
export type BadgeVariant = keyof typeof badge.variant | NestedKeyOf<typeof badge.color>
export type BadgeSize = keyof typeof badge.size | ExtractDeepKey<AppConfig, ['ui', 'badge', 'size']>
export type BadgeColor = keyof typeof badge.color | ExtractDeepKey<AppConfig, ['ui', 'badge', 'color']> | typeof colors[number]
export type BadgeVariant = keyof typeof badge.variant | ExtractDeepKey<AppConfig, ['ui', 'badge', 'variant']> | NestedKeyOf<typeof badge.color> | NestedKeyOf<ExtractDeepObject<AppConfig, ['ui', 'badge', 'color']>>
export interface Badge {
label?: string

View File

@@ -1,11 +1,12 @@
import type { Link } from './link'
import { button } from '../ui.config'
import type { NestedKeyOf } from '.'
import type { NestedKeyOf, ExtractDeepKey, ExtractDeepObject } from '.'
import colors from '#ui-colors'
import type { AppConfig } from 'nuxt/schema'
export type ButtonSize = keyof typeof button.size
export type ButtonColor = keyof typeof button.color | typeof colors[number]
export type ButtonVariant = keyof typeof button.variant | NestedKeyOf<typeof button.color>
export type ButtonSize = keyof typeof button.size | ExtractDeepKey<AppConfig, ['ui', 'button', 'size']>
export type ButtonColor = keyof typeof button.color | ExtractDeepKey<AppConfig, ['ui', 'button', 'color']> | typeof colors[number]
export type ButtonVariant = keyof typeof button.variant | ExtractDeepKey<AppConfig, ['ui', 'button', 'variant']> | NestedKeyOf<typeof button.color> | NestedKeyOf<ExtractDeepObject<AppConfig, ['ui', 'button', 'color']>>
export interface Button extends Link {
type?: string

5
src/runtime/types/form-group.d.ts vendored Normal file
View File

@@ -0,0 +1,5 @@
import { formGroup } from '../ui.config'
import type { ExtractDeepKey } from '.'
import type { AppConfig } from 'nuxt/schema'
export type FormGroupSize = keyof typeof formGroup.size | ExtractDeepKey<AppConfig, ['ui', 'formGroup', 'size']>

View File

@@ -1,4 +1,4 @@
import { Ref } from 'vue'
import type { Ref } from 'vue'
export interface FormError<T extends string = string> {
path: T

View File

@@ -1,4 +1,5 @@
export * from './accordion'
export * from './alert'
export * from './avatar'
export * from './badge'
export * from './breadcrumb'
@@ -6,12 +7,19 @@ export * from './button'
export * from './clipboard'
export * from './command-palette'
export * from './dropdown'
export * from './form-group'
export * from './form'
export * from './input'
export * from './kbd'
export * from './link'
export * from './meter'
export * from './notification'
export * from './popper'
export * from './progress'
export * from './range'
export * from './select'
export * from './tabs'
export * from './textarea'
export * from './toggle'
export * from './vertical-navigation'
export * from './utils'

8
src/runtime/types/input.d.ts vendored Normal file
View File

@@ -0,0 +1,8 @@
import { input } from '../ui.config'
import type { NestedKeyOf, ExtractDeepKey, ExtractDeepObject } from '.'
import colors from '#ui-colors'
import type { AppConfig } from 'nuxt/schema'
export type InputSize = keyof typeof input.size | ExtractDeepKey<AppConfig, ['ui', 'input', 'size']>
export type InputColor = keyof typeof input.color | ExtractDeepKey<AppConfig, ['ui', 'input', 'color']> | typeof colors[number]
export type InputVariant = keyof typeof input.variant | ExtractDeepKey<AppConfig, ['ui', 'input', 'variant']> | NestedKeyOf<typeof input.color> | NestedKeyOf<ExtractDeepObject<AppConfig, ['ui', 'input', 'color']>>

5
src/runtime/types/kbd.d.ts vendored Normal file
View File

@@ -0,0 +1,5 @@
import { kbd } from '../ui.config'
import type { ExtractDeepKey } from '.'
import type { AppConfig } from 'nuxt/schema'
export type KbdSize = keyof typeof kbd.size | ExtractDeepKey<AppConfig, ['ui', 'kbd', 'size']>

5
src/runtime/types/range.d.ts vendored Normal file
View File

@@ -0,0 +1,5 @@
import { range } from '../ui.config'
import type { ExtractDeepKey } from '.'
import type { AppConfig } from 'nuxt/schema'
export type RangeSize = keyof typeof range.size | ExtractDeepKey<AppConfig, ['ui', 'range', 'size']>

8
src/runtime/types/select.d.ts vendored Normal file
View File

@@ -0,0 +1,8 @@
import { select } from '../ui.config'
import type { NestedKeyOf, ExtractDeepKey, ExtractDeepObject } from '.'
import colors from '#ui-colors'
import type { AppConfig } from 'nuxt/schema'
export type SelectSize = keyof typeof select.size | ExtractDeepKey<AppConfig, ['ui', 'select', 'size']>
export type SelectColor = keyof typeof select.color | ExtractDeepKey<AppConfig, ['ui', 'select', 'color']> | typeof colors[number]
export type SelectVariant = keyof typeof select.variant | ExtractDeepKey<AppConfig, ['ui', 'select', 'variant']> | NestedKeyOf<typeof select.color> | NestedKeyOf<ExtractDeepObject<AppConfig, ['ui', 'select', 'color']>>

8
src/runtime/types/textarea.d.ts vendored Normal file
View File

@@ -0,0 +1,8 @@
import { textarea } from '../ui.config'
import type { NestedKeyOf, ExtractDeepKey, ExtractDeepObject } from '.'
import colors from '#ui-colors'
import type { AppConfig } from 'nuxt/schema'
export type TextareaSize = keyof typeof textarea.size | ExtractDeepKey<AppConfig, ['ui', 'textarea', 'size']>
export type TextareaColor = keyof typeof textarea.color | ExtractDeepKey<AppConfig, ['ui', 'textarea', 'color']> | typeof colors[number]
export type TextareaVariant = keyof typeof textarea.variant | ExtractDeepKey<AppConfig, ['ui', 'textarea', 'variant']> | NestedKeyOf<typeof textarea.color> | NestedKeyOf<ExtractDeepObject<AppConfig, ['ui', 'textarea', 'color']>>

5
src/runtime/types/toggle.d.ts vendored Normal file
View File

@@ -0,0 +1,5 @@
import { toggle } from '../ui.config'
import type { ExtractDeepKey } from '.'
import type { AppConfig } from 'nuxt/schema'
export type ToggleSize = keyof typeof toggle.size | ExtractDeepKey<AppConfig, ['ui', 'toggle', 'size']>

View File

@@ -1,11 +1,28 @@
export type Strategy = 'merge' | 'override';
export type Strategy = 'merge' | 'override'
export type NestedKeyOf<ObjectType extends object> = {
[Key in keyof ObjectType]: ObjectType[Key] extends object
? NestedKeyOf<ObjectType[Key]>
: Key;
}[keyof ObjectType];
: Key
}[keyof ObjectType]
export type DeepPartial<T> = Partial<{
[P in keyof T]: DeepPartial<T[P]> | { [key: string]: string | object };
}>;
[P in keyof T]: DeepPartial<T[P]> | { [key: string]: string | object }
}>
type DeepKey<T, Keys extends string[]> =
Keys extends [infer First, ...infer Rest]
? First extends keyof T
? Rest extends string[]
? DeepKey<T[First], Rest>
: never
: never
: T
export type ExtractDeepKey<T, Path extends string[]> = DeepKey<T, Path> extends infer Result
? Result extends object ? keyof Result : never
: never
export type ExtractDeepObject<T, Path extends string[]> = DeepKey<T, Path> extends infer Result
? Result extends object ? Result : never
: never

View File

@@ -39,7 +39,7 @@ export function hexToRgb (hex: string) {
export function getSlotsChildren (slots: any) {
let children = slots.default?.()
if (children.length) {
if (children?.length) {
children = children.flatMap(c => {
if (typeof c.type === 'symbol') {
if (typeof c.children === 'string') {
@@ -53,7 +53,7 @@ export function getSlotsChildren (slots: any) {
return c
}).filter(Boolean)
}
return children
return children || []
}
/**