mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-22 16:00:39 +01:00
feat(module)!: use tailwind-merge for class merging (#509)
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<div :class="ui.wrapper">
|
||||
<div :class="wrapperClass">
|
||||
<HDisclosure v-for="(item, index) in items" v-slot="{ open, close }" :key="index" :default-open="defaultOpen || item.defaultOpen">
|
||||
<HDisclosureButton :ref="() => buttonRefs[index] = close" as="template" :disabled="item.disabled">
|
||||
<slot :item="item" :index="index" :open="open" :close="close">
|
||||
<UButton v-bind="{ ...omit(ui.default, ['openIcon', 'closeIcon']), ...$attrs, ...omit(item, ['slot', 'disabled', 'content', 'defaultOpen']) }">
|
||||
<UButton v-bind="{ ...omit(ui.default, ['openIcon', 'closeIcon']), ...attrs, ...omit(item, ['slot', 'disabled', 'content', 'defaultOpen']) }">
|
||||
<template #trailing>
|
||||
<UIcon
|
||||
:name="!open ? openIcon : closeIcon ? closeIcon : openIcon"
|
||||
@@ -43,10 +43,11 @@
|
||||
import { ref, computed, defineComponent } from 'vue'
|
||||
import type { PropType } from 'vue'
|
||||
import { Disclosure as HDisclosure, DisclosureButton as HDisclosureButton, DisclosurePanel as HDisclosurePanel } from '@headlessui/vue'
|
||||
import { defu } from 'defu'
|
||||
import { omit } from 'lodash-es'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import UIcon from '../elements/Icon.vue'
|
||||
import UButton from '../elements/Button.vue'
|
||||
import { defuTwMerge } from '../../utils'
|
||||
import StateEmitter from '../../utils/StateEmitter'
|
||||
import type { AccordionItem } from '../../types/accordion'
|
||||
import { useAppConfig } from '#imports'
|
||||
@@ -87,17 +88,19 @@ export default defineComponent({
|
||||
},
|
||||
ui: {
|
||||
type: Object as PropType<Partial<typeof appConfig.ui.accordion>>,
|
||||
default: () => appConfig.ui.accordion
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
setup (props) {
|
||||
setup (props, { attrs }) {
|
||||
// TODO: Remove
|
||||
const appConfig = useAppConfig()
|
||||
|
||||
const ui = computed<Partial<typeof appConfig.ui.accordion>>(() => defu({}, props.ui, appConfig.ui.accordion))
|
||||
const ui = computed<Partial<typeof appConfig.ui.accordion>>(() => defuTwMerge({}, props.ui, appConfig.ui.accordion))
|
||||
|
||||
const uiButton = computed<Partial<typeof appConfig.ui.button>>(() => appConfig.ui.button)
|
||||
|
||||
const wrapperClass = computed(() => twMerge(ui.value.wrapper, attrs.class as string))
|
||||
|
||||
const buttonRefs = ref<Function[]>([])
|
||||
|
||||
function closeOthers (itemIndex: number) {
|
||||
@@ -136,9 +139,11 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
return {
|
||||
attrs: omit(attrs, ['class']),
|
||||
// eslint-disable-next-line vue/no-dupe-keys
|
||||
ui,
|
||||
uiButton,
|
||||
wrapperClass,
|
||||
buttonRefs,
|
||||
closeOthers,
|
||||
omit,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div :class="alertClass">
|
||||
<div :class="alertClass" v-bind="attrs">
|
||||
<div class="flex gap-3" :class="{ 'items-start': (description || $slots.description), 'items-center': !description && !$slots.description }">
|
||||
<UIcon v-if="icon" :name="icon" :class="ui.icon.base" />
|
||||
<UAvatar v-if="avatar" v-bind="{ size: ui.avatar.size, ...avatar }" :class="ui.avatar.base" />
|
||||
@@ -34,17 +34,18 @@
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent } from 'vue'
|
||||
import type { PropType } from 'vue'
|
||||
import { defu } from 'defu'
|
||||
import { twMerge, twJoin } from 'tailwind-merge'
|
||||
import UIcon from '../elements/Icon.vue'
|
||||
import UAvatar from '../elements/Avatar.vue'
|
||||
import UButton from '../elements/Button.vue'
|
||||
import type { Avatar } from '../../types/avatar'
|
||||
import type { Button } from '../../types/button'
|
||||
import { classNames } from '../../utils'
|
||||
import { defuTwMerge } from '../../utils'
|
||||
import { useAppConfig } from '#imports'
|
||||
// TODO: Remove
|
||||
// @ts-expect-error
|
||||
import appConfig from '#build/app.config'
|
||||
import { omit } from 'lodash-es'
|
||||
|
||||
// const appConfig = useAppConfig()
|
||||
|
||||
@@ -54,6 +55,7 @@ export default defineComponent({
|
||||
UAvatar,
|
||||
UButton
|
||||
},
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
@@ -98,29 +100,30 @@ export default defineComponent({
|
||||
},
|
||||
ui: {
|
||||
type: Object as PropType<Partial<typeof appConfig.ui.alert>>,
|
||||
default: () => appConfig.ui.alert
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
emits: ['close'],
|
||||
setup (props) {
|
||||
setup (props, { attrs }) {
|
||||
// TODO: Remove
|
||||
const appConfig = useAppConfig()
|
||||
|
||||
const ui = computed<Partial<typeof appConfig.ui.alert>>(() => defu({}, props.ui, appConfig.ui.alert))
|
||||
const ui = computed<Partial<typeof appConfig.ui.alert>>(() => defuTwMerge({}, props.ui, appConfig.ui.alert))
|
||||
|
||||
const alertClass = computed(() => {
|
||||
const variant = ui.value.color?.[props.color as string]?.[props.variant as string] || ui.value.variant[props.variant]
|
||||
|
||||
return classNames(
|
||||
return twMerge(twJoin(
|
||||
ui.value.wrapper,
|
||||
ui.value.rounded,
|
||||
ui.value.shadow,
|
||||
ui.value.padding,
|
||||
variant?.replaceAll('{color}', props.color)
|
||||
)
|
||||
), attrs.class as string)
|
||||
})
|
||||
|
||||
return {
|
||||
attrs: omit(attrs, ['class']),
|
||||
// eslint-disable-next-line vue/no-dupe-keys
|
||||
ui,
|
||||
alertClass
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
<span :class="wrapperClass">
|
||||
<img
|
||||
v-if="url && !error"
|
||||
:class="avatarClass"
|
||||
:class="imgClass"
|
||||
:alt="alt"
|
||||
:src="url"
|
||||
v-bind="$attrs"
|
||||
v-bind="attrs"
|
||||
@error="onError"
|
||||
>
|
||||
<span v-else-if="text" :class="ui.text">{{ text }}</span>
|
||||
@@ -22,13 +22,14 @@
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, computed, watch } from 'vue'
|
||||
import type { PropType } from 'vue'
|
||||
import { defu } from 'defu'
|
||||
import { twMerge, twJoin } from 'tailwind-merge'
|
||||
import UIcon from '../elements/Icon.vue'
|
||||
import { classNames } from '../../utils'
|
||||
import { defuTwMerge } from '../../utils'
|
||||
import { useAppConfig } from '#imports'
|
||||
// TODO: Remove
|
||||
// @ts-expect-error
|
||||
import appConfig from '#build/app.config'
|
||||
import { omit } from 'lodash-es'
|
||||
|
||||
// const appConfig = useAppConfig()
|
||||
|
||||
@@ -79,16 +80,20 @@ export default defineComponent({
|
||||
type: [String, Number],
|
||||
default: null
|
||||
},
|
||||
imgClass: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
ui: {
|
||||
type: Object as PropType<Partial<typeof appConfig.ui.avatar>>,
|
||||
default: () => appConfig.ui.avatar
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
setup (props) {
|
||||
setup (props, { attrs }) {
|
||||
// TODO: Remove
|
||||
const appConfig = useAppConfig()
|
||||
|
||||
const ui = computed<Partial<typeof appConfig.ui.avatar>>(() => defu({}, props.ui, appConfig.ui.avatar))
|
||||
const ui = computed<Partial<typeof appConfig.ui.avatar>>(() => defuTwMerge({}, props.ui, appConfig.ui.avatar))
|
||||
|
||||
const url = computed(() => {
|
||||
if (typeof props.src === 'boolean') {
|
||||
@@ -102,30 +107,30 @@ export default defineComponent({
|
||||
})
|
||||
|
||||
const wrapperClass = computed(() => {
|
||||
return classNames(
|
||||
return twMerge(twJoin(
|
||||
ui.value.wrapper,
|
||||
(error.value || !url.value) && ui.value.background,
|
||||
ui.value.rounded,
|
||||
ui.value.size[props.size]
|
||||
)
|
||||
), attrs.class as string)
|
||||
})
|
||||
|
||||
const avatarClass = computed(() => {
|
||||
return classNames(
|
||||
const imgClass = computed(() => {
|
||||
return twMerge(twJoin(
|
||||
ui.value.rounded,
|
||||
ui.value.size[props.size]
|
||||
)
|
||||
), props.imgClass)
|
||||
})
|
||||
|
||||
const iconClass = computed(() => {
|
||||
return classNames(
|
||||
return twJoin(
|
||||
ui.value.icon.base,
|
||||
ui.value.icon.size[props.size]
|
||||
)
|
||||
})
|
||||
|
||||
const chipClass = computed(() => {
|
||||
return classNames(
|
||||
return twJoin(
|
||||
ui.value.chip.base,
|
||||
ui.value.chip.size[props.size],
|
||||
ui.value.chip.position[props.chipPosition],
|
||||
@@ -146,8 +151,10 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
return {
|
||||
attrs: omit(attrs, ['class']),
|
||||
wrapperClass,
|
||||
avatarClass,
|
||||
// eslint-disable-next-line vue/no-dupe-keys
|
||||
imgClass,
|
||||
iconClass,
|
||||
chipClass,
|
||||
url,
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { h, cloneVNode, computed, defineComponent } from 'vue'
|
||||
import type { PropType } from 'vue'
|
||||
import { defu } from 'defu'
|
||||
import { classNames, getSlotsChildren } from '../../utils'
|
||||
import { omit } from 'lodash-es'
|
||||
import { twMerge, twJoin } from 'tailwind-merge'
|
||||
import { defuTwMerge, getSlotsChildren } from '../../utils'
|
||||
import Avatar from './Avatar.vue'
|
||||
import { useAppConfig } from '#imports'
|
||||
// TODO: Remove
|
||||
@@ -11,6 +12,7 @@ import appConfig from '#build/app.config'
|
||||
// const appConfig = useAppConfig()
|
||||
|
||||
export default defineComponent({
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
size: {
|
||||
type: String,
|
||||
@@ -25,14 +27,14 @@ export default defineComponent({
|
||||
},
|
||||
ui: {
|
||||
type: Object as PropType<Partial<typeof appConfig.ui.avatarGroup>>,
|
||||
default: () => appConfig.ui.avatarGroup
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
setup (props, { slots }) {
|
||||
setup (props, { attrs, slots }) {
|
||||
// TODO: Remove
|
||||
const appConfig = useAppConfig()
|
||||
|
||||
const ui = computed<Partial<typeof appConfig.ui.avatarGroup>>(() => defu({}, props.ui, appConfig.ui.avatarGroup))
|
||||
const ui = computed<Partial<typeof appConfig.ui.avatarGroup>>(() => defuTwMerge({}, props.ui, appConfig.ui.avatarGroup))
|
||||
|
||||
const children = computed(() => getSlotsChildren(slots))
|
||||
|
||||
@@ -46,13 +48,8 @@ export default defineComponent({
|
||||
vProps.size = props.size
|
||||
}
|
||||
|
||||
vProps.ui = node.props.ui || {}
|
||||
vProps.ui.wrapper = classNames(
|
||||
appConfig.ui.avatar.wrapper,
|
||||
vProps.ui.wrapper || '',
|
||||
ui.value.ring,
|
||||
ui.value.margin
|
||||
)
|
||||
vProps.class = node.props.class || ''
|
||||
vProps.class = twMerge(twJoin(vProps.class, ui.value.ring, ui.value.margin), vProps.class)
|
||||
|
||||
return cloneVNode(node, vProps)
|
||||
}
|
||||
@@ -61,19 +58,13 @@ export default defineComponent({
|
||||
return h(Avatar, {
|
||||
size: props.size,
|
||||
text: `+${children.value.length - max.value}`,
|
||||
ui: {
|
||||
wrapper: classNames(
|
||||
appConfig.ui.avatar.wrapper,
|
||||
ui.value.ring,
|
||||
ui.value.margin
|
||||
)
|
||||
}
|
||||
class: twJoin(ui.value.ring, ui.value.margin)
|
||||
})
|
||||
}
|
||||
|
||||
return null
|
||||
}).filter(Boolean).reverse())
|
||||
|
||||
return () => h('div', { class: ui.value.wrapper }, clones.value)
|
||||
return () => h('div', { class: twMerge(ui.value.wrapper, attrs.class as string), ...omit(attrs, ['class']) }, clones.value)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<span :class="badgeClass">
|
||||
<span :class="badgeClass" v-bind="attrs">
|
||||
<slot>{{ label }}</slot>
|
||||
</span>
|
||||
</template>
|
||||
@@ -7,8 +7,9 @@
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent } from 'vue'
|
||||
import type { PropType } from 'vue'
|
||||
import { defu } from 'defu'
|
||||
import { classNames } from '../../utils'
|
||||
import { omit } from 'lodash-es'
|
||||
import { twMerge, twJoin } from 'tailwind-merge'
|
||||
import { defuTwMerge } from '../../utils'
|
||||
import { useAppConfig } from '#imports'
|
||||
// TODO: Remove
|
||||
// @ts-expect-error
|
||||
@@ -17,6 +18,7 @@ import appConfig from '#build/app.config'
|
||||
// const appConfig = useAppConfig()
|
||||
|
||||
export default defineComponent({
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
size: {
|
||||
type: String,
|
||||
@@ -48,28 +50,29 @@ export default defineComponent({
|
||||
},
|
||||
ui: {
|
||||
type: Object as PropType<Partial<typeof appConfig.ui.badge>>,
|
||||
default: () => appConfig.ui.badge
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
setup (props) {
|
||||
setup (props, { attrs }) {
|
||||
// TODO: Remove
|
||||
const appConfig = useAppConfig()
|
||||
|
||||
const ui = computed<Partial<typeof appConfig.ui.badge>>(() => defu({}, props.ui, appConfig.ui.badge))
|
||||
const ui = computed<Partial<typeof appConfig.ui.badge>>(() => defuTwMerge({}, props.ui, appConfig.ui.badge))
|
||||
|
||||
const badgeClass = computed(() => {
|
||||
const variant = ui.value.color?.[props.color as string]?.[props.variant as string] || ui.value.variant[props.variant]
|
||||
|
||||
return classNames(
|
||||
return twMerge(twJoin(
|
||||
ui.value.base,
|
||||
ui.value.font,
|
||||
ui.value.rounded,
|
||||
ui.value.size[props.size],
|
||||
variant?.replaceAll('{color}', props.color)
|
||||
)
|
||||
), attrs.class as string)
|
||||
})
|
||||
|
||||
return {
|
||||
attrs: omit(attrs, ['class']),
|
||||
badgeClass
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<ULink :type="type" :disabled="disabled || loading" :class="buttonClass">
|
||||
<ULink :type="type" :disabled="disabled || loading" :class="buttonClass" v-bind="attrs">
|
||||
<slot name="leading" :disabled="disabled" :loading="loading">
|
||||
<UIcon v-if="isLeading && leadingIconName" :name="leadingIconName" :class="leadingIconClass" aria-hidden="true" />
|
||||
</slot>
|
||||
@@ -17,12 +17,13 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, useSlots } from 'vue'
|
||||
import { computed, defineComponent } from 'vue'
|
||||
import type { PropType } from 'vue'
|
||||
import { defu } from 'defu'
|
||||
import { omit } from 'lodash-es'
|
||||
import { twMerge, twJoin } from 'tailwind-merge'
|
||||
import UIcon from '../elements/Icon.vue'
|
||||
import ULink from '../elements/Link.vue'
|
||||
import { classNames } from '../../utils'
|
||||
import { defuTwMerge } from '../../utils'
|
||||
import { useAppConfig } from '#imports'
|
||||
// TODO: Remove
|
||||
// @ts-expect-error
|
||||
@@ -35,6 +36,7 @@ export default defineComponent({
|
||||
UIcon,
|
||||
ULink
|
||||
},
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
@@ -118,16 +120,14 @@ export default defineComponent({
|
||||
},
|
||||
ui: {
|
||||
type: Object as PropType<Partial<typeof appConfig.ui.button>>,
|
||||
default: () => appConfig.ui.button
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
setup (props) {
|
||||
setup (props, { attrs, slots }) {
|
||||
// TODO: Remove
|
||||
const appConfig = useAppConfig()
|
||||
|
||||
const slots = useSlots()
|
||||
|
||||
const ui = computed<Partial<typeof appConfig.ui.button>>(() => defu({}, props.ui, appConfig.ui.button))
|
||||
const ui = computed<Partial<typeof appConfig.ui.button>>(() => defuTwMerge({}, props.ui, appConfig.ui.button))
|
||||
|
||||
const isLeading = computed(() => {
|
||||
return (props.icon && props.leading) || (props.icon && !props.trailing) || (props.loading && !props.trailing) || props.leadingIcon
|
||||
@@ -142,7 +142,7 @@ export default defineComponent({
|
||||
const buttonClass = computed(() => {
|
||||
const variant = ui.value.color?.[props.color as string]?.[props.variant as string] || ui.value.variant[props.variant]
|
||||
|
||||
return classNames(
|
||||
return twMerge(twJoin(
|
||||
ui.value.base,
|
||||
ui.value.font,
|
||||
ui.value.rounded,
|
||||
@@ -151,7 +151,7 @@ export default defineComponent({
|
||||
props.padded && ui.value[isSquare.value ? 'square' : 'padding'][props.size],
|
||||
variant?.replaceAll('{color}', props.color),
|
||||
props.block ? 'w-full flex justify-center items-center' : 'inline-flex items-center'
|
||||
)
|
||||
), attrs.class as string)
|
||||
})
|
||||
|
||||
const leadingIconName = computed(() => {
|
||||
@@ -171,7 +171,7 @@ export default defineComponent({
|
||||
})
|
||||
|
||||
const leadingIconClass = computed(() => {
|
||||
return classNames(
|
||||
return twJoin(
|
||||
ui.value.icon.base,
|
||||
ui.value.icon.size[props.size],
|
||||
props.loading && 'animate-spin'
|
||||
@@ -179,7 +179,7 @@ export default defineComponent({
|
||||
})
|
||||
|
||||
const trailingIconClass = computed(() => {
|
||||
return classNames(
|
||||
return twJoin(
|
||||
ui.value.icon.base,
|
||||
ui.value.icon.size[props.size],
|
||||
props.loading && !isLeading.value && 'animate-spin'
|
||||
@@ -187,6 +187,7 @@ export default defineComponent({
|
||||
})
|
||||
|
||||
return {
|
||||
attrs: omit(attrs, ['class']),
|
||||
isLeading,
|
||||
isTrailing,
|
||||
isSquare,
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { h, cloneVNode, computed, defineComponent } from 'vue'
|
||||
import type { PropType } from 'vue'
|
||||
import { defu } from 'defu'
|
||||
import { getSlotsChildren } from '../../utils'
|
||||
import { omit } from 'lodash-es'
|
||||
import { twMerge, twJoin } from 'tailwind-merge'
|
||||
import { defuTwMerge, getSlotsChildren } from '../../utils'
|
||||
import { useAppConfig } from '#imports'
|
||||
// TODO: Remove
|
||||
// @ts-expect-error
|
||||
@@ -10,6 +11,7 @@ import appConfig from '#build/app.config'
|
||||
// const appConfig = useAppConfig()
|
||||
|
||||
export default defineComponent({
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
size: {
|
||||
type: String,
|
||||
@@ -20,14 +22,14 @@ export default defineComponent({
|
||||
},
|
||||
ui: {
|
||||
type: Object as PropType<Partial<typeof appConfig.ui.buttonGroup>>,
|
||||
default: () => appConfig.ui.buttonGroup
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
setup (props, { slots }) {
|
||||
setup (props, { attrs, slots }) {
|
||||
// TODO: Remove
|
||||
const appConfig = useAppConfig()
|
||||
|
||||
const ui = computed<Partial<typeof appConfig.ui.buttonGroup>>(() => defu({}, props.ui, appConfig.ui.buttonGroup))
|
||||
const ui = computed<Partial<typeof appConfig.ui.buttonGroup>>(() => defuTwMerge({}, props.ui, appConfig.ui.buttonGroup))
|
||||
|
||||
const children = computed(() => getSlotsChildren(slots))
|
||||
|
||||
@@ -50,22 +52,20 @@ export default defineComponent({
|
||||
vProps.size = props.size
|
||||
}
|
||||
|
||||
vProps.class = node.props?.class || ''
|
||||
vProps.class += ' !shadow-none'
|
||||
vProps.ui = node.props?.ui || {}
|
||||
vProps.ui.rounded = ''
|
||||
|
||||
const classes = ['shadow-none', 'rounded-none']
|
||||
if (index === 0) {
|
||||
vProps.ui.rounded = rounded.value.left
|
||||
classes.push(rounded.value.left)
|
||||
}
|
||||
if (index === children.value.length - 1) {
|
||||
classes.push(rounded.value.right)
|
||||
}
|
||||
|
||||
if (index === children.value.length - 1) {
|
||||
vProps.ui.rounded = rounded.value.right
|
||||
}
|
||||
vProps.class = node.props?.class || ''
|
||||
vProps.class = twMerge(twJoin(...classes), vProps.class)
|
||||
|
||||
return cloneVNode(node, vProps)
|
||||
}))
|
||||
|
||||
return () => h('div', { class: [ui.value.wrapper, ui.value.rounded, ui.value.shadow] }, clones.value)
|
||||
return () => h('div', { class: twMerge(twJoin(ui.value.wrapper, ui.value.rounded, ui.value.shadow), attrs.class as string), ...omit(attrs, ['class']) }, clones.value)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<HMenu v-slot="{ open }" as="div" :class="ui.wrapper" @mouseleave="onMouseLeave">
|
||||
<HMenu v-slot="{ open }" as="div" :class="wrapperClass" v-bind="attrs" @mouseleave="onMouseLeave">
|
||||
<HMenuButton
|
||||
ref="trigger"
|
||||
as="div"
|
||||
@@ -50,11 +50,13 @@ import type { PropType } from 'vue'
|
||||
import { Menu as HMenu, MenuButton as HMenuButton, MenuItems as HMenuItems, MenuItem as HMenuItem } from '@headlessui/vue'
|
||||
import { defu } from 'defu'
|
||||
import { omit } from 'lodash-es'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
import UIcon from '../elements/Icon.vue'
|
||||
import UAvatar from '../elements/Avatar.vue'
|
||||
import UKbd from '../elements/Kbd.vue'
|
||||
import ULink from '../elements/Link.vue'
|
||||
import { usePopper } from '../../composables/usePopper'
|
||||
import { defuTwMerge } from '../../utils'
|
||||
import type { DropdownItem } from '../../types/dropdown'
|
||||
import type { PopperOptions } from '../../types'
|
||||
import { useAppConfig } from '#imports'
|
||||
@@ -75,6 +77,7 @@ export default defineComponent({
|
||||
UKbd,
|
||||
ULink
|
||||
},
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
items: {
|
||||
type: Array as PropType<DropdownItem[][]>,
|
||||
@@ -105,14 +108,14 @@ export default defineComponent({
|
||||
},
|
||||
ui: {
|
||||
type: Object as PropType<Partial<typeof appConfig.ui.dropdown>>,
|
||||
default: () => appConfig.ui.dropdown
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
setup (props) {
|
||||
setup (props, { attrs }) {
|
||||
// TODO: Remove
|
||||
const appConfig = useAppConfig()
|
||||
|
||||
const ui = computed<Partial<typeof appConfig.ui.dropdown>>(() => defu({}, props.ui, appConfig.ui.dropdown))
|
||||
const ui = computed<Partial<typeof appConfig.ui.dropdown>>(() => defuTwMerge({}, props.ui, appConfig.ui.dropdown))
|
||||
|
||||
const popper = computed<PopperOptions>(() => defu(props.mode === 'hover' ? { offsetDistance: 0 } : {}, props.popper, ui.value.popper as PopperOptions))
|
||||
|
||||
@@ -142,6 +145,8 @@ export default defineComponent({
|
||||
return props.mode === 'hover' ? { paddingTop: `${offsetDistance}px`, paddingBottom: `${offsetDistance}px` } : {}
|
||||
})
|
||||
|
||||
const wrapperClass = computed(() => twMerge(ui.value.wrapper, attrs.class as string))
|
||||
|
||||
function onMouseOver () {
|
||||
if (props.mode !== 'hover' || !menuApi.value) {
|
||||
return
|
||||
@@ -183,11 +188,13 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
return {
|
||||
attrs: omit(attrs, ['class']),
|
||||
// eslint-disable-next-line vue/no-dupe-keys
|
||||
ui,
|
||||
trigger,
|
||||
container,
|
||||
containerStyle,
|
||||
wrapperClass,
|
||||
onMouseOver,
|
||||
onMouseLeave,
|
||||
omit
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<kbd :class="[ui.base, ui.size[size], ui.padding, ui.rounded, ui.font, ui.background, ui.ring]">
|
||||
<kbd :class="kbdClass" v-bind="attrs">
|
||||
<slot>{{ value }}</slot>
|
||||
</kbd>
|
||||
</template>
|
||||
@@ -7,7 +7,9 @@
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed } from 'vue'
|
||||
import type { PropType } from 'vue'
|
||||
import { defu } from 'defu'
|
||||
import { omit } from 'lodash-es'
|
||||
import { twMerge, twJoin } from 'tailwind-merge'
|
||||
import { defuTwMerge } from '../../utils'
|
||||
import { useAppConfig } from '#imports'
|
||||
// TODO: Remove
|
||||
// @ts-expect-error
|
||||
@@ -16,6 +18,7 @@ import appConfig from '#build/app.config'
|
||||
// const appConfig = useAppConfig()
|
||||
|
||||
export default defineComponent({
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
@@ -30,18 +33,32 @@ export default defineComponent({
|
||||
},
|
||||
ui: {
|
||||
type: Object as PropType<Partial<typeof appConfig.ui.kbd>>,
|
||||
default: () => appConfig.ui.kbd
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
setup (props) {
|
||||
setup (props, { attrs }) {
|
||||
// TODO: Remove
|
||||
const appConfig = useAppConfig()
|
||||
|
||||
const ui = computed<Partial<typeof appConfig.ui.kbd>>(() => defu({}, props.ui, appConfig.ui.kbd))
|
||||
const ui = computed<Partial<typeof appConfig.ui.kbd>>(() => defuTwMerge({}, props.ui, appConfig.ui.kbd))
|
||||
|
||||
const kbdClass = computed(() => {
|
||||
return twMerge(twJoin(
|
||||
ui.value.base,
|
||||
ui.value.size[props.size],
|
||||
ui.value.padding,
|
||||
ui.value.rounded,
|
||||
ui.value.font,
|
||||
ui.value.background,
|
||||
ui.value.ring
|
||||
), attrs.class as string)
|
||||
})
|
||||
|
||||
return {
|
||||
attrs: omit(attrs, ['class']),
|
||||
// eslint-disable-next-line vue/no-dupe-keys
|
||||
ui
|
||||
ui,
|
||||
kbdClass
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user