mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-14 20:19:34 +01:00
fix: dynamic slots autocomplete (#77)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
This commit is contained in:
@@ -22,7 +22,7 @@ const items = [{
|
||||
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed neque elit, tristique placerat feugiat ac, facilisis vitae arcu. Proin eget egestas augue. Praesent ut sem nec arcu pellentesque aliquet. Duis dapibus diam vel metus tempus vulputate.'
|
||||
}, {
|
||||
label: 'Utilities',
|
||||
slot: 'toto',
|
||||
slot: 'custom' as const,
|
||||
icon: 'i-heroicons-wrench-screwdriver',
|
||||
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed neque elit, tristique placerat feugiat ac, facilisis vitae arcu. Proin eget egestas augue. Praesent ut sem nec arcu pellentesque aliquet. Duis dapibus diam vel metus tempus vulputate.'
|
||||
}]
|
||||
@@ -30,6 +30,10 @@ const items = [{
|
||||
|
||||
<template>
|
||||
<UCard :ui="{ body: 'p-0 sm:p-0' }">
|
||||
<UAccordion :items="items" class="w-96" :ui="{ trigger: 'px-3.5', content: 'px-3.5' }" />
|
||||
<UAccordion :items="items" class="w-96" :ui="{ trigger: 'px-3.5', content: 'px-3.5' }">
|
||||
<template #custom="{ item }">
|
||||
<span class="text-gray-500 dark:text-gray-400">Custom: {{ item.content }}</span>
|
||||
</template>
|
||||
</UAccordion>
|
||||
</UCard>
|
||||
</template>
|
||||
|
||||
@@ -3,7 +3,7 @@ const items = [{
|
||||
label: 'Home',
|
||||
to: '/'
|
||||
}, {
|
||||
slot: 'dropdown',
|
||||
slot: 'dropdown' as const,
|
||||
icon: 'i-heroicons-ellipsis-horizontal',
|
||||
children: [{
|
||||
label: 'Documentation'
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
const appConfig = useAppConfig()
|
||||
|
||||
const items = [
|
||||
[{
|
||||
label: 'My account',
|
||||
@@ -10,6 +12,7 @@ const items = [
|
||||
[{
|
||||
label: 'Profile',
|
||||
icon: 'i-heroicons-user',
|
||||
slot: 'custom' as const,
|
||||
select(e: Event) {
|
||||
e.preventDefault()
|
||||
console.log('Profile clicked')
|
||||
@@ -116,6 +119,14 @@ defineShortcuts(extractShortcuts(items))
|
||||
<div class="flex-1">
|
||||
<UDropdownMenu :items="items" arrow :content="{ side: 'bottom' }" class="min-w-48">
|
||||
<UButton label="Open" color="white" />
|
||||
|
||||
<template #custom="{ item }">
|
||||
<UIcon :name="item.icon" class="shrink-0 size-5" />
|
||||
|
||||
<span class="truncate">{{ item.label }}</span>
|
||||
|
||||
<UIcon :name="appConfig.ui.icons.check" class="shrink-0 size-5 text-primary-500 dark:text-primary-400 ms-auto" />
|
||||
</template>
|
||||
</UDropdownMenu>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -26,7 +26,8 @@ const items = [
|
||||
label: 'Examples',
|
||||
icon: 'i-heroicons-light-bulb',
|
||||
to: 'https://ui.nuxt.com',
|
||||
target: '_blank'
|
||||
target: '_blank',
|
||||
slot: 'custom' as const
|
||||
}, {
|
||||
label: 'Help',
|
||||
icon: 'i-heroicons-question-mark-circle',
|
||||
@@ -37,7 +38,13 @@ const items = [
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col gap-12 w-full max-w-4xl">
|
||||
<UNavigationMenu :items="items" class="border-b border-gray-200 dark:border-gray-800" />
|
||||
<UNavigationMenu :items="items" class="border-b border-gray-200 dark:border-gray-800">
|
||||
<template #custom="{ item }">
|
||||
<UIcon :name="item.icon" class="size-5" />
|
||||
|
||||
<span class="truncate text-primary-500 dark:text-primary-400">{{ item.label }}</span>
|
||||
</template>
|
||||
</UNavigationMenu>
|
||||
|
||||
<UNavigationMenu :items="items" orientation="vertical" class="w-48" />
|
||||
</div>
|
||||
|
||||
@@ -12,13 +12,19 @@ const items = [{
|
||||
}, {
|
||||
label: 'Tab3',
|
||||
icon: 'i-heroicons-bell',
|
||||
content: 'Finally, this is the content for Tab3'
|
||||
content: 'Finally, this is the content for Tab3',
|
||||
slot: 'custom' as const
|
||||
}]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col gap-4">
|
||||
<UTabs :items="items" class="w-96" />
|
||||
<UTabs :items="items" class="w-96">
|
||||
<template #custom="{ item }">
|
||||
<span class="text-gray-500 dark:text-gray-400">Custom: {{ item.content }}</span>
|
||||
</template>
|
||||
</UTabs>
|
||||
|
||||
<UTabs :items="items" orientation="vertical" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -4,6 +4,7 @@ import type { AccordionRootProps, AccordionRootEmits, AccordionContentProps } fr
|
||||
import type { AppConfig } from '@nuxt/schema'
|
||||
import _appConfig from '#build/app.config'
|
||||
import theme from '#build/ui/accordion'
|
||||
import type { DynamicSlots } from '#ui/types/utils'
|
||||
|
||||
const appConfig = _appConfig as AppConfig & { ui: { accordion: Partial<typeof theme> } }
|
||||
|
||||
@@ -31,14 +32,13 @@ export interface AccordionEmits extends AccordionRootEmits {}
|
||||
|
||||
type SlotProps<T> = (props: { item: T, index: number }) => any
|
||||
|
||||
export type AccordionSlots<T> = {
|
||||
export type AccordionSlots<T extends { slot?: string }> = {
|
||||
default: SlotProps<T>
|
||||
leading: SlotProps<T>
|
||||
label: SlotProps<T>
|
||||
trailing: SlotProps<T>
|
||||
content: SlotProps<T>
|
||||
[key: string]: SlotProps<T>
|
||||
}
|
||||
} & DynamicSlots<T, SlotProps<T>>
|
||||
</script>
|
||||
|
||||
<script setup lang="ts" generic="T extends AccordionItem">
|
||||
|
||||
@@ -5,6 +5,7 @@ import type { AppConfig } from '@nuxt/schema'
|
||||
import _appConfig from '#build/app.config'
|
||||
import theme from '#build/ui/breadcrumb'
|
||||
import type { AvatarProps, LinkProps } from '#ui/types'
|
||||
import type { DynamicSlots } from '#ui/types/utils'
|
||||
|
||||
const appConfig = _appConfig as AppConfig & { ui: { breadcrumb: Partial<typeof theme> } }
|
||||
|
||||
@@ -26,14 +27,13 @@ export interface BreadcrumbProps<T> extends Omit<PrimitiveProps, 'asChild'> {
|
||||
|
||||
type SlotProps<T> = (props: { item: T, index: number, active?: boolean }) => any
|
||||
|
||||
export interface BreadcrumbSlots<T> {
|
||||
export type BreadcrumbSlots<T extends { slot?: string }> = {
|
||||
leading: SlotProps<T>
|
||||
label: SlotProps<T>
|
||||
trailing: SlotProps<T>
|
||||
item: SlotProps<T>
|
||||
[key: string]: SlotProps<T>
|
||||
separator(): any
|
||||
}
|
||||
} & DynamicSlots<T, SlotProps<T>>
|
||||
</script>
|
||||
|
||||
<script setup lang="ts" generic="T extends BreadcrumbItem">
|
||||
@@ -56,8 +56,8 @@ 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.item()">
|
||||
<slot :name="item.slot || 'item'" :item="item" :index="index">
|
||||
<ULink as="span" v-bind="omit(item, ['label', 'icon', 'avatar'])" :aria-current="index === items!.length - 1 ? 'page' : undefined" :class="ui.link({ active: index === items!.length - 1, disabled: !!item.disabled, to: !!item.to })" raw>
|
||||
<ULink as="span" v-bind="omit(item, ['label', 'icon', 'avatar', 'slot'])" :aria-current="index === items!.length - 1 ? 'page' : undefined" :class="ui.link({ active: index === items!.length - 1, disabled: !!item.disabled, to: !!item.to })" raw>
|
||||
<slot :name="item.slot || 'item'" :item="item" :index="index">
|
||||
<slot name="leading" :item="item" :active="index === items!.length - 1" :index="index">
|
||||
<UAvatar v-if="item.avatar" size="2xs" v-bind="item.avatar" :class="ui.linkLeadingAvatar({ active: index === items!.length - 1 })" />
|
||||
<UIcon v-else-if="item.icon" :name="item.icon" :class="ui.linkLeadingIcon({ active: index === items!.length - 1 })" />
|
||||
@@ -70,8 +70,8 @@ const ui = computed(() => tv({ extend: breadcrumb, slots: props.ui })())
|
||||
</span>
|
||||
|
||||
<slot name="trailing" :item="item" :active="index === items!.length - 1" :index="index" />
|
||||
</ULink>
|
||||
</slot>
|
||||
</slot>
|
||||
</ULink>
|
||||
</li>
|
||||
|
||||
<li v-if="index < items!.length - 1" role="presentation" :class="ui.separator()">
|
||||
|
||||
@@ -5,6 +5,7 @@ import type { AppConfig } from '@nuxt/schema'
|
||||
import _appConfig from '#build/app.config'
|
||||
import theme from '#build/ui/dropdown-menu'
|
||||
import type { AvatarProps, KbdProps, LinkProps } from '#ui/types'
|
||||
import type { DynamicSlots } from '#ui/types/utils'
|
||||
|
||||
const appConfig = _appConfig as AppConfig & { ui: { dropdownMenu: Partial<typeof theme> } }
|
||||
|
||||
@@ -43,14 +44,13 @@ export interface DropdownMenuEmits extends DropdownMenuRootEmits {}
|
||||
|
||||
type SlotProps<T> = (props: { item: T, active?: boolean, index: number }) => any
|
||||
|
||||
export interface DropdownMenuSlots<T> {
|
||||
export type DropdownMenuSlots<T extends { slot?: string }> = {
|
||||
default(): any
|
||||
leading: SlotProps<T>
|
||||
label: SlotProps<T>
|
||||
trailing: SlotProps<T>
|
||||
item: SlotProps<T>
|
||||
[key: string]: SlotProps<T>
|
||||
}
|
||||
} & DynamicSlots<T, SlotProps<T>>
|
||||
</script>
|
||||
|
||||
<script setup lang="ts" generic="T extends DropdownMenuItem">
|
||||
@@ -71,7 +71,7 @@ const slots = defineSlots<DropdownMenuSlots<T>>()
|
||||
const rootProps = useForwardPropsEmits(reactivePick(props, 'defaultOpen', 'open', 'modal'), emits)
|
||||
const contentProps = toRef(() => defu(props.content, { side: 'bottom', sideOffset: 8 }) as DropdownMenuContentProps)
|
||||
const arrowProps = toRef(() => props.arrow as DropdownMenuArrowProps)
|
||||
const proxySlots = omit(slots, ['default'])
|
||||
const proxySlots = omit(slots, ['default']) as Record<string, DropdownMenuSlots<T>[string]>
|
||||
|
||||
const ui = computed(() => tv({ extend: dropdownMenu, slots: props.ui })())
|
||||
</script>
|
||||
|
||||
@@ -16,7 +16,7 @@ interface DropdownMenuContentProps<T> extends Omit<RadixDropdownMenuContentProps
|
||||
|
||||
interface DropdownMenuContentEmits extends RadixDropdownMenuContentEmits {}
|
||||
|
||||
interface DropdownMenuContentSlots<T> extends DropdownMenuSlots<T> {}
|
||||
type DropdownMenuContentSlots<T extends { slot?: string }> = DropdownMenuSlots<T>
|
||||
</script>
|
||||
|
||||
<script setup lang="ts" generic="T extends DropdownMenuItem">
|
||||
@@ -34,7 +34,7 @@ const slots = defineSlots<DropdownMenuContentSlots<T>>()
|
||||
|
||||
const appConfig = useAppConfig()
|
||||
const contentProps = useForwardPropsEmits(reactiveOmit(props, 'sub', 'items', 'portal', 'class', 'ui'), emits)
|
||||
const proxySlots = omit(slots, ['default'])
|
||||
const proxySlots = omit(slots, ['default']) as Record<string, DropdownMenuContentSlots<T>[string]>
|
||||
|
||||
const [DefineItemTemplate, ReuseItemTemplate] = createReusableTemplate()
|
||||
|
||||
@@ -43,25 +43,27 @@ const groups = computed(() => props.items?.length ? (Array.isArray(props.items[0
|
||||
|
||||
<template>
|
||||
<DefineItemTemplate v-slot="{ item, active, index }">
|
||||
<slot name="leading" :item="item" :active="active" :index="index">
|
||||
<UAvatar v-if="item.avatar" size="2xs" v-bind="item.avatar" :class="ui.linkLeadingAvatar({ active })" />
|
||||
<UIcon v-else-if="item.icon" :name="item.icon" :class="ui.linkLeadingIcon({ active })" />
|
||||
<slot :name="item.slot || 'item'" :item="item" :index="index">
|
||||
<slot name="leading" :item="item" :active="active" :index="index">
|
||||
<UAvatar v-if="item.avatar" size="2xs" v-bind="item.avatar" :class="ui.linkLeadingAvatar({ active })" />
|
||||
<UIcon v-else-if="item.icon" :name="item.icon" :class="ui.linkLeadingIcon({ active })" />
|
||||
</slot>
|
||||
|
||||
<span v-if="item.label || $slots.label" :class="ui.linkLabel()">
|
||||
<slot name="label" :item="item" :active="active" :index="index">
|
||||
{{ item.label }}
|
||||
</slot>
|
||||
</span>
|
||||
|
||||
<span v-if="$slots.trailing || item.children?.length || item.kbds?.length" :class="ui.linkTrailing()">
|
||||
<slot name="trailing" :item="item" :active="active" :index="index">
|
||||
<UIcon v-if="item.children?.length" :name="appConfig.ui.icons.chevronRight" :class="ui.linkTrailingIcon()" />
|
||||
<span v-else-if="item.kbds?.length" :class="ui.linkTrailingKbds()">
|
||||
<UKbd v-for="(kbd, kbdIndex) in item.kbds" :key="kbdIndex" size="md" v-bind="typeof kbd === 'string' ? { value: kbd } : kbd" />
|
||||
</span>
|
||||
</slot>
|
||||
</span>
|
||||
</slot>
|
||||
|
||||
<span v-if="item.label || $slots.label" :class="ui.linkLabel()">
|
||||
<slot name="label" :item="item" :active="active" :index="index">
|
||||
{{ item.label }}
|
||||
</slot>
|
||||
</span>
|
||||
|
||||
<span v-if="$slots.trailing || item.children?.length || item.kbds?.length" :class="ui.linkTrailing()">
|
||||
<slot name="trailing" :item="item" :active="active" :index="index">
|
||||
<UIcon v-if="item.children?.length" :name="appConfig.ui.icons.chevronRight" :class="ui.linkTrailingIcon()" />
|
||||
<span v-else-if="item.kbds?.length" :class="ui.linkTrailingKbds()">
|
||||
<UKbd v-for="(kbd, kbdIndex) in item.kbds" :key="kbdIndex" size="md" v-bind="typeof kbd === 'string' ? { value: kbd } : kbd" />
|
||||
</span>
|
||||
</slot>
|
||||
</span>
|
||||
</DefineItemTemplate>
|
||||
|
||||
<DropdownMenu.Portal :disabled="!portal">
|
||||
@@ -69,9 +71,7 @@ const groups = computed(() => props.items?.length ? (Array.isArray(props.items[0
|
||||
<DropdownMenu.Group v-for="(group, groupIndex) in groups" :key="`group-${groupIndex}`" :class="ui.group()">
|
||||
<template v-for="(item, index) in group" :key="`group-${groupIndex}-${index}`">
|
||||
<DropdownMenu.Label v-if="item.type === 'label'" :class="ui.label()">
|
||||
<slot :name="item.slot || 'item'" :item="item" :index="index">
|
||||
<ReuseItemTemplate :item="item" :index="index" />
|
||||
</slot>
|
||||
<ReuseItemTemplate :item="item" :index="index" />
|
||||
</DropdownMenu.Label>
|
||||
<DropdownMenu.Sub v-else-if="item?.children?.length">
|
||||
<DropdownMenu.SubTrigger
|
||||
@@ -83,9 +83,7 @@ const groups = computed(() => props.items?.length ? (Array.isArray(props.items[0
|
||||
:text-value="item.label"
|
||||
:class="ui.link()"
|
||||
>
|
||||
<slot :name="item.slot || 'item'" :item="item" :index="index">
|
||||
<ReuseItemTemplate :item="item" :index="index" />
|
||||
</slot>
|
||||
<ReuseItemTemplate :item="item" :index="index" />
|
||||
</DropdownMenu.SubTrigger>
|
||||
|
||||
<UDropdownMenuContent
|
||||
@@ -106,13 +104,11 @@ 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">
|
||||
<slot :name="item.slot || 'item'" :item="item" :index="index">
|
||||
<ULink v-slot="{ active, ...slotProps }" v-bind="omit((item as DropdownMenuItem), ['label', 'icon', 'avatar', 'kbds', 'slot', 'open', 'defaultOpen', 'select', 'children', 'type'])" custom>
|
||||
<ULinkBase v-bind="slotProps" :class="ui.link({ active })">
|
||||
<ReuseItemTemplate :item="item" :active="active" :index="index" />
|
||||
</ULinkBase>
|
||||
</ULink>
|
||||
</slot>
|
||||
<ULink v-slot="{ active, ...slotProps }" v-bind="omit((item as DropdownMenuItem), ['label', 'icon', 'avatar', 'kbds', 'slot', 'open', 'defaultOpen', 'select', 'children', 'type'])" custom>
|
||||
<ULinkBase v-bind="slotProps" :class="ui.link({ active })">
|
||||
<ReuseItemTemplate :item="item" :active="active" :index="index" />
|
||||
</ULinkBase>
|
||||
</ULink>
|
||||
</DropdownMenu.Item>
|
||||
</template>
|
||||
</DropdownMenu.Group>
|
||||
|
||||
@@ -5,6 +5,7 @@ import type { AppConfig } from '@nuxt/schema'
|
||||
import _appConfig from '#build/app.config'
|
||||
import theme from '#build/ui/navigation-menu'
|
||||
import type { AvatarProps, BadgeProps, LinkProps, SeparatorProps } from '#ui/types'
|
||||
import type { DynamicSlots } from '#ui/types/utils'
|
||||
|
||||
const appConfig = _appConfig as AppConfig & { ui: { navigationMenu: Partial<typeof theme> } }
|
||||
|
||||
@@ -31,13 +32,12 @@ export interface NavigationMenuEmits extends NavigationMenuRootEmits {}
|
||||
|
||||
type SlotProps<T> = (props: { item: T, index: number, active?: boolean }) => any
|
||||
|
||||
export interface NavigationMenuSlots<T> {
|
||||
export type NavigationMenuSlots<T extends { slot?: string }> = {
|
||||
leading: SlotProps<T>
|
||||
label: SlotProps<T>
|
||||
trailing: SlotProps<T>
|
||||
item: SlotProps<T>
|
||||
[key: string]: SlotProps<T>
|
||||
}
|
||||
} & DynamicSlots<T, SlotProps<T>>
|
||||
</script>
|
||||
|
||||
<script setup lang="ts" generic="T extends NavigationMenuItem">
|
||||
@@ -63,10 +63,10 @@ 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.item()">
|
||||
<slot :name="item.slot || 'item'" :item="item" :index="index">
|
||||
<ULink v-slot="{ active, ...slotProps }" v-bind="omit(item, ['label', 'icon', 'avatar', 'badge', 'select'])" custom>
|
||||
<NavigationMenuLink as-child :active="active" @select="item.select">
|
||||
<ULinkBase v-bind="slotProps" :class="ui.link({ active, disabled: !!item.disabled })">
|
||||
<ULink v-slot="{ active, ...slotProps }" v-bind="omit(item, ['label', 'icon', 'avatar', 'badge', 'slot', 'select'])" custom>
|
||||
<NavigationMenuLink as-child :active="active" @select="item.select">
|
||||
<ULinkBase v-bind="slotProps" :class="ui.link({ active, disabled: !!item.disabled })">
|
||||
<slot :name="item.slot || 'item'" :item="item" :index="index">
|
||||
<slot name="leading" :item="item" :active="active" :index="index">
|
||||
<UAvatar v-if="item.avatar" size="2xs" v-bind="item.avatar" :class="ui.linkLeadingAvatar({ active, disabled: !!item.disabled })" />
|
||||
<UIcon v-else-if="item.icon" :name="item.icon" :class="ui.linkLeadingIcon({ active, disabled: !!item.disabled })" />
|
||||
@@ -89,10 +89,10 @@ const lists = computed(() => props.items?.length ? (Array.isArray(props.items[0]
|
||||
/>
|
||||
</slot>
|
||||
</span>
|
||||
</ULinkBase>
|
||||
</NavigationMenuLink>
|
||||
</ULink>
|
||||
</slot>
|
||||
</slot>
|
||||
</ULinkBase>
|
||||
</NavigationMenuLink>
|
||||
</ULink>
|
||||
</NavigationMenuItem>
|
||||
</NavigationMenuList>
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import type { AppConfig } from '@nuxt/schema'
|
||||
import _appConfig from '#build/app.config'
|
||||
import theme from '#build/ui/tabs'
|
||||
import type { AvatarProps } from '#ui/types'
|
||||
import type { DynamicSlots } from '#ui/types/utils'
|
||||
|
||||
const appConfig = _appConfig as AppConfig & { ui: { tabs: Partial<typeof theme> } }
|
||||
|
||||
@@ -31,14 +32,13 @@ export interface TabsEmits extends TabsRootEmits {}
|
||||
|
||||
type SlotProps<T> = (props: { item: T, index: number }) => any
|
||||
|
||||
export type TabsSlots<T> = {
|
||||
export type TabsSlots<T extends { slot?: string }> = {
|
||||
default: SlotProps<T>
|
||||
leading: SlotProps<T>
|
||||
label: SlotProps<T>
|
||||
trailing: SlotProps<T>
|
||||
content: SlotProps<T>
|
||||
[key: string]: SlotProps<T>
|
||||
}
|
||||
} & DynamicSlots<T, SlotProps<T>>
|
||||
</script>
|
||||
|
||||
<script setup lang="ts" generic="T extends TabsItem">
|
||||
|
||||
3
src/runtime/types/utils.d.ts
vendored
3
src/runtime/types/utils.d.ts
vendored
@@ -1,3 +1,6 @@
|
||||
export type DeepPartial<T> = Partial<{
|
||||
[P in keyof T]: DeepPartial<T[P]> | { [key: string]: string | object }
|
||||
}>
|
||||
|
||||
export type DynamicSlots<T extends { slot?: string }, SlotProps, Slot = T['slot']> =
|
||||
Record<string, SlotProps> & (Slot extends string ? Record<Slot, SlotProps> : Record<string, never>)
|
||||
|
||||
@@ -14,7 +14,8 @@ describe('Tabs', () => {
|
||||
}, {
|
||||
label: 'Tab3',
|
||||
icon: 'i-heroicons-bell',
|
||||
content: 'Finally, this is the content for Tab3'
|
||||
content: 'Finally, this is the content for Tab3',
|
||||
slot: 'custom'
|
||||
}]
|
||||
|
||||
const props = { items }
|
||||
|
||||
Reference in New Issue
Block a user