Merge branch 'v3' into feat/init-blog

This commit is contained in:
HugoRCD
2025-07-03 16:41:18 +02:00
85 changed files with 1206 additions and 716 deletions

View File

@@ -147,7 +147,8 @@ const test = ({ name, prose, content }) => {
? undefined
: `
import { describe, it, expect } from 'vitest'
import ${upperName}, { type ${upperName}Props, type ${upperName}Slots } from '../../${content ? '../' : ''}src/runtime/components/${content ? 'content/' : ''}${upperName}.vue'
import ${upperName} from '../../${content ? '../' : ''}src/runtime/components/${content ? 'content/' : ''}${upperName}.vue'
import type { ${upperName}Props, ${upperName}Slots } from '../../${content ? '../' : ''}src/runtime/components/${content ? 'content/' : ''}${upperName}.vue'
import ComponentRender from '../${content ? '../' : ''}component-render'
describe('${upperName}', () => {

View File

@@ -1,6 +1,7 @@
<template>
<UBanner
id="ui3-launch"
title="Nuxt UI v3 is officially released!"
icon="i-lucide-rocket"
:actions="[
{
@@ -10,9 +11,5 @@
}
]"
close
>
<template #title>
<span class="font-semibold">Nuxt UI v3</span> is officially released.
</template>
</UBanner>
/>
</template>

View File

@@ -1,5 +1,6 @@
<script setup lang="ts">
import { object, string, nonempty, refine, type Infer } from 'superstruct'
import { object, string, nonempty, refine } from 'superstruct'
import type { Infer } from 'superstruct'
import type { FormSubmitEvent } from '@nuxt/ui'
const schema = object({

View File

@@ -1,5 +1,6 @@
<script setup lang="ts">
import { object, string, type InferType } from 'yup'
import { object, string } from 'yup'
import type { InferType } from 'yup'
import type { FormSubmitEvent } from '@nuxt/ui'
const schema = object({

View File

@@ -0,0 +1,106 @@
<script setup lang="ts">
import { h, resolveComponent } from 'vue'
import type { TableColumn, TableRow } from '@nuxt/ui'
const UBadge = resolveComponent('UBadge')
type Payment = {
id: string
date: string
status: 'paid' | 'failed' | 'refunded'
email: string
amount: number
}
const data = ref<Payment[]>([{
id: '4600',
date: '2024-03-11T15:30:00',
status: 'paid',
email: 'james.anderson@example.com',
amount: 594
}, {
id: '4599',
date: '2024-03-11T10:10:00',
status: 'failed',
email: 'mia.white@example.com',
amount: 276
}, {
id: '4598',
date: '2024-03-11T08:50:00',
status: 'refunded',
email: 'william.brown@example.com',
amount: 315
}, {
id: '4597',
date: '2024-03-10T19:45:00',
status: 'paid',
email: 'emma.davis@example.com',
amount: 529
}, {
id: '4596',
date: '2024-03-10T15:55:00',
status: 'paid',
email: 'ethan.harris@example.com',
amount: 639
}])
const columns: TableColumn<Payment>[] = [{
accessorKey: 'id',
header: '#',
cell: ({ row }) => `#${row.getValue('id')}`
}, {
accessorKey: 'date',
header: 'Date',
cell: ({ row }) => {
return new Date(row.getValue('date')).toLocaleString('en-US', {
day: 'numeric',
month: 'short',
hour: '2-digit',
minute: '2-digit',
hour12: false
})
}
}, {
accessorKey: 'status',
header: 'Status',
cell: ({ row }) => {
const color = ({
paid: 'success' as const,
failed: 'error' as const,
refunded: 'neutral' as const
})[row.getValue('status') as string]
return h(UBadge, { class: 'capitalize', variant: 'subtle', color }, () => row.getValue('status'))
}
}, {
accessorKey: 'email',
header: 'Email'
}, {
accessorKey: 'amount',
header: () => h('div', { class: 'text-right' }, 'Amount'),
footer: ({ column }) => {
const total = column.getFacetedRowModel().rows.reduce((acc: number, row: TableRow<Payment>) => acc + Number.parseFloat(row.getValue('amount')), 0)
const formatted = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'EUR'
}).format(total)
return h('div', { class: 'text-right font-medium' }, `Total: ${formatted}`)
},
cell: ({ row }) => {
const amount = Number.parseFloat(row.getValue('amount'))
const formatted = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'EUR'
}).format(amount)
return h('div', { class: 'text-right font-medium' }, formatted)
}
}]
</script>
<template>
<UTable :data="data" :columns="columns" class="flex-1" />
</template>

View File

@@ -1,7 +1,8 @@
<script setup lang="ts">
import { h, resolveComponent } from 'vue'
import type { TableColumn } from '@nuxt/ui'
import { getGroupedRowModel, type GroupingOptions } from '@tanstack/vue-table'
import { getGroupedRowModel } from '@tanstack/vue-table'
import type { GroupingOptions } from '@tanstack/vue-table'
const UBadge = resolveComponent('UBadge')

View File

