chore(Link): add pickLinkProps util

This commit is contained in:
Benjamin Canac
2024-05-17 11:58:31 +02:00
parent 9970f0ea6b
commit 034062df65
8 changed files with 25 additions and 21 deletions

View File

@@ -11,7 +11,7 @@ const appConfig = _appConfig as AppConfig & { ui: { breadcrumb: Partial<typeof t
const breadcrumb = tv({ extend: tv(theme), ...(appConfig.ui?.breadcrumb || {}) })
export interface BreadcrumbItem extends LinkProps {
export interface BreadcrumbItem extends Omit<LinkProps, 'custom'> {
label?: string
icon?: string
avatar?: AvatarProps
@@ -41,7 +41,7 @@ import { computed } from 'vue'
import { Primitive } from 'radix-vue'
import { useAppConfig } from '#imports'
import { ULink, UIcon, UAvatar } from '#components'
import { omit } from '#ui/utils'
import { pickLinkProps } from '#ui/utils/link'
const props = defineProps<BreadcrumbProps<T>>()
const slots = defineSlots<BreadcrumbSlots<T>>()
@@ -56,7 +56,7 @@ const ui = computed(() => tv({ extend: breadcrumb, slots: props.ui })())
<ol :class="ui.list()">
<template v-for="(item, index) in items" :key="index">
<li :class="ui.itemWrapper()">
<ULink as="span" v-bind="omit(item, ['label', 'icon', 'avatar', 'slot'])" :aria-current="index === items!.length - 1 ? 'page' : undefined" :class="ui.item({ active: index === items!.length - 1, disabled: !!item.disabled, to: !!item.to })" raw>
<ULink v-bind="pickLinkProps(item)" as="span" :aria-current="index === items!.length - 1 ? 'page' : undefined" :class="ui.item({ active: index === items!.length - 1, disabled: !!item.disabled, to: !!item.to })" raw>
<slot :name="item.slot || 'item'" :item="item" :index="index">
<slot :name="item.slot ? `${item.slot}-leading`: 'item-leading'" :item="item" :active="index === items!.length - 1" :index="index">
<UAvatar v-if="item.avatar" size="2xs" v-bind="item.avatar" :class="ui.itemLeadingAvatar({ active: index === items!.length - 1 })" />

View File

@@ -12,7 +12,7 @@ const button = tv({ extend: tv(theme), ...(appConfig.ui?.button || {}) })
type ButtonVariants = VariantProps<typeof button>
export interface ButtonProps extends UseComponentIconsProps, LinkProps {
export interface ButtonProps extends UseComponentIconsProps, Omit<LinkProps, 'custom'> {
label?: string
color?: ButtonVariants['color']
variant?: ButtonVariants['variant']
@@ -34,14 +34,14 @@ export interface ButtonSlots {
<script setup lang="ts">
import { computed } from 'vue'
import { useForwardProps } from 'radix-vue'
import { reactiveOmit } from '@vueuse/core'
import { useComponentIcons, useButtonGroup } from '#imports'
import { UIcon, ULink } from '#components'
import { pickLinkProps } from '#ui/utils/link'
const props = defineProps<ButtonProps>()
const slots = defineSlots<ButtonSlots>()
const linkProps = useForwardProps(reactiveOmit(props, 'type', 'label', 'color', 'variant', 'size', 'icon', 'leading', 'leadingIcon', 'trailing', 'trailingIcon', 'loading', 'loadingIcon', 'square', 'block', 'disabled', 'truncate', 'class', 'ui'))
const linkProps = useForwardProps(pickLinkProps(props))
const { orientation, size: buttonSize } = useButtonGroup<ButtonProps>(props)
const { isLeading, isTrailing, leadingIconName, trailingIconName } = useComponentIcons(props)

View File

@@ -11,7 +11,7 @@ const appConfig = _appConfig as AppConfig & { ui: { contextMenu: Partial<typeof
const contextMenu = tv({ extend: tv(theme), ...(appConfig.ui?.contextMenu || {}) })
export interface ContextMenuItem extends Omit<LinkProps, 'type'>, Pick<ContextMenuItemProps, 'disabled'> {
export interface ContextMenuItem extends Omit<LinkProps, 'type' | 'custom'>, Pick<ContextMenuItemProps, 'disabled'> {
label?: string
icon?: string
avatar?: AvatarProps

View File

@@ -15,8 +15,6 @@ interface ContextMenuContentProps<T> extends Omit<RadixContextMenuContentProps,
}
interface ContextMenuContentEmits extends RadixContextMenuContentEmits {}
type ContextMenuContentSlots<T extends { slot?: string }> = ContextMenuSlots<T>
</script>
<script setup lang="ts" generic="T extends ContextMenuItem">
@@ -27,14 +25,15 @@ import { reactiveOmit, createReusableTemplate } from '@vueuse/core'
import { useAppConfig } from '#imports'
import { ULink } from '#components'
import { omit } from '#ui/utils'
import { pickLinkProps } from '#ui/utils/link'
const props = defineProps<ContextMenuContentProps<T>>()
const emits = defineEmits<ContextMenuContentEmits>()
const slots = defineSlots<ContextMenuContentSlots<T>>()
const slots = defineSlots<ContextMenuSlots<T>>()
const appConfig = useAppConfig()
const contentProps = useForwardPropsEmits(reactiveOmit(props, 'sub', 'items', 'portal', 'class', 'ui'), emits)
const proxySlots = omit(slots, ['default']) as Record<string, ContextMenuContentSlots<T>[string]>
const proxySlots = omit(slots, ['default']) as Record<string, ContextMenuSlots<T>[string]>
const [DefineItemTemplate, ReuseItemTemplate] = createReusableTemplate()
@@ -102,7 +101,7 @@ const groups = computed(() => props.items?.length ? (Array.isArray(props.items[0
</UContextMenuContent>
</ContextMenu.Sub>
<ContextMenu.Item v-else as-child :disabled="item.disabled" :text-value="item.label" @select="item.select">
<ULink v-slot="{ active, ...slotProps }" v-bind="omit((item as ContextMenuItem), ['label', 'icon', 'avatar', 'content', 'kbds', 'slot', 'open', 'defaultOpen', 'select', 'children', 'type'])" custom>
<ULink v-slot="{ active, ...slotProps }" v-bind="pickLinkProps(item as Omit<ContextMenuItem, 'type'>)" custom>
<ULinkBase v-bind="slotProps" :class="ui.item({ active })">
<ReuseItemTemplate :item="item" :active="active" :index="index" />
</ULinkBase>

View File

@@ -11,7 +11,7 @@ const appConfig = _appConfig as AppConfig & { ui: { dropdownMenu: Partial<typeof
const dropdownMenu = tv({ extend: tv(theme), ...(appConfig.ui?.dropdownMenu || {}) })
export interface DropdownMenuItem extends Omit<LinkProps, 'type'>, Pick<DropdownMenuItemProps, 'disabled'> {
export interface DropdownMenuItem extends Omit<LinkProps, 'type' | 'custom'>, Pick<DropdownMenuItemProps, 'disabled'> {
label?: string
icon?: string
avatar?: AvatarProps

View File

@@ -15,8 +15,6 @@ interface DropdownMenuContentProps<T> extends Omit<RadixDropdownMenuContentProps
}
interface DropdownMenuContentEmits extends RadixDropdownMenuContentEmits {}
type DropdownMenuContentSlots<T extends { slot?: string }> = DropdownMenuSlots<T>
</script>
<script setup lang="ts" generic="T extends DropdownMenuItem">
@@ -27,14 +25,15 @@ import { reactiveOmit, createReusableTemplate } from '@vueuse/core'
import { useAppConfig } from '#imports'
import { ULink } from '#components'
import { omit } from '#ui/utils'
import { pickLinkProps } from '#ui/utils/link'
const props = defineProps<DropdownMenuContentProps<T>>()
const emits = defineEmits<DropdownMenuContentEmits>()
const slots = defineSlots<DropdownMenuContentSlots<T>>()
const slots = defineSlots<DropdownMenuSlots<T>>()
const appConfig = useAppConfig()
const contentProps = useForwardPropsEmits(reactiveOmit(props, 'sub', 'items', 'portal', 'class', 'ui'), emits)
const proxySlots = omit(slots, ['default']) as Record<string, DropdownMenuContentSlots<T>[string]>
const proxySlots = omit(slots, ['default']) as Record<string, DropdownMenuSlots<T>[string]>
const [DefineItemTemplate, ReuseItemTemplate] = createReusableTemplate()
@@ -105,7 +104,7 @@ const groups = computed(() => props.items?.length ? (Array.isArray(props.items[0
</UDropdownMenuContent>
</DropdownMenu.Sub>
<DropdownMenu.Item v-else as-child :disabled="item.disabled" :text-value="item.label" @select="item.select">
<ULink v-slot="{ active, ...slotProps }" v-bind="omit((item as DropdownMenuItem), ['label', 'icon', 'avatar', 'content', 'kbds', 'slot', 'open', 'defaultOpen', 'select', 'children', 'type'])" custom>
<ULink v-slot="{ active, ...slotProps }" v-bind="pickLinkProps(item as Omit<DropdownMenuItem, 'type'>)" custom>
<ULinkBase v-bind="slotProps" :class="ui.item({ active })">
<ReuseItemTemplate :item="item" :active="active" :index="index" />
</ULinkBase>

View File

@@ -11,7 +11,7 @@ const appConfig = _appConfig as AppConfig & { ui: { navigationMenu: Partial<type
const navigationMenu = tv({ extend: tv(theme), ...(appConfig.ui?.navigationMenu || {}) })
export interface NavigationMenuItem extends LinkProps, Pick<NavigationMenuItemProps, 'value'> {
export interface NavigationMenuItem extends Omit<LinkProps, 'custom'>, Pick<NavigationMenuItemProps, 'value'> {
label?: string
icon?: string
avatar?: AvatarProps
@@ -44,7 +44,7 @@ import { computed } from 'vue'
import { NavigationMenuRoot, NavigationMenuList, NavigationMenuItem, NavigationMenuLink, useForwardPropsEmits } from 'radix-vue'
import { reactivePick } from '@vueuse/core'
import { UIcon, UAvatar, UBadge, ULink, ULinkBase } from '#components'
import { omit } from '#ui/utils'
import { pickLinkProps } from '#ui/utils/link'
const props = withDefaults(defineProps<NavigationMenuProps<T>>(), { orientation: 'horizontal' })
const emits = defineEmits<NavigationMenuEmits>()
@@ -62,7 +62,7 @@ const lists = computed(() => props.items?.length ? (Array.isArray(props.items[0]
<template v-for="(list, listIndex) in lists" :key="`list-${listIndex}`">
<NavigationMenuList :class="ui.list()">
<NavigationMenuItem v-for="(item, index) in list" :key="`list-${listIndex}-${index}`" :value="item.value || String(index)" :class="ui.itemWrapper()">
<ULink v-slot="{ active, ...slotProps }" v-bind="omit(item, ['label', 'value', 'icon', 'avatar', 'badge', 'slot', 'select'])" custom>
<ULink v-slot="{ active, ...slotProps }" v-bind="pickLinkProps(item)" custom>
<NavigationMenuLink as-child :active="active" @select="item.select">
<ULinkBase v-bind="slotProps" :class="ui.item({ active, disabled: !!item.disabled })">
<slot :name="item.slot || 'item'" :item="item" :index="index">

View File

@@ -0,0 +1,6 @@
import { reactivePick } from '@vueuse/core'
import type { LinkProps } from '#ui/types'
export function pickLinkProps(link: LinkProps) {
return reactivePick(link, 'active', 'activeClass', 'ariaCurrentValue', 'as', 'disabled', 'exact', 'exactActiveClass', 'exactHash', 'exactQuery', 'external', 'href', 'inactiveClass', 'noPrefetch', 'noRel', 'prefetch', 'prefetchedClass', 'rel', 'replace', 'target', 'to', 'type')
}