@@ -77,6 +77,7 @@ Use the `columns` prop as an array of [ColumnDef](https://tanstack.com/table/lat
- `accessorKey`: [The key of the row object to use when extracting the value for the column.]{class="text-muted"}
- `header`: [The header to display for the column. If a string is passed, it can be used as a default for the column ID. If a function is passed, it will be passed a props object for the header and should return the rendered header value (the exact type depends on the adapter being used).]{class="text-muted"}
- `footer`: [The footer to display for the column. Works exactly like header, but is displayed under the table.]{class="text-muted"}
- `cell`: [The cell to display each row for the column. If a function is passed, it will be passed a props object for the cell and should return the rendered cell value (the exact type depends on the adapter being used).]{class="text-muted"}
- `meta`: [Extra properties for the column.]{class="text-muted"}
- `class`:
@@ -161,7 +162,7 @@ props:
### Sticky
Use the `sticky` prop to make the header sticky.
Use the `sticky` prop to make the header or footer sticky.
::component-code
---
@@ -172,6 +173,10 @@ ignore:
- class
external:
- data
items:
sticky:
- true
- false
props:
sticky: true
data:
@@ -372,6 +377,22 @@ class: '!p-0'
This example is similar as the Popover [with following cursor example](/components/popover#with-following-cursor) and uses a [`refDebounced`](https://vueuse.org/shared/refDebounced/#refdebounced) to prevent the Popover from opening and closing too quickly when moving the cursor from one row to another.
::
### With column footer :badge{label="Soon" class="align-text-top"}
You can add a `footer` property to the column definition to render a footer for the column.
::component-example
---
prettier: true
collapse: true
name: 'table-column-footer-example'
highlights:
- 94
- 108
class: '!p-0'
---
::
### With column sorting
You can update a column `header` to render a [Button](/components/button) component inside the `header` to toggle the sorting state using the TanStack Table [Sorting APIs](https://tanstack.com/table/latest/docs/api/features/sorting).

View File

@@ -14,24 +14,24 @@
"@iconify-json/lucide": "^1.2.54",
"@iconify-json/simple-icons": "^1.2.41",
"@iconify-json/vscode-icons": "^1.2.23",
"@nuxt/content": "^3.6.1",
"@nuxt/content": "^3.6.2",
"@nuxt/image": "^1.10.0",
"@nuxt/ui": "workspace:*",
"@nuxt/ui-pro": "https://pkg.pr.new/@nuxt/ui-pro@3d48704",
"@nuxt/ui-pro": "https://pkg.pr.new/@nuxt/ui-pro@22fdc5e",
"@nuxthub/core": "^0.9.0",
"@nuxtjs/plausible": "^1.2.0",
"@octokit/rest": "^22.0.0",
"@rollup/plugin-yaml": "^4.1.2",
"@vueuse/integrations": "^13.4.0",
"@vueuse/nuxt": "^13.4.0",
"@vueuse/integrations": "^13.5.0",
"@vueuse/nuxt": "^13.5.0",
"ai": "^4.3.16",
"better-sqlite3": "^12.2.0",
"capture-website": "^4.2.0",
"joi": "^17.13.3",
"maska": "^3.1.1",
"motion-v": "^1.3.1",
"maska": "^3.2.0",
"motion-v": "^1.4.0",
"nuxt": "^3.17.6",
"nuxt-component-meta": "^0.12.0",
"nuxt-component-meta": "^0.12.1",
"nuxt-llms": "^0.1.3",
"nuxt-og-image": "^5.1.8",
"prettier": "^3.6.2",

View File

@@ -124,8 +124,8 @@
"@tailwindcss/vite": "^4.1.11",
"@tanstack/vue-table": "^8.21.3",
"@unhead/vue": "^2.0.11",
"@vueuse/core": "^13.4.0",
"@vueuse/integrations": "^13.4.0",
"@vueuse/core": "^13.5.0",
"@vueuse/integrations": "^13.5.0",
"colortranslator": "^5.0.0",
"consola": "^3.4.2",
"defu": "^6.1.4",
@@ -143,7 +143,7 @@
"mlly": "^1.7.4",
"ohash": "^2.0.11",
"pathe": "^2.0.3",
"reka-ui": "2.3.1",
"reka-ui": "2.3.2",
"scule": "^1.3.0",
"tailwind-variants": "^1.0.0",
"tailwindcss": "^4.1.11",
@@ -152,22 +152,22 @@
"unplugin-auto-import": "^19.3.0",
"unplugin-vue-components": "^28.8.0",
"vaul-vue": "0.4.1",
"vue-component-type-helpers": "^2.2.10"
"vue-component-type-helpers": "^3.0.0"
},
"devDependencies": {
"@nuxt/eslint-config": "^1.4.1",
"@nuxt/eslint-config": "^1.5.0",
"@nuxt/module-builder": "^1.0.1",
"@nuxt/test-utils": "^3.19.1",
"@nuxt/test-utils": "^3.19.2",
"@release-it/conventional-changelog": "^10.0.1",
"@vue/test-utils": "^2.4.6",
"embla-carousel": "^8.6.0",
"eslint": "^9.30.0",
"eslint": "^9.30.1",
"happy-dom": "^18.0.1",
"nuxt": "^3.17.6",
"release-it": "^19.0.3",
"vitest": "^3.2.4",
"vitest-environment-nuxt": "^1.0.1",
"vue-tsc": "^2.2.10"
"vue-tsc": "^3.0.0"
},
"peerDependencies": {
"@inertiajs/vue3": "^2.0.7",

View File

@@ -19,6 +19,6 @@
"@vitejs/plugin-vue": "^5.2.4",
"typescript": "^5.8.3",
"vite": "^6.3.5",
"vue-tsc": "^2.2.10"
"vue-tsc": "^3.0.0"
}
}

View File

@@ -242,6 +242,16 @@ const columns: TableColumn<Payment>[] = [{
}, {
accessorKey: 'amount',
header: () => h('div', { class: 'text-right' }, 'Amount'),
footer: ({ column }) => {
const total = column.getFacetedRowModel().rows.reduce((acc: number, row: TableRow<Payment>) => acc + Number.parseFloat(row.getValue('amount')), 0)
const formatted = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'EUR'
}).format(total)
return h('div', { class: 'text-right font-medium' }, `Total: ${formatted}`)
},
cell: ({ row }) => {
const amount = Number.parseFloat(row.getValue('amount'))

View File

@@ -19,7 +19,7 @@
},
"devDependencies": {
"typescript": "^5.8.3",
"vue-tsc": "^2.2.10"
"vue-tsc": "^3.0.0"
},
"resolutions": {
"unimport": "4.1.1"

1162
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -22,6 +22,12 @@
"reka-ui",
"vaul-vue"
]
}, {
"groupName": "vue-tsc",
"matchPackageNames": [
"vue-tsc",
"vue-component-type-helpers"
]
}, {
"matchDepTypes": ["peerDependencies"],
"enabled": false

View File

@@ -3,7 +3,8 @@ import { normalize } from 'pathe'
import { resolvePathSync } from 'mlly'
import MagicString from 'magic-string'
import { runtimeDir, type NuxtUIOptions } from '../unplugin'
import { runtimeDir } from '../unplugin'
import type { NuxtUIOptions } from '../unplugin'
/**
* This plugin normalises Nuxt environment (#imports) and `import.meta.client` within the Nuxt UI components.

View File

@@ -4,7 +4,8 @@ import { genSafeVariableName } from 'knitwork'
import MagicString from 'magic-string'
import { resolvePathSync } from 'mlly'
import { runtimeDir, type NuxtUIOptions } from '../unplugin'
import { runtimeDir } from '../unplugin'
import type { NuxtUIOptions } from '../unplugin'
import type { UnpluginOptions } from 'unplugin'

View File

@@ -42,14 +42,15 @@ export interface ButtonSlots {
</script>
<script setup lang="ts">
import { type Ref, computed, ref, inject } from 'vue'
import { computed, ref, inject } from 'vue'
import type { Ref } from 'vue'
import { defu } from 'defu'
import { useForwardProps } from 'reka-ui'
import { useAppConfig } from '#imports'
import { useComponentIcons } from '../composables/useComponentIcons'
import { useButtonGroup } from '../composables/useButtonGroup'
import { formLoadingInjectionKey } from '../composables/useFormField'
import { omit } from '../utils'
import { omit, mergeClasses } from '../utils'
import { tv } from '../utils/tv'
import { pickLinkProps } from '../utils/link'
import UIcon from './Icon.vue'
@@ -57,11 +58,7 @@ import UAvatar from './Avatar.vue'
import ULink from './Link.vue'
import ULinkBase from './LinkBase.vue'
const props = withDefaults(defineProps<ButtonProps>(), {
active: undefined,
activeClass: '',
inactiveClass: ''
})
const props = defineProps<ButtonProps>()
const slots = defineSlots<ButtonSlots>()
const appConfig = useAppConfig() as Button['AppConfig']
@@ -96,10 +93,10 @@ const ui = computed(() => tv({
variants: {
active: {
true: {
base: props.activeClass
base: mergeClasses(appConfig.ui?.button?.variants?.active?.true?.base, props.activeClass)
},
false: {
base: props.inactiveClass
base: mergeClasses(appConfig.ui?.button?.variants?.active?.false?.base, props.inactiveClass)
}
}
}

View File

@@ -47,7 +47,6 @@ import ULink from './Link.vue'
import UAvatar from './Avatar.vue'
import UIcon from './Icon.vue'
import UKbd from './Kbd.vue'
// eslint-disable-next-line import/no-self-import
import UContextMenuContent from './ContextMenuContent.vue'
const props = defineProps<ContextMenuContentProps<T>>()

View File

@@ -53,7 +53,6 @@ import ULink from './Link.vue'
import UAvatar from './Avatar.vue'
import UIcon from './Icon.vue'
import UKbd from './Kbd.vue'
// eslint-disable-next-line import/no-self-import
import UDropdownMenuContent from './DropdownMenuContent.vue'
const props = defineProps<DropdownMenuContentProps<T>>()

View File

@@ -47,7 +47,8 @@ export interface FormFieldSlots {
</script>
<script setup lang="ts">
import { computed, ref, inject, provide, type Ref, useId } from 'vue'
import { computed, ref, inject, provide, useId } from 'vue'
import type { Ref } from 'vue'
import { Primitive, Label } from 'reka-ui'
import { useAppConfig } from '#imports'
import { formFieldInjectionKey, inputIdInjectionKey } from '../composables/useFormField'

View File

@@ -88,11 +88,12 @@ export interface LinkSlots {
<script setup lang="ts">
import { computed } from 'vue'
import { defu } from 'defu'
import { isEqual } from 'ohash/utils'
import { useForwardProps } from 'reka-ui'
import { defu } from 'defu'
import { reactiveOmit } from '@vueuse/core'
import { useRoute, useAppConfig } from '#imports'
import { mergeClasses } from '../utils'
import { tv } from '../utils/tv'
import { isPartiallyEqual } from '../utils/link'
import ULinkBase from './LinkBase.vue'
@@ -103,9 +104,7 @@ const props = withDefaults(defineProps<LinkProps>(), {
as: 'button',
type: 'button',
ariaCurrentValue: 'page',
active: undefined,
activeClass: '',
inactiveClass: ''
active: undefined
})
defineSlots<LinkSlots>()
@@ -119,8 +118,8 @@ const ui = computed(() => tv({
...defu({
variants: {
active: {
true: props.activeClass,
false: props.inactiveClass
true: mergeClasses(appConfig.ui?.link?.variants?.active?.true, props.activeClass),
false: mergeClasses(appConfig.ui?.link?.variants?.active?.false, props.inactiveClass)
}
}
}, appConfig.ui?.link || {})

View File

@@ -1,6 +1,7 @@
<script setup lang="ts">
import { computed } from 'vue'
import { useOverlay, type Overlay } from '../composables/useOverlay'
import { useOverlay } from '../composables/useOverlay'
import type { Overlay } from '../composables/useOverlay'
const { overlays, unmount, close } = useOverlay()

View File

@@ -83,10 +83,10 @@ export interface TableProps<T extends TableData = TableData> extends TableOption
*/
empty?: string
/**
* Whether the table should have a sticky header.
* Whether the table should have a sticky header or footer. True for both, 'header' for header only, 'footer' for footer only.
* @defaultValue false
*/
sticky?: boolean
sticky?: boolean | 'header' | 'footer'
/** Whether the table should be in loading state. */
loading?: boolean
/**
@@ -172,6 +172,7 @@ export interface TableProps<T extends TableData = TableData> extends TableOption
}
type DynamicHeaderSlots<T, K = keyof T> = Record<string, (props: HeaderContext<T, unknown>) => any> & Record<`${K extends string ? K : never}-header`, (props: HeaderContext<T, unknown>) => any>
type DynamicFooterSlots<T, K = keyof T> = Record<string, (props: HeaderContext<T, unknown>) => any> & Record<`${K extends string ? K : never}-footer`, (props: HeaderContext<T, unknown>) => any>
type DynamicCellSlots<T, K = keyof T> = Record<string, (props: CellContext<T, unknown>) => any> & Record<`${K extends string ? K : never}-cell`, (props: CellContext<T, unknown>) => any>
export type TableSlots<T extends TableData = TableData> = {
@@ -181,7 +182,7 @@ export type TableSlots<T extends TableData = TableData> = {
'caption': (props?: {}) => any
'body-top': (props?: {}) => any
'body-bottom': (props?: {}) => any
} & DynamicHeaderSlots<T> & DynamicCellSlots<T>
} & DynamicHeaderSlots<T> & DynamicFooterSlots<T> & DynamicCellSlots<T>
</script>
@@ -216,6 +217,22 @@ const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.table || {})
loadingAnimation: props.loadingAnimation
}))
const hasFooter = computed(() => {
function hasFooterRecursive(columns: TableColumn<T>[]): boolean {
for (const column of columns) {
if ('footer' in column) {
return true
}
if ('columns' in column && hasFooterRecursive(column.columns as TableColumn<T>[])) {
return true
}
}
return false
}
return hasFooterRecursive(columns.value)
})
const globalFilterState = defineModel<string>('globalFilter', { default: undefined })
const columnFiltersState = defineModel<ColumnFiltersState>('columnFilters', { default: [] })
const columnOrderState = defineModel<ColumnOrderState>('columnOrder', { default: [] })
@@ -461,6 +478,30 @@ defineExpose({
<slot name="body-bottom" />
</tbody>
<tfoot v-if="hasFooter" :class="ui.tfoot({ class: [props.ui?.tfoot] })">
<tr :class="ui.separator({ class: [props.ui?.separator] })" />
<tr v-for="footerGroup in tableApi.getFooterGroups()" :key="footerGroup.id" :class="ui.tr({ class: [props.ui?.tr] })">
<th
v-for="header in footerGroup.headers"
:key="header.id"
:data-pinned="header.column.getIsPinned()"
:colspan="header.colSpan > 1 ? header.colSpan : undefined"
:class="ui.th({
class: [
props.ui?.th,
typeof header.column.columnDef.meta?.class?.th === 'function' ? header.column.columnDef.meta.class.th(header) : header.column.columnDef.meta?.class?.th
],
pinned: !!header.column.getIsPinned()
})"
>
<slot :name="`${header.id}-footer`" v-bind="header.getContext()">
<FlexRender v-if="!header.isPlaceholder" :render="header.column.columnDef.footer" :props="header.getContext()" />
</slot>
</th>
</tr>
</tfoot>
</table>
</Primitive>
</template>

View File

@@ -36,6 +36,8 @@ interface Shortcut {
const chainedShortcutRegex = /^[^-]+.*-.*[^-]+$/
const combinedShortcutRegex = /^[^_]+.*_.*[^_]+$/
// keyboard keys which can be combined with Shift modifier (in addition to alphabet keys)
const shiftableKeys = ['arrowleft', 'arrowright', 'arrowup', 'arrowright', 'tab', 'escape', 'enter', 'backspace']
export function extractShortcuts(items: any[] | any[][]) {
const shortcuts: Record<string, Handler> = {}
@@ -76,7 +78,8 @@ export function defineShortcuts(config: MaybeRef<ShortcutsConfig>, options: Shor
return
}
const alphabeticalKey = /^[a-z]{1}$/i.test(e.key)
const alphabetKey = /^[a-z]{1}$/i.test(e.key)
const shiftableKey = shiftableKeys.includes(e.key.toLowerCase())
let chainedKey
chainedInputs.value.push(e.key)
@@ -109,9 +112,9 @@ export function defineShortcuts(config: MaybeRef<ShortcutsConfig>, options: Shor
if (e.ctrlKey !== shortcut.ctrlKey) {
continue
}
// shift modifier is only checked in combination with alphabetical keys
// (shift with non-alphabetical keys would change the key)
if (alphabeticalKey && e.shiftKey !== shortcut.shiftKey) {
// shift modifier is only checked in combination with alphabet keys and some extra keys
// (shift with special characters would change the key)
if ((alphabetKey || shiftableKey) && e.shiftKey !== shortcut.shiftKey) {
continue
}
// alt modifier changes the combined key anyways

View File

@@ -1,4 +1,5 @@
import { inject, provide, computed, type ComputedRef, type InjectionKey } from 'vue'
import { inject, provide, computed } from 'vue'
import type { ComputedRef, InjectionKey } from 'vue'
import type { AvatarGroupProps } from '../types'
export const avatarGroupInjectionKey: InjectionKey<ComputedRef<{ size: AvatarGroupProps['size'] }>> = Symbol('nuxt-ui.avatar-group')

View File

@@ -1,4 +1,5 @@
import { computed, toValue, type MaybeRefOrGetter } from 'vue'
import { computed, toValue } from 'vue'
import type { MaybeRefOrGetter } from 'vue'
import { useAppConfig } from '#imports'
import type { AvatarProps } from '../types'

View File

@@ -1,5 +1,7 @@
import { inject, computed, type InjectionKey, type Ref, type ComputedRef, provide } from 'vue'
import { type UseEventBusReturn, useDebounceFn } from '@vueuse/core'
import { inject, computed, provide } from 'vue'
import type { InjectionKey, Ref, ComputedRef } from 'vue'
import { useDebounceFn } from '@vueuse/core'
import type { UseEventBusReturn } from '@vueuse/core'
import type { FormFieldProps } from '../types'
import type { FormEvent, FormInputEvents, FormFieldInjectedOptions, FormInjectedOptions } from '../types/form'
import type { GetObjectField } from '../types/utils'

View File

@@ -3,9 +3,34 @@ import { reactive, markRaw, shallowReactive } from 'vue'
import { createSharedComposable } from '@vueuse/core'
import type { ComponentProps, ComponentEmit } from 'vue-component-type-helpers'
// Extracts the first argument of the close event
type CloseEventArgType<T> = T extends (event: 'close', args_0: infer R) => void ? R : never
/**
* This is a workaround for a design limitation in TypeScript.
*
* Conditional types only match the last function overload, not a union of all possible
* parameter types. This workaround forces TypeScript to properly extract the 'close'
* event argument type from component emits with multiple event signatures.
*
* @see https://github.com/microsoft/TypeScript/issues/32164
*/
type CloseEventArgType<T> = T extends {
(event: 'close', arg_0: infer Arg, ...args: any[]): void
(...args: any[]): void
(...args: any[]): void
(...args: any[]): void
(...args: any[]): void
(...args: any[]): void
(...args: any[]): void
(...args: any[]): void
(...args: any[]): void
(...args: any[]): void
(...args: any[]): void
(...args: any[]): void
(...args: any[]): void
(...args: any[]): void
(...args: any[]): void
(...args: any[]): void
(...args: any[]): void
} ? Arg : never
export type OverlayOptions<OverlayAttrs = Record<string, any>> = {
defaultOpen?: boolean
props?: OverlayAttrs

View File

@@ -1,4 +1,5 @@
import { inject, provide, computed, type Ref, type InjectionKey } from 'vue'
import { inject, provide, computed } from 'vue'
import type { Ref, InjectionKey } from 'vue'
export const portalTargetInjectionKey: InjectionKey<Ref<string | HTMLElement>> = Symbol('nuxt-ui.portal-target')

View File

@@ -21,11 +21,11 @@ export interface Form<S extends FormSchema> {
blurredFields: ReadonlySet<DeepReadonly<keyof FormData<S, false>>>
}
export type FormSchema<I extends object = object, O extends object = I> =
| YupObjectSchema<I>
| JoiSchema<I>
| SuperstructSchema<any, any>
| StandardSchemaV1<I, O>
export type FormSchema<I extends object = object, O extends object = I>
= | YupObjectSchema<I>
| JoiSchema<I>
| SuperstructSchema<any, any>
| StandardSchemaV1<I, O>
// Define a utility type to infer the input type based on the schema type
export type InferInput<Schema> = Schema extends StandardSchemaV1 ? StandardSchemaV1.InferInput<Schema>
@@ -83,10 +83,10 @@ export type FormInputEvent<T extends object> = {
eager?: boolean
}
export type FormEvent<T extends object> =
| FormInputEvent<T>
| FormChildAttachEvent
| FormChildDetachEvent
export type FormEvent<T extends object>
= | FormInputEvent<T>
| FormChildAttachEvent
| FormChildDetachEvent
export interface FormInjectedOptions {
disabled?: boolean

View File

@@ -30,8 +30,8 @@ type ComponentSlots<T extends { slots?: Record<string, any> }> = Id<{
[K in keyof T['slots']]?: ClassValue
}>
type GetComponentAppConfig<A, U extends string, K extends string> =
A extends Record<U, Record<K, any>> ? A[U][K] : {}
type GetComponentAppConfig<A, U extends string, K extends string>
= A extends Record<U, Record<K, any>> ? A[U][K] : {}
type ComponentAppConfig<
T,

View File

@@ -44,8 +44,8 @@ export type MergeTypes<T extends object> = {
export type GetItemKeys<I> = keyof Extract<NestedItem<I>, object>
export type GetItemValue<I, VK extends GetItemKeys<I> | undefined, T extends NestedItem<I> = NestedItem<I>> =
T extends object
export type GetItemValue<I, VK extends GetItemKeys<I> | undefined, T extends NestedItem<I> = NestedItem<I>>
= T extends object
? VK extends undefined
? T
: VK extends keyof T
@@ -70,10 +70,10 @@ export type GetModelValueEmits<
'update:modelValue': [payload: GetModelValue<T, VK, M>]
}
export type StringOrVNode =
| string
| VNode
| (() => VNode)
export type StringOrVNode
= | string
| VNode
| (() => VNode)
export type EmitsToProps<T> = {
[K in keyof T as `on${Capitalize<string & K>}`]: T[K] extends [...args: infer Args]

View File

@@ -85,3 +85,14 @@ export function compare<T>(value?: T, currentValue?: T, comparator?: string | ((
export function isArrayOfArray<A>(item: A[] | A[][]): item is A[][] {
return Array.isArray(item[0])
}
export function mergeClasses(appConfigClass?: string | string[], propClass?: string) {
if (!appConfigClass && !propClass) {
return ''
}
return [
...(Array.isArray(appConfigClass) ? appConfigClass : [appConfigClass]),
propClass
].filter(Boolean)
}

View File

@@ -1,4 +1,5 @@
import { createTV, type defaultConfig } from 'tailwind-variants'
import { createTV } from 'tailwind-variants'
import type { defaultConfig } from 'tailwind-variants'
import type { AppConfig } from '@nuxt/schema'
import appConfig from '#build/app.config'

View File

@@ -7,6 +7,7 @@ export default (options: Required<ModuleOptions>) => ({
caption: 'sr-only',
thead: 'relative',
tbody: 'divide-y divide-default [&>tr]:data-[selectable=true]:hover:bg-elevated/50 [&>tr]:data-[selectable=true]:focus-visible:outline-primary',
tfoot: 'relative',
tr: 'data-[selected=true]:bg-elevated/50',
th: 'px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0',
td: 'p-4 text-sm text-muted whitespace-nowrap [&:has([role=checkbox])]:pe-0',
@@ -23,7 +24,14 @@ export default (options: Required<ModuleOptions>) => ({
},
sticky: {
true: {
thead: 'sticky top-0 inset-x-0 bg-default/75 z-[1] backdrop-blur',
tfoot: 'sticky bottom-0 inset-x-0 bg-default/75 z-[1] backdrop-blur'
},
header: {
thead: 'sticky top-0 inset-x-0 bg-default/75 z-[1] backdrop-blur'
},
footer: {
tfoot: 'sticky bottom-0 inset-x-0 bg-default/75 z-[1] backdrop-blur'
}
},
loading: {

View File

@@ -1,5 +1,6 @@
import { describe, it, expect } from 'vitest'
import Accordion, { type AccordionProps, type AccordionSlots } from '../../src/runtime/components/Accordion.vue'
import Accordion from '../../src/runtime/components/Accordion.vue'
import type { AccordionProps, AccordionSlots } from '../../src/runtime/components/Accordion.vue'
import ComponentRender from '../component-render'
describe('Accordion', () => {

View File

@@ -1,5 +1,6 @@
import { describe, it, expect } from 'vitest'
import Alert, { type AlertProps, type AlertSlots } from '../../src/runtime/components/Alert.vue'
import Alert from '../../src/runtime/components/Alert.vue'
import type { AlertProps, AlertSlots } from '../../src/runtime/components/Alert.vue'
import ComponentRender from '../component-render'
import theme from '#build/ui/alert'

View File

@@ -1,5 +1,6 @@
import { describe, it, expect } from 'vitest'
import Avatar, { type AvatarProps, type AvatarSlots } from '../../src/runtime/components/Avatar.vue'
import Avatar from '../../src/runtime/components/Avatar.vue'
import type { AvatarProps, AvatarSlots } from '../../src/runtime/components/Avatar.vue'
import ComponentRender from '../component-render'
import theme from '#build/ui/avatar'

View File

@@ -1,7 +1,8 @@
import { defineComponent } from 'vue'
import { describe, it, expect } from 'vitest'
import Avatar from '../../src/runtime/components/Avatar.vue'
import AvatarGroup, { type AvatarGroupProps, type AvatarGroupSlots } from '../../src/runtime/components/AvatarGroup.vue'
import AvatarGroup from '../../src/runtime/components/AvatarGroup.vue'
import type { AvatarGroupProps, AvatarGroupSlots } from '../../src/runtime/components/AvatarGroup.vue'
import ComponentRender from '../component-render'
import theme from '#build/ui/avatar-group'

View File

@@ -1,5 +1,6 @@
import { describe, it, expect } from 'vitest'
import Badge, { type BadgeProps, type BadgeSlots } from '../../src/runtime/components/Badge.vue'
import Badge from '../../src/runtime/components/Badge.vue'
import type { BadgeProps, BadgeSlots } from '../../src/runtime/components/Badge.vue'
import ComponentRender from '../component-render'
import theme from '#build/ui/badge'

View File

@@ -1,5 +1,6 @@
import { describe, it, expect } from 'vitest'
import Breadcrumb, { type BreadcrumbProps, type BreadcrumbSlots } from '../../src/runtime/components/Breadcrumb.vue'
import Breadcrumb from '../../src/runtime/components/Breadcrumb.vue'
import type { BreadcrumbProps, BreadcrumbSlots } from '../../src/runtime/components/Breadcrumb.vue'
import ComponentRender from '../component-render'
describe('Breadcrumb', () => {

View File

@@ -1,6 +1,7 @@
import { ref } from 'vue'
import { describe, it, expect, test } from 'vitest'
import Button, { type ButtonProps, type ButtonSlots } from '../../src/runtime/components/Button.vue'
import Button from '../../src/runtime/components/Button.vue'
import type { ButtonProps, ButtonSlots } from '../../src/runtime/components/Button.vue'
import ComponentRender from '../component-render'
import theme from '#build/ui/button'
import { mountSuspended } from '@nuxt/test-utils/runtime'

View File

@@ -1,5 +1,6 @@
import { describe, it, expect } from 'vitest'
import ButtonGroup, { type ButtonGroupProps, type ButtonGroupSlots } from '../../src/runtime/components/ButtonGroup.vue'
import ButtonGroup from '../../src/runtime/components/ButtonGroup.vue'
import type { ButtonGroupProps, ButtonGroupSlots } from '../../src/runtime/components/ButtonGroup.vue'
import ComponentRender from '../component-render'
import { UInput, UButton } from '#components'
import buttonTheme from '#build/ui/button'

View File

@@ -1,6 +1,7 @@
import { describe, it, expect, vi, afterAll, test } from 'vitest'
import { mountSuspended } from '@nuxt/test-utils/runtime'
import Calendar, { type CalendarProps, type CalendarSlots } from '../../src/runtime/components/Calendar.vue'
import Calendar from '../../src/runtime/components/Calendar.vue'
import type { CalendarProps, CalendarSlots } from '../../src/runtime/components/Calendar.vue'
import ComponentRender from '../component-render'
import theme from '#build/ui/calendar'
import { CalendarDate } from '@internationalized/date'

View File

@@ -1,5 +1,6 @@
import { describe, it, expect } from 'vitest'
import Card, { type CardProps, type CardSlots } from '../../src/runtime/components/Card.vue'
import Card from '../../src/runtime/components/Card.vue'
import type { CardProps, CardSlots } from '../../src/runtime/components/Card.vue'
import ComponentRender from '../component-render'
import theme from '#build/ui/card'

View File

@@ -1,6 +1,7 @@
import { defineComponent } from 'vue'
import { describe, it, expect } from 'vitest'
import Carousel, { type CarouselProps, type CarouselSlots } from '../../src/runtime/components/Carousel.vue'
import Carousel from '../../src/runtime/components/Carousel.vue'
import type { CarouselProps, CarouselSlots } from '../../src/runtime/components/Carousel.vue'
import ComponentRender from '../component-render'
const CarouselWrapper = defineComponent({

View File

@@ -1,5 +1,6 @@
import { describe, it, expect, test } from 'vitest'
import Checkbox, { type CheckboxProps, type CheckboxSlots } from '../../src/runtime/components/Checkbox.vue'
import Checkbox from '../../src/runtime/components/Checkbox.vue'
import type { CheckboxProps, CheckboxSlots } from '../../src/runtime/components/Checkbox.vue'
import ComponentRender from '../component-render'
import theme from '#build/ui/checkbox'
import { renderForm } from '../utils/form'

View File

@@ -1,5 +1,6 @@
import { describe, it, expect, test } from 'vitest'
import CheckboxGroup, { type CheckboxGroupProps, type CheckboxGroupSlots } from '../../src/runtime/components/CheckboxGroup.vue'
import CheckboxGroup from '../../src/runtime/components/CheckboxGroup.vue'
import type { CheckboxGroupProps, CheckboxGroupSlots } from '../../src/runtime/components/CheckboxGroup.vue'
import ComponentRender from '../component-render'
import theme from '#build/ui/checkbox-group'
import themeCheckbox from '#build/ui/checkbox'

View File

@@ -1,5 +1,6 @@
import { describe, it, expect } from 'vitest'
import Chip, { type ChipProps, type ChipSlots } from '../../src/runtime/components/Chip.vue'
import Chip from '../../src/runtime/components/Chip.vue'
import type { ChipProps, ChipSlots } from '../../src/runtime/components/Chip.vue'
import ComponentRender from '../component-render'
import theme from '#build/ui/chip'

View File

@@ -1,5 +1,6 @@
import { describe, it, expect } from 'vitest'
import Collapsible, { type CollapsibleProps, type CollapsibleSlots } from '../../src/runtime/components/Collapsible.vue'
import Collapsible from '../../src/runtime/components/Collapsible.vue'
import type { CollapsibleProps, CollapsibleSlots } from '../../src/runtime/components/Collapsible.vue'
import ComponentRender from '../component-render'
describe('Collapsible', () => {

View File

@@ -1,6 +1,7 @@
import { describe, it, expect, test } from 'vitest'
import { mountSuspended } from '@nuxt/test-utils/runtime'
import ColorPicker, { type ColorPickerProps } from '../../src/runtime/components/ColorPicker.vue'
import ColorPicker from '../../src/runtime/components/ColorPicker.vue'
import type { ColorPickerProps } from '../../src/runtime/components/ColorPicker.vue'
import ComponentRender from '../component-render'
import theme from '#build/ui/color-picker'

View File

@@ -1,5 +1,6 @@
import { describe, it, expect } from 'vitest'
import CommandPalette, { type CommandPaletteProps, type CommandPaletteSlots } from '../../src/runtime/components/CommandPalette.vue'
import CommandPalette from '../../src/runtime/components/CommandPalette.vue'
import type { CommandPaletteProps, CommandPaletteSlots } from '../../src/runtime/components/CommandPalette.vue'
import ComponentRender from '../component-render'
describe('CommandPalette', () => {

View File

@@ -1,5 +1,6 @@
import { describe, it, expect } from 'vitest'
import Container, { type ContainerProps, type ContainerSlots } from '../../src/runtime/components/Container.vue'
import Container from '../../src/runtime/components/Container.vue'
import type { ContainerProps, ContainerSlots } from '../../src/runtime/components/Container.vue'
import ComponentRender from '../component-render'
describe('Container', () => {

View File

@@ -1,6 +1,7 @@
import { h, defineComponent } from 'vue'
import { describe, it, expect, test } from 'vitest'
import ContextMenu, { type ContextMenuProps, type ContextMenuSlots } from '../../src/runtime/components/ContextMenu.vue'
import ContextMenu from '../../src/runtime/components/ContextMenu.vue'
import type { ContextMenuProps, ContextMenuSlots } from '../../src/runtime/components/ContextMenu.vue'
import theme from '#build/ui/context-menu'
import { mountSuspended } from '@nuxt/test-utils/runtime'
import { expectSlotProps } from '../utils/types'

View File

@@ -1,5 +1,6 @@
import { describe, it, expect } from 'vitest'
import Drawer, { type DrawerProps, type DrawerSlots } from '../../src/runtime/components/Drawer.vue'
import Drawer from '../../src/runtime/components/Drawer.vue'
import type { DrawerProps, DrawerSlots } from '../../src/runtime/components/Drawer.vue'
import ComponentRender from '../component-render'
import theme from '#build/ui/drawer'

View File

@@ -1,5 +1,6 @@
import { describe, it, expect, test } from 'vitest'
import DropdownMenu, { type DropdownMenuProps, type DropdownMenuSlots } from '../../src/runtime/components/DropdownMenu.vue'
import DropdownMenu from '../../src/runtime/components/DropdownMenu.vue'
import type { DropdownMenuProps, DropdownMenuSlots } from '../../src/runtime/components/DropdownMenu.vue'
import ComponentRender from '../component-render'
import theme from '#build/ui/dropdown-menu'
import { expectSlotProps } from '../utils/types'

View File

@@ -1,6 +1,7 @@
import { describe, it, expect, test } from 'vitest'
import { mount } from '@vue/test-utils'
import Input, { type InputProps, type InputSlots } from '../../src/runtime/components/Input.vue'
import Input from '../../src/runtime/components/Input.vue'
import type { InputProps, InputSlots } from '../../src/runtime/components/Input.vue'
import ComponentRender from '../component-render'
import theme from '#build/ui/input'

View File

@@ -1,5 +1,6 @@
import { describe, it, expect, test } from 'vitest'
import InputMenu, { type InputMenuProps, type InputMenuSlots } from '../../src/runtime/components/InputMenu.vue'
import InputMenu from '../../src/runtime/components/InputMenu.vue'
import type { InputMenuProps, InputMenuSlots } from '../../src/runtime/components/InputMenu.vue'
import ComponentRender from '../component-render'
import theme from '#build/ui/input'
import { renderForm } from '../utils/form'

View File

@@ -2,7 +2,8 @@ import { describe, it, expect, test } from 'vitest'
import { flushPromises } from '@vue/test-utils'
import { mountSuspended } from '@nuxt/test-utils/runtime'
import { reactive } from 'vue'
import InputNumber, { type InputNumberProps, type InputNumberSlots } from '../../src/runtime/components/InputNumber.vue'
import InputNumber from '../../src/runtime/components/InputNumber.vue'
import type { InputNumberProps, InputNumberSlots } from '../../src/runtime/components/InputNumber.vue'
import ComponentRender from '../component-render'
import theme from '#build/ui/input-number'
import type { FormInputEvents } from '~/src/module'

View File

@@ -1,6 +1,7 @@
import { describe, it, expect } from 'vitest'
import theme from '#build/ui/input'
import InputTags, { type InputTagsProps, type InputTagsSlots } from '../../src/runtime/components/InputTags.vue'
import InputTags from '../../src/runtime/components/InputTags.vue'
import type { InputTagsProps, InputTagsSlots } from '../../src/runtime/components/InputTags.vue'
import ComponentRender from '../component-render'
describe('InputTags', () => {

View File

@@ -1,5 +1,6 @@
import { describe, it, expect } from 'vitest'
import Kbd, { type KbdProps, type KbdSlots } from '../../src/runtime/components/Kbd.vue'
import Kbd from '../../src/runtime/components/Kbd.vue'
import type { KbdProps, KbdSlots } from '../../src/runtime/components/Kbd.vue'
import ComponentRender from '../component-render'
import theme from '#build/ui/kbd'

View File

@@ -1,5 +1,6 @@
import { describe, it, expect } from 'vitest'
import Modal, { type ModalProps, type ModalSlots } from '../../src/runtime/components/Modal.vue'
import Modal from '../../src/runtime/components/Modal.vue'
import type { ModalProps, ModalSlots } from '../../src/runtime/components/Modal.vue'
import ComponentRender from '../component-render'
describe('Modal', () => {

View File

@@ -1,5 +1,6 @@
import { describe, it, expect, test } from 'vitest'
import NavigationMenu, { type NavigationMenuProps, type NavigationMenuSlots } from '../../src/runtime/components/NavigationMenu.vue'
import NavigationMenu from '../../src/runtime/components/NavigationMenu.vue'
import type { NavigationMenuProps, NavigationMenuSlots } from '../../src/runtime/components/NavigationMenu.vue'
import ComponentRender from '../component-render'
import theme from '#build/ui/navigation-menu'
import { expectSlotProps } from '../utils/types'

View File

@@ -1,5 +1,6 @@
import { describe, it, expect } from 'vitest'
import Pagination, { type PaginationProps, type PaginationSlots } from '../../src/runtime/components/Pagination.vue'
import Pagination from '../../src/runtime/components/Pagination.vue'
import type { PaginationProps, PaginationSlots } from '../../src/runtime/components/Pagination.vue'
import ComponentRender from '../component-render'
import theme from '#build/ui/button'

View File

@@ -1,6 +1,7 @@
import { describe, it, expect, test } from 'vitest'
import { flushPromises, mount } from '@vue/test-utils'
import PinInput, { type PinInputProps } from '../../src/runtime/components/PinInput.vue'
import PinInput from '../../src/runtime/components/PinInput.vue'
import type { PinInputProps } from '../../src/runtime/components/PinInput.vue'
import ComponentRender from '../component-render'
import theme from '#build/ui/pin-input'

View File

@@ -1,5 +1,6 @@
import { describe, it, expect } from 'vitest'
import Popover, { type PopoverProps, type PopoverSlots } from '../../src/runtime/components/Popover.vue'
import Popover from '../../src/runtime/components/Popover.vue'
import type { PopoverProps, PopoverSlots } from '../../src/runtime/components/Popover.vue'
import ComponentRender from '../component-render'
describe('Popover', () => {

View File

@@ -1,5 +1,6 @@
import { describe, it, expect } from 'vitest'
import Progress, { type ProgressProps, type ProgressSlots } from '../../src/runtime/components/Progress.vue'
import Progress from '../../src/runtime/components/Progress.vue'
import type { ProgressProps, ProgressSlots } from '../../src/runtime/components/Progress.vue'
import ComponentRender from '../component-render'
import theme from '#build/ui/progress'

View File

@@ -1,5 +1,6 @@
import { describe, it, expect, test } from 'vitest'
import RadioGroup, { type RadioGroupProps, type RadioGroupSlots } from '../../src/runtime/components/RadioGroup.vue'
import RadioGroup from '../../src/runtime/components/RadioGroup.vue'
import type { RadioGroupProps, RadioGroupSlots } from '../../src/runtime/components/RadioGroup.vue'
import ComponentRender from '../component-render'
import theme from '#build/ui/radio-group'
import { flushPromises, mount } from '@vue/test-utils'

View File

@@ -1,6 +1,7 @@
import { describe, it, expect, test } from 'vitest'
import { flushPromises, mount } from '@vue/test-utils'
import Select, { type SelectProps, type SelectSlots } from '../../src/runtime/components/Select.vue'
import Select from '../../src/runtime/components/Select.vue'
import type { SelectProps, SelectSlots } from '../../src/runtime/components/Select.vue'
import ComponentRender from '../component-render'
import theme from '#build/ui/input'
import { renderForm } from '../utils/form'

View File

@@ -1,5 +1,6 @@
import { describe, it, expect, test } from 'vitest'
import SelectMenu, { type SelectMenuProps, type SelectMenuSlots } from '../../src/runtime/components/SelectMenu.vue'
import SelectMenu from '../../src/runtime/components/SelectMenu.vue'
import type { SelectMenuProps, SelectMenuSlots } from '../../src/runtime/components/SelectMenu.vue'
import ComponentRender from '../component-render'
import theme from '#build/ui/input'
import { renderForm } from '../utils/form'

View File

@@ -1,5 +1,6 @@
import { describe, it, expect } from 'vitest'
import Separator, { type SeparatorProps, type SeparatorSlots } from '../../src/runtime/components/Separator.vue'
import Separator from '../../src/runtime/components/Separator.vue'
import type { SeparatorProps, SeparatorSlots } from '../../src/runtime/components/Separator.vue'
import ComponentRender from '../component-render'
import theme from '#build/ui/separator'

View File

@@ -1,5 +1,6 @@
import { describe, it, expect } from 'vitest'
import Skeleton, { type SkeletonProps } from '../../src/runtime/components/Skeleton.vue'
import Skeleton from '../../src/runtime/components/Skeleton.vue'
import type { SkeletonProps } from '../../src/runtime/components/Skeleton.vue'
import ComponentRender from '../component-render'
describe('Skeleton', () => {

View File

@@ -1,5 +1,6 @@
import { describe, it, expect } from 'vitest'
import Slideover, { type SlideoverProps, type SlideoverSlots } from '../../src/runtime/components/Slideover.vue'
import Slideover from '../../src/runtime/components/Slideover.vue'
import type { SlideoverProps, SlideoverSlots } from '../../src/runtime/components/Slideover.vue'
import ComponentRender from '../component-render'
describe('Slideover', () => {

View File

@@ -1,5 +1,6 @@
import { describe, it, expect, test } from 'vitest'
import Slider, { type SliderProps } from '../../src/runtime/components/Slider.vue'
import Slider from '../../src/runtime/components/Slider.vue'
import type { SliderProps } from '../../src/runtime/components/Slider.vue'
import ComponentRender from '../component-render'
import theme from '#build/ui/slider'
import { flushPromises, mount } from '@vue/test-utils'

View File

@@ -1,5 +1,6 @@
import { describe, it, expect } from 'vitest'
import Stepper, { type StepperProps, type StepperSlots } from '../../src/runtime/components/Stepper.vue'
import Stepper from '../../src/runtime/components/Stepper.vue'
import type { StepperProps, StepperSlots } from '../../src/runtime/components/Stepper.vue'
import ComponentRender from '../component-render'
import theme from '#build/ui/stepper'

View File

@@ -1,5 +1,6 @@
import { describe, it, expect, test } from 'vitest'
import Switch, { type SwitchProps, type SwitchSlots } from '../../src/runtime/components/Switch.vue'
import Switch from '../../src/runtime/components/Switch.vue'
import type { SwitchProps, SwitchSlots } from '../../src/runtime/components/Switch.vue'
import ComponentRender from '../component-render'
import theme from '#build/ui/switch'
import { flushPromises, mount } from '@vue/test-utils'

View File

@@ -3,7 +3,8 @@ import { describe, it, expect } from 'vitest'
import { flushPromises } from '@vue/test-utils'
import { mountSuspended } from '@nuxt/test-utils/runtime'
import { UCheckbox, UButton, UBadge, UDropdownMenu } from '#components'
import Table, { type TableProps, type TableSlots, type TableColumn } from '../../src/runtime/components/Table.vue'
import Table from '../../src/runtime/components/Table.vue'
import type { TableProps, TableSlots, TableColumn, TableRow } from '../../src/runtime/components/Table.vue'
import ComponentRender from '../component-render'
import theme from '#build/ui/table'
@@ -98,6 +99,16 @@ describe('Table', () => {
}, {
accessorKey: 'amount',
header: () => h('div', { class: 'text-right' }, 'Amount'),
footer: ({ column }) => {
const total = column.getFacetedRowModel().rows.reduce((acc: number, row: TableRow<typeof data[number]>) => acc + Number.parseFloat(row.getValue('amount')), 0)
const formatted = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'EUR'
}).format(total)
return h('div', { class: 'text-right font-medium' }, `Total: ${formatted}`)
},
cell: ({ row }) => {
const amount = Number.parseFloat(row.getValue('amount'))

View File

@@ -1,5 +1,6 @@
import { describe, it, expect } from 'vitest'
import Tabs, { type TabsProps, type TabsSlots } from '../../src/runtime/components/Tabs.vue'
import Tabs from '../../src/runtime/components/Tabs.vue'
import type { TabsProps, TabsSlots } from '../../src/runtime/components/Tabs.vue'
import ComponentRender from '../component-render'
import theme from '#build/ui/tabs'

View File

@@ -1,6 +1,7 @@
import { describe, it, expect, test } from 'vitest'
import { mount } from '@vue/test-utils'
import Textarea, { type TextareaProps, type TextareaSlots } from '../../src/runtime/components/Textarea.vue'
import Textarea from '../../src/runtime/components/Textarea.vue'
import type { TextareaProps, TextareaSlots } from '../../src/runtime/components/Textarea.vue'
import ComponentRender from '../component-render'
import theme from '#build/ui/textarea'
import { renderForm } from '../utils/form'

View File

@@ -1,5 +1,6 @@
import { describe, it, expect } from 'vitest'
import Timeline, { type TimelineProps, type TimelineSlots } from '../../src/runtime/components/Timeline.vue'
import Timeline from '../../src/runtime/components/Timeline.vue'
import type { TimelineProps, TimelineSlots } from '../../src/runtime/components/Timeline.vue'
import ComponentRender from '../component-render'
import theme from '#build/ui/timeline'

View File

@@ -1,7 +1,8 @@
import { defineComponent } from 'vue'
import { describe, it, expect } from 'vitest'
import Toaster from '../../src/runtime/components/Toaster.vue'
import Toast, { type ToastProps, type ToastSlots } from '../../src/runtime/components/Toast.vue'
import Toast from '../../src/runtime/components/Toast.vue'
import type { ToastProps, ToastSlots } from '../../src/runtime/components/Toast.vue'
import ComponentRender from '../component-render'
import { ClientOnly } from '#components'

View File

@@ -1,7 +1,8 @@
import { defineComponent } from 'vue'
import { describe, it, expect } from 'vitest'
import { TooltipProvider } from 'reka-ui'
import Tooltip, { type TooltipProps, type TooltipSlots } from '../../src/runtime/components/Tooltip.vue'
import Tooltip from '../../src/runtime/components/Tooltip.vue'
import type { TooltipProps, TooltipSlots } from '../../src/runtime/components/Tooltip.vue'
import ComponentRender from '../component-render'
const TooltipWrapper = defineComponent({

View File

@@ -1,5 +1,6 @@
import { describe, it, expect, test } from 'vitest'
import Tree, { type TreeProps, type TreeSlots, type TreeItem } from '../../src/runtime/components/Tree.vue'
import Tree from '../../src/runtime/components/Tree.vue'
import type { TreeProps, TreeSlots, TreeItem } from '../../src/runtime/components/Tree.vue'
import ComponentRender from '../component-render'
import theme from '#build/ui/tree'
import { expectEmitPayloadType } from '../utils/types'

View File

@@ -50,6 +50,7 @@ exports[`Table > renders with as correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</section>"
`;
@@ -104,6 +105,7 @@ exports[`Table > renders with body-bottom slot correctly 1`] = `
</tr>
<!--v-if-->Body bottom slot
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -157,6 +159,7 @@ exports[`Table > renders with body-top slot correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -211,6 +214,7 @@ exports[`Table > renders with caption correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -265,6 +269,7 @@ exports[`Table > renders with caption slot correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -319,6 +324,7 @@ exports[`Table > renders with cell slot correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -373,6 +379,7 @@ exports[`Table > renders with class correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -564,6 +571,32 @@ exports[`Table > renders with columns correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<tfoot class="relative">
<tr class="absolute z-[1] left-0 w-full h-px bg-(--ui-border-accented)"></tr>
<tr class="data-[selected=true]:bg-elevated/50">
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&amp;:has([role=checkbox])]:pe-0">
<!---->
</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&amp;:has([role=checkbox])]:pe-0">
<!---->
</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&amp;:has([role=checkbox])]:pe-0">
<!---->
</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&amp;:has([role=checkbox])]:pe-0">
<!---->
</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&amp;:has([role=checkbox])]:pe-0">
<!---->
</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&amp;:has([role=checkbox])]:pe-0">
<div class="text-right font-medium">Total: €2,990.00</div>
</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&amp;:has([role=checkbox])]:pe-0">
<!---->
</th>
</tr>
</tfoot>
</table>
</div>"
`;
@@ -618,6 +651,7 @@ exports[`Table > renders with data correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -635,6 +669,7 @@ exports[`Table > renders with empty correctly 1`] = `
<td colspan="0" class="py-6 text-center text-sm text-muted">There is no data</td>
</tr>
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -674,6 +709,32 @@ exports[`Table > renders with empty slot correctly 1`] = `
<td colspan="7" class="py-6 text-center text-sm text-muted">Empty slot</td>
</tr>
</tbody>
<tfoot class="relative">
<tr class="absolute z-[1] left-0 w-full h-px bg-(--ui-border-accented)"></tr>
<tr class="data-[selected=true]:bg-elevated/50">
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&amp;:has([role=checkbox])]:pe-0">
<!---->
</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&amp;:has([role=checkbox])]:pe-0">
<!---->
</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&amp;:has([role=checkbox])]:pe-0">
<!---->
</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&amp;:has([role=checkbox])]:pe-0">
<!---->
</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&amp;:has([role=checkbox])]:pe-0">
<!---->
</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&amp;:has([role=checkbox])]:pe-0">
<div class="text-right font-medium">Total: €0.00</div>
</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&amp;:has([role=checkbox])]:pe-0">
<!---->
</th>
</tr>
</tfoot>
</table>
</div>"
`;
@@ -728,6 +789,7 @@ exports[`Table > renders with expanded slot correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -782,6 +844,7 @@ exports[`Table > renders with header slot correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -836,6 +899,7 @@ exports[`Table > renders with loading animation carousel correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -890,6 +954,7 @@ exports[`Table > renders with loading animation carousel-inverse correctly 1`] =
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -944,6 +1009,7 @@ exports[`Table > renders with loading animation elastic correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -998,6 +1064,7 @@ exports[`Table > renders with loading animation swing correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -1052,6 +1119,7 @@ exports[`Table > renders with loading color error correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -1106,6 +1174,7 @@ exports[`Table > renders with loading color info correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -1160,6 +1229,7 @@ exports[`Table > renders with loading color neutral correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -1214,6 +1284,7 @@ exports[`Table > renders with loading color primary correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -1268,6 +1339,7 @@ exports[`Table > renders with loading color secondary correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -1322,6 +1394,7 @@ exports[`Table > renders with loading color success correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -1376,6 +1449,7 @@ exports[`Table > renders with loading color warning correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -1430,6 +1504,7 @@ exports[`Table > renders with loading correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -1469,6 +1544,32 @@ exports[`Table > renders with loading slot correctly 1`] = `
<td colspan="7" class="py-6 text-center">Loading slot</td>
</tr>
</tbody>
<tfoot class="relative">
<tr class="absolute z-[1] left-0 w-full h-px bg-(--ui-border-accented)"></tr>
<tr class="data-[selected=true]:bg-elevated/50">
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&amp;:has([role=checkbox])]:pe-0">
<!---->
</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&amp;:has([role=checkbox])]:pe-0">
<!---->
</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&amp;:has([role=checkbox])]:pe-0">
<!---->
</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&amp;:has([role=checkbox])]:pe-0">
<!---->
</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&amp;:has([role=checkbox])]:pe-0">
<!---->
</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&amp;:has([role=checkbox])]:pe-0">
<div class="text-right font-medium">Total: €0.00</div>
</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&amp;:has([role=checkbox])]:pe-0">
<!---->
</th>
</tr>
</tfoot>
</table>
</div>"
`;
@@ -1523,6 +1624,7 @@ exports[`Table > renders with sticky correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -1577,6 +1679,7 @@ exports[`Table > renders with ui correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -1594,6 +1697,7 @@ exports[`Table > renders without data correctly 1`] = `
<td colspan="0" class="py-6 text-center text-sm text-muted">No data</td>
</tr>
</tbody>
<!--v-if-->
</table>
</div>"
`;

View File

@@ -50,6 +50,7 @@ exports[`Table > renders with as correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</section>"
`;
@@ -104,6 +105,7 @@ exports[`Table > renders with body-bottom slot correctly 1`] = `
</tr>
<!--v-if-->Body bottom slot
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -157,6 +159,7 @@ exports[`Table > renders with body-top slot correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -211,6 +214,7 @@ exports[`Table > renders with caption correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -265,6 +269,7 @@ exports[`Table > renders with caption slot correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -319,6 +324,7 @@ exports[`Table > renders with cell slot correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -373,6 +379,7 @@ exports[`Table > renders with class correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -564,6 +571,32 @@ exports[`Table > renders with columns correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<tfoot class="relative">
<tr class="absolute z-[1] left-0 w-full h-px bg-(--ui-border-accented)"></tr>
<tr class="data-[selected=true]:bg-elevated/50">
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&amp;:has([role=checkbox])]:pe-0">
<!---->
</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&amp;:has([role=checkbox])]:pe-0">
<!---->
</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&amp;:has([role=checkbox])]:pe-0">
<!---->
</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&amp;:has([role=checkbox])]:pe-0">
<!---->
</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&amp;:has([role=checkbox])]:pe-0">
<!---->
</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&amp;:has([role=checkbox])]:pe-0">
<div class="text-right font-medium">Total: €2,990.00</div>
</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&amp;:has([role=checkbox])]:pe-0">
<!---->
</th>
</tr>
</tfoot>
</table>
</div>"
`;
@@ -618,6 +651,7 @@ exports[`Table > renders with data correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -635,6 +669,7 @@ exports[`Table > renders with empty correctly 1`] = `
<td colspan="0" class="py-6 text-center text-sm text-muted">There is no data</td>
</tr>
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -674,6 +709,32 @@ exports[`Table > renders with empty slot correctly 1`] = `
<td colspan="7" class="py-6 text-center text-sm text-muted">Empty slot</td>
</tr>
</tbody>
<tfoot class="relative">
<tr class="absolute z-[1] left-0 w-full h-px bg-(--ui-border-accented)"></tr>
<tr class="data-[selected=true]:bg-elevated/50">
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&amp;:has([role=checkbox])]:pe-0">
<!---->
</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&amp;:has([role=checkbox])]:pe-0">
<!---->
</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&amp;:has([role=checkbox])]:pe-0">
<!---->
</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&amp;:has([role=checkbox])]:pe-0">
<!---->
</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&amp;:has([role=checkbox])]:pe-0">
<!---->
</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&amp;:has([role=checkbox])]:pe-0">
<div class="text-right font-medium">Total: €0.00</div>
</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&amp;:has([role=checkbox])]:pe-0">
<!---->
</th>
</tr>
</tfoot>
</table>
</div>"
`;
@@ -728,6 +789,7 @@ exports[`Table > renders with expanded slot correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -782,6 +844,7 @@ exports[`Table > renders with header slot correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -836,6 +899,7 @@ exports[`Table > renders with loading animation carousel correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -890,6 +954,7 @@ exports[`Table > renders with loading animation carousel-inverse correctly 1`] =
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -944,6 +1009,7 @@ exports[`Table > renders with loading animation elastic correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -998,6 +1064,7 @@ exports[`Table > renders with loading animation swing correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -1052,6 +1119,7 @@ exports[`Table > renders with loading color error correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -1106,6 +1174,7 @@ exports[`Table > renders with loading color info correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -1160,6 +1229,7 @@ exports[`Table > renders with loading color neutral correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -1214,6 +1284,7 @@ exports[`Table > renders with loading color primary correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -1268,6 +1339,7 @@ exports[`Table > renders with loading color secondary correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -1322,6 +1394,7 @@ exports[`Table > renders with loading color success correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -1376,6 +1449,7 @@ exports[`Table > renders with loading color warning correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -1430,6 +1504,7 @@ exports[`Table > renders with loading correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -1469,6 +1544,32 @@ exports[`Table > renders with loading slot correctly 1`] = `
<td colspan="7" class="py-6 text-center">Loading slot</td>
</tr>
</tbody>
<tfoot class="relative">
<tr class="absolute z-[1] left-0 w-full h-px bg-(--ui-border-accented)"></tr>
<tr class="data-[selected=true]:bg-elevated/50">
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&amp;:has([role=checkbox])]:pe-0">
<!---->
</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&amp;:has([role=checkbox])]:pe-0">
<!---->
</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&amp;:has([role=checkbox])]:pe-0">
<!---->
</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&amp;:has([role=checkbox])]:pe-0">
<!---->
</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&amp;:has([role=checkbox])]:pe-0">
<!---->
</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&amp;:has([role=checkbox])]:pe-0">
<div class="text-right font-medium">Total: €0.00</div>
</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&amp;:has([role=checkbox])]:pe-0">
<!---->
</th>
</tr>
</tfoot>
</table>
</div>"
`;
@@ -1523,6 +1624,7 @@ exports[`Table > renders with sticky correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -1577,6 +1679,7 @@ exports[`Table > renders with ui correctly 1`] = `
</tr>
<!--v-if-->
</tbody>
<!--v-if-->
</table>
</div>"
`;
@@ -1594,6 +1697,7 @@ exports[`Table > renders without data correctly 1`] = `
<td colspan="0" class="py-6 text-center text-sm text-muted">No data</td>
</tr>
</tbody>
<!--v-if-->
</table>
</div>"
`;