feat(Table): implement component (#2364)

This commit is contained in:
Benjamin Canac
2024-10-23 17:32:30 +02:00
committed by GitHub
parent 34bddd45be
commit b54950e3ed
40 changed files with 4000 additions and 62 deletions

View File

@@ -32,6 +32,10 @@ const props = defineProps<{
* @defaultValue false
*/
collapse?: boolean
/**
* A list of line numbers to highlight in the code block
*/
highlights?: number[]
}>()
const route = useRoute()
@@ -105,7 +109,7 @@ const code = computed(() => {
`
}
code += `\`\`\`vue`
code += `\`\`\`vue${props.highlights?.length ? ` {${props.highlights.join('-')}}` : ''}`
if (props.external?.length) {
code += `
@@ -201,7 +205,8 @@ const { data: ast } = await useAsyncData(`component-code-${name}-${hash({ props:
formatted = await $prettier.format(code.value, {
trailingComma: 'none',
semi: false,
singleQuote: true
singleQuote: true,
printWidth: 100
})
} catch {
formatted = code.value

View File

@@ -22,13 +22,11 @@ const props = withDefaults(defineProps<{
* @defaultValue true
*/
preview?: boolean
/**
* Whether to show the source code
* @defaultValue true
*/
source?: boolean
/**
* A list of variable props to link to the component.
*/
@@ -40,6 +38,10 @@ const props = withDefaults(defineProps<{
default: any
multiple?: boolean
}>
/**
* A list of line numbers to highlight in the code block
*/
highlights?: number[]
}>(), {
preview: true,
source: true
@@ -65,7 +67,7 @@ const code = computed(() => {
`
}
code += `\`\`\`vue${props.preview ? '' : ` [${data.pascalName}.vue]`}
code += `\`\`\`vue ${props.preview ? '' : ` [${data.pascalName}.vue]`}${props.highlights?.length ? `{${props.highlights.join('-')}}` : ''}
${data?.code ?? ''}
\`\`\``
@@ -87,7 +89,8 @@ const { data: ast } = await useAsyncData(`component-example-${camelName}`, async
formatted = await $prettier.format(code.value, {
trailingComma: 'none',
semi: false,
singleQuote: true
singleQuote: true,
printWidth: 100
})
} catch {
formatted = code.value
@@ -113,7 +116,7 @@ const optionsValues = ref(props.options?.reduce((acc, option) => {
<template>
<div class="my-5">
<div v-if="preview">
<template v-if="preview">
<div class="border border-[var(--ui-color-neutral-200)] dark:border-[var(--ui-color-neutral-700)] relative z-[1]" :class="[{ 'border-b-0 rounded-t-[calc(var(--ui-radius)*1.5)]': props.source, 'rounded-[calc(var(--ui-radius)*1.5)]': !props.source }]">
<div v-if="props.options?.length || !!slots.options" class="flex gap-4 p-4 border-b border-[var(--ui-color-neutral-200)] dark:border-[var(--ui-color-neutral-700)]">
<slot name="options" />
@@ -170,7 +173,7 @@ const optionsValues = ref(props.options?.reduce((acc, option) => {
<component :is="camelName" v-bind="{ ...componentProps, ...optionsValues }" />
</div>
</div>
</div>
</template>
<MDCRenderer v-if="ast && props.source" :body="ast.body" :data="ast.data" class="[&_pre]:!rounded-t-none [&_div.my-5]:!mt-0" />
</div>

View File

@@ -99,6 +99,7 @@ const metaProps: ComputedRef<ComponentMeta['props']> = computed(() => {
<MDC v-if="prop.description" :value="prop.description" class="text-[var(--ui-text-toned)] mt-1" />
<ComponentPropsLinks v-if="prop.tags?.length" :prop="prop" />
<ComponentPropsSchema v-if="prop.schema" :prop="prop" :ignore="ignore" />
</ProseTd>
</ProseTr>

View File

@@ -0,0 +1,17 @@
<script setup lang="ts">
import type { PropertyMeta } from 'vue-component-meta'
const props = defineProps<{
prop: PropertyMeta
}>()
const links = computed(() => props.prop.tags?.filter((tag: any) => tag.name === 'link'))
</script>
<template>
<ProseUl v-if="links?.length">
<ProseLi v-for="link in links" :key="link.name">
<MDC :value="link.text ?? ''" class="my-1" />
</ProseLi>
</ProseUl>
</template>

View File

@@ -28,6 +28,14 @@ function stripCompoundVariants(component?: any) {
}
}
if (compoundVariant.loadingColor) {
if (!['primary', 'neutral'].includes(compoundVariant.loadingColor)) {
strippedCompoundVariants.value = true
return false
}
}
return true
})
}

View File

@@ -0,0 +1,119 @@
<script setup lang="ts">
import { h, resolveComponent } from 'vue'
import type { TableColumn } 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'),
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)
}
}]
const table = useTemplateRef('table')
const columnFilters = ref([{
id: 'email',
value: 'james'
}])
</script>
<template>
<div class="flex flex-col flex-1">
<div class="flex px-4 py-3.5 border-b border-[var(--ui-border-accented)]">
<UInput
:model-value="(table?.tableApi?.getColumn('email')?.getFilterValue() as string)"
class="max-w-sm"
placeholder="Filter emails..."
@update:model-value="table?.tableApi?.getColumn('email')?.setFilterValue($event)"
/>
</div>
<UTable
ref="table"
v-model:column-filters="columnFilters"
:data="data"
:columns="columns"
/>
</div>
</template>

View File

@@ -0,0 +1,114 @@
<script setup lang="ts">
import { h, resolveComponent } from 'vue'
import type { TableColumn } from '@nuxt/ui'
import type { Column } from '@tanstack/vue-table'
const UBadge = resolveComponent('UBadge')
const UButton = resolveComponent('UButton')
type Payment = {
id: string
date: string
status: 'paid' | 'failed' | 'refunded'
email: string
amount: number
}
const data = ref<Payment[]>([{
id: '46000000000000000000000000000000000000000',
date: '2024-03-11T15:30:00',
status: 'paid',
email: 'james.anderson@example.com',
amount: 594000
}, {
id: '45990000000000000000000000000000000000000',
date: '2024-03-11T10:10:00',
status: 'failed',
email: 'mia.white@example.com',
amount: 276000
}, {
id: '45980000000000000000000000000000000000000',
date: '2024-03-11T08:50:00',
status: 'refunded',
email: 'william.brown@example.com',
amount: 315000
}, {
id: '45970000000000000000000000000000000000000',
date: '2024-03-10T19:45:00',
status: 'paid',
email: 'emma.davis@example.com',
amount: 5290000
}, {
id: '45960000000000000000000000000000000000000',
date: '2024-03-10T15:55:00',
status: 'paid',
email: 'ethan.harris@example.com',
amount: 639000
}])
const columns: TableColumn<Payment>[] = [{
accessorKey: 'id',
header: ({ column }) => getHeader(column, 'ID', 'left'),
cell: ({ row }) => `#${row.getValue('id')}`
}, {
accessorKey: 'date',
header: ({ column }) => getHeader(column, 'Date', 'left')
}, {
accessorKey: 'status',
header: ({ column }) => getHeader(column, 'Status', 'left'),
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: ({ column }) => getHeader(column, 'Email', 'left')
}, {
accessorKey: 'amount',
header: ({ column }) => h('div', { class: 'text-right' }, getHeader(column, 'Amount', 'right')),
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)
}
}]
function getHeader(column: Column<Payment>, label: string, position: 'left' | 'right') {
const isPinned = column.getIsPinned()
return h(UButton, {
color: 'neutral',
variant: 'ghost',
label,
icon: isPinned ? 'i-heroicons-star-20-solid' : 'i-heroicons-star',
class: '-mx-2.5',
onClick() {
column.pin(isPinned === position ? false : position)
}
})
}
const columnPinning = ref({
left: [],
right: ['amount']
})
</script>
<template>
<UTable
v-model:column-pinning="columnPinning"
:data="data"
:columns="columns"
class="flex-1"
/>
</template>

View File

@@ -0,0 +1,118 @@
<script setup lang="ts">
import { h, resolveComponent } from 'vue'
import type { TableColumn } from '@nuxt/ui'
const UBadge = resolveComponent('UBadge')
const UButton = resolveComponent('UButton')
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: ({ column }) => {
const isSorted = column.getIsSorted()
return h(UButton, {
color: 'neutral',
variant: 'ghost',
label: 'Email',
icon: isSorted ? (isSorted === 'asc' ? 'i-heroicons-bars-arrow-up-20-solid' : 'i-heroicons-bars-arrow-down-20-solid') : 'i-heroicons-arrows-up-down-20-solid',
class: '-mx-2.5',
onClick: () => column.toggleSorting(column.getIsSorted() === 'asc')
})
}
}, {
accessorKey: 'amount',
header: () => h('div', { class: 'text-right' }, 'Amount'),
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)
}
}]
const sorting = ref([{
id: 'email',
desc: false
}])
</script>
<template>
<UTable
v-model:sorting="sorting"
:data="data"
:columns="columns"
class="flex-1"
/>
</template>

View File

@@ -0,0 +1,150 @@
<script setup lang="ts">
import { h, resolveComponent } from 'vue'
import type { TableColumn } from '@nuxt/ui'
import type { Column } from '@tanstack/vue-table'
const UBadge = resolveComponent('UBadge')
const UButton = resolveComponent('UButton')
const UDropdownMenu = resolveComponent('UDropdownMenu')
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: ({ column }) => getHeader(column, 'ID'),
cell: ({ row }) => `#${row.getValue('id')}`
}, {
accessorKey: 'date',
header: ({ column }) => getHeader(column, '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: ({ column }) => getHeader(column, '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: ({ column }) => getHeader(column, 'Email')
}, {
accessorKey: 'amount',
header: ({ column }) => h('div', { class: 'text-right' }, getHeader(column, 'Amount')),
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)
}
}]
function getHeader(column: Column<Payment>, label: string) {
const isSorted = column.getIsSorted()
return h(UDropdownMenu, {
content: {
align: 'start'
},
items: [{
label: 'Asc',
type: 'checkbox',
icon: 'i-heroicons-bars-arrow-up-20-solid',
checked: isSorted === 'asc',
onSelect: () => {
if (isSorted === 'asc') {
column.clearSorting()
} else {
column.toggleSorting(false)
}
}
}, {
label: 'Desc',
icon: 'i-heroicons-bars-arrow-down-20-solid',
type: 'checkbox',
checked: isSorted === 'desc',
onSelect: () => {
if (isSorted === 'desc') {
column.clearSorting()
} else {
column.toggleSorting(true)
}
}
}]
}, () => h(UButton, {
color: 'neutral',
variant: 'ghost',
label,
icon: isSorted ? (isSorted === 'asc' ? 'i-heroicons-bars-arrow-up-20-solid' : 'i-heroicons-bars-arrow-down-20-solid') : 'i-heroicons-arrows-up-down-20-solid',
class: '-mx-2.5 data-[state=open]:bg-[var(--ui-bg-elevated)]'
}))
}
const sorting = ref([{
id: 'id',
desc: false
}])
</script>
<template>
<UTable
v-model:sorting="sorting"
:data="data"
:columns="columns"
class="flex-1"
/>
</template>

View File

@@ -0,0 +1,134 @@
<script setup lang="ts">
import { h, resolveComponent } from 'vue'
import { upperFirst } from 'scule'
import type { TableColumn } 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'),
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)
}
}]
const table = useTemplateRef('table')
const columnVisibility = ref({
id: false
})
</script>
<template>
<div class="flex flex-col flex-1">
<div class="flex justify-end px-4 py-3.5 border-b border-[var(--ui-border-accented)]">
<UDropdownMenu
:items="table?.tableApi?.getAllColumns().filter(column => column.getCanHide()).map(column => ({
label: upperFirst(column.id),
type: 'checkbox' as const,
checked: column.getIsVisible(),
onUpdateChecked(checked: boolean) {
table?.tableApi?.getColumn(column.id)?.toggleVisibility(!!checked)
},
onSelect(e?: Event) {
e?.preventDefault()
}
}))"
:content="{ align: 'end' }"
>
<UButton
label="Columns"
color="neutral"
variant="outline"
trailing-icon="i-heroicons-chevron-down-20-solid"
/>
</UDropdownMenu>
</div>
<UTable
ref="table"
v-model:column-visibility="columnVisibility"
:data="data"
:columns="columns"
/>
</div>
</template>

View File

@@ -0,0 +1,96 @@
<script setup lang="ts">
import { h, resolveComponent } from 'vue'
import type { TableColumn } 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'),
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

@@ -0,0 +1,319 @@
<script setup lang="ts">
import { h, resolveComponent } from 'vue'
import { upperFirst } from 'scule'
import type { TableColumn } from '@nuxt/ui'
const UButton = resolveComponent('UButton')
const UCheckbox = resolveComponent('UCheckbox')
const UBadge = resolveComponent('UBadge')
const UDropdownMenu = resolveComponent('UDropdownMenu')
const toast = useToast()
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
}, {
id: '4595',
date: '2024-03-10T13:40:00',
status: 'refunded',
email: 'ava.thomas@example.com',
amount: 428
}, {
id: '4594',
date: '2024-03-10T09:15:00',
status: 'paid',
email: 'michael.wilson@example.com',
amount: 683
}, {
id: '4593',
date: '2024-03-09T20:25:00',
status: 'failed',
email: 'olivia.taylor@example.com',
amount: 947
}, {
id: '4592',
date: '2024-03-09T18:45:00',
status: 'paid',
email: 'benjamin.jackson@example.com',
amount: 851
}, {
id: '4591',
date: '2024-03-09T16:05:00',
status: 'paid',
email: 'sophia.miller@example.com',
amount: 762
}, {
id: '4590',
date: '2024-03-09T14:20:00',
status: 'paid',
email: 'noah.clark@example.com',
amount: 573
}, {
id: '4589',
date: '2024-03-09T11:35:00',
status: 'failed',
email: 'isabella.lee@example.com',
amount: 389
}, {
id: '4588',
date: '2024-03-08T22:50:00',
status: 'refunded',
email: 'liam.walker@example.com',
amount: 701
}, {
id: '4587',
date: '2024-03-08T20:15:00',
status: 'paid',
email: 'charlotte.hall@example.com',
amount: 856
}, {
id: '4586',
date: '2024-03-08T17:40:00',
status: 'paid',
email: 'mason.young@example.com',
amount: 492
}, {
id: '4585',
date: '2024-03-08T14:55:00',
status: 'failed',
email: 'amelia.king@example.com',
amount: 637
}, {
id: '4584',
date: '2024-03-08T12:30:00',
status: 'paid',
email: 'elijah.wright@example.com',
amount: 784
}, {
id: '4583',
date: '2024-03-08T09:45:00',
status: 'refunded',
email: 'harper.scott@example.com',
amount: 345
}, {
id: '4582',
date: '2024-03-07T23:10:00',
status: 'paid',
email: 'evelyn.green@example.com',
amount: 918
}, {
id: '4581',
date: '2024-03-07T20:25:00',
status: 'paid',
email: 'logan.baker@example.com',
amount: 567
}])
const columns: TableColumn<Payment>[] = [{
id: 'select',
header: ({ table }) => h(UCheckbox, {
'modelValue': table.getIsAllPageRowsSelected(),
'indeterminate': table.getIsSomePageRowsSelected(),
'onUpdate:modelValue': (value: boolean) => table.toggleAllPageRowsSelected(!!value),
'ariaLabel': 'Select all'
}),
cell: ({ row }) => h(UCheckbox, {
'modelValue': row.getIsSelected(),
'onUpdate:modelValue': (value: boolean) => row.toggleSelected(!!value),
'ariaLabel': 'Select row'
}),
enableSorting: false,
enableHiding: false
}, {
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: ({ column }) => {
const isSorted = column.getIsSorted()
return h(UButton, {
color: 'neutral',
variant: 'ghost',
label: 'Email',
icon: isSorted ? (isSorted === 'asc' ? 'i-heroicons-bars-arrow-up-20-solid' : 'i-heroicons-bars-arrow-down-20-solid') : 'i-heroicons-arrows-up-down-20-solid',
class: '-mx-2.5',
onClick: () => column.toggleSorting(column.getIsSorted() === 'asc')
})
},
cell: ({ row }) => h('div', { class: 'lowercase' }, row.getValue('email'))
}, {
accessorKey: 'amount',
header: () => h('div', { class: 'text-right' }, 'Amount'),
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)
}
}, {
id: 'actions',
enableHiding: false,
cell: ({ row }) => {
const items = [{
type: 'label',
label: 'Actions'
}, {
label: 'Copy payment ID',
onSelect() {
navigator.clipboard.writeText(row.original.id)
toast.add({
title: 'Payment ID copied to clipboard!',
color: 'success',
icon: 'i-heroicons-check-circle'
})
}
}, {
label: row.getIsExpanded() ? 'Collapse' : 'Expand',
onSelect() {
row.toggleExpanded()
}
}, {
type: 'separator'
}, {
label: 'View customer'
}, {
label: 'View payment details'
}]
return h('div', { class: 'text-right' }, h(UDropdownMenu, {
content: {
align: 'end'
},
items
}, () => h(UButton, {
icon: 'i-heroicons-ellipsis-vertical-20-solid',
color: 'neutral',
variant: 'ghost',
class: 'ml-auto'
})))
}
}]
const table = useTemplateRef('table')
function randomize() {
data.value = [...data.value].sort(() => Math.random() - 0.5)
}
</script>
<template>
<div class="flex-1 divide-y divide-[var(--ui-border-accented)]">
<div class="flex items-center gap-2 px-4 py-3.5">
<UInput
:model-value="(table?.tableApi?.getColumn('email')?.getFilterValue() as string)"
class="max-w-sm"
placeholder="Filter emails..."
@update:model-value="table?.tableApi?.getColumn('email')?.setFilterValue($event)"
/>
<UButton color="neutral" label="Randomize" @click="randomize" />
<UDropdownMenu
:items="table?.tableApi?.getAllColumns().filter(column => column.getCanHide()).map(column => ({
label: upperFirst(column.id),
type: 'checkbox' as const,
checked: column.getIsVisible(),
onUpdateChecked(checked: boolean) {
table?.tableApi?.getColumn(column.id)?.toggleVisibility(!!checked)
},
onSelect(e?: Event) {
e?.preventDefault()
}
}))"
:content="{ align: 'end' }"
>
<UButton
label="Columns"
color="neutral"
variant="outline"
trailing-icon="i-heroicons-chevron-down-20-solid"
class="ml-auto"
/>
</UDropdownMenu>
</div>
<UTable
ref="table"
:data="data"
:columns="columns"
sticky
class="h-96"
>
<template #expanded="{ row }">
<pre>{{ row.original }}</pre>
</template>
</UTable>
<div class="px-4 py-3.5 text-sm text-[var(--ui-text-muted)]">
{{ table?.tableApi?.getFilteredSelectedRowModel().rows.length || 0 }} of
{{ table?.tableApi?.getFilteredRowModel().rows.length || 0 }} row(s) selected.
</div>
</div>
</template>

View File

@@ -0,0 +1,55 @@
<script setup lang="ts">
import type { TableColumn } from '@nuxt/ui'
const UAvatar = resolveComponent('UAvatar')
type User = {
id: number
name: string
username: string
email: string
avatar: { src: string }
company: { name: string }
}
const { data, status } = await useFetch<User[]>('https://jsonplaceholder.typicode.com/users', {
transform: (data) => {
return data?.map(user => ({
...user,
avatar: { src: `https://i.pravatar.cc/120?img=${user.id}` }
})) || []
},
lazy: true
})
const columns: TableColumn<User>[] = [{
accessorKey: 'id',
header: 'ID'
}, {
accessorKey: 'name',
header: 'Name',
cell: ({ row }) => {
return h('div', { class: 'flex items-center gap-3' }, [
h(UAvatar, {
...row.original.avatar,
size: 'lg'
}),
h('div', undefined, [
h('p', { class: 'font-medium text-[var(--ui-text-highlighted)]' }, row.original.name),
h('p', { class: '' }, `@${row.original.username}`)
])
])
}
}, {
accessorKey: 'email',
header: 'Email'
}, {
accessorKey: 'company',
header: 'Company',
cell: ({ row }) => row.original.company.name
}]
</script>
<template>
<UTable :data="data" :columns="columns" :loading="status === 'pending'" class="flex-1" />
</template>

View File

@@ -0,0 +1,115 @@
<script setup lang="ts">
import { h, resolveComponent } from 'vue'
import type { TableColumn } 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'),
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)
}
}]
const table = useTemplateRef('table')
const globalFilter = ref('45')
</script>
<template>
<div class="flex flex-col flex-1">
<div class="flex px-4 py-3.5 border-b border-[var(--ui-border-accented)]">
<UInput
v-model="globalFilter"
class="max-w-sm"
placeholder="Filter..."
/>
</div>
<UTable
ref="table"
v-model:global-filter="globalFilter"
:data="data"
:columns="columns"
/>
</div>
</template>

View File

@@ -0,0 +1,140 @@
<script setup lang="ts">
import { h, resolveComponent } from 'vue'
import type { TableColumn } from '@nuxt/ui'
import type { Row } from '@tanstack/vue-table'
const UButton = resolveComponent('UButton')
const UBadge = resolveComponent('UBadge')
const UDropdownMenu = resolveComponent('UDropdownMenu')
const toast = useToast()
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'),
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)
}
}, {
id: 'actions',
cell: ({ row }) => {
return h('div', { class: 'text-right' }, h(UDropdownMenu, {
content: {
align: 'end'
},
items: getRowItems(row)
}, () => h(UButton, {
icon: 'i-heroicons-ellipsis-vertical-20-solid',
color: 'neutral',
variant: 'ghost',
class: 'ml-auto'
})))
}
}]
function getRowItems(row: Row<Payment>) {
return [{
type: 'label',
label: 'Actions'
}, {
label: 'Copy payment ID',
onSelect() {
navigator.clipboard.writeText(row.original.id)
toast.add({
title: 'Payment ID copied to clipboard!',
color: 'success',
icon: 'i-heroicons-check-circle'
})
}
}, {
type: 'separator'
}, {
label: 'View customer'
}, {
label: 'View payment details'
}]
}
</script>
<template>
<UTable :data="data" :columns="columns" class="flex-1" />
</template>

View File

@@ -0,0 +1,121 @@
<script setup lang="ts">
import { h, resolveComponent } from 'vue'
import type { TableColumn } from '@nuxt/ui'
const UButton = resolveComponent('UButton')
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>[] = [{
id: 'expand',
cell: ({ row }) => h(UButton, {
color: 'neutral',
variant: 'ghost',
icon: 'i-heroicons-chevron-down-20-solid',
square: true,
ui: {
leadingIcon: ['transition-transform', row.getIsExpanded() ? 'duration-200 rotate-180' : '']
},
onClick: () => row.toggleExpanded()
})
}, {
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'),
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)
}
}]
const expanded = ref({ 1: true })
</script>
<template>
<UTable
v-model:expanded="expanded"
:data="data"
:columns="columns"
:ui="{ tr: 'data-[expanded=true]:bg-[var(--ui-bg-elevated)]/50' }"
class="flex-1"
>
<template #expanded="{ row }">
<pre>{{ row.original }}</pre>
</template>
</UTable>
</template>

View File

@@ -0,0 +1,122 @@
<script setup lang="ts">
import { h, resolveComponent } from 'vue'
import type { TableColumn } from '@nuxt/ui'
const UCheckbox = resolveComponent('UCheckbox')
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>[] = [{
id: 'select',
header: ({ table }) => h(UCheckbox, {
'modelValue': table.getIsAllPageRowsSelected(),
'indeterminate': table.getIsSomePageRowsSelected(),
'onUpdate:modelValue': (value: boolean) => table.toggleAllPageRowsSelected(!!value),
'ariaLabel': 'Select all'
}),
cell: ({ row }) => h(UCheckbox, {
'modelValue': row.getIsSelected(),
'onUpdate:modelValue': (value: boolean) => row.toggleSelected(!!value),
'ariaLabel': 'Select row'
})
}, {
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'),
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)
}
}]
const table = useTemplateRef('table')
const rowSelection = ref({ 1: true })
</script>
<template>
<div class="flex-1">
<UTable
ref="table"
v-model:row-selection="rowSelection"
:data="data"
:columns="columns"
/>
<div class="px-4 py-3.5 border-t border-[var(--ui-border-accented)] text-sm text-[var(--ui-text-muted)]">
{{ table?.tableApi?.getFilteredSelectedRowModel().rows.length || 0 }} of
{{ table?.tableApi?.getFilteredRowModel().rows.length || 0 }} row(s) selected.
</div>
</div>
</template>

View File

@@ -75,10 +75,24 @@ const communityLinks = computed(() => [{
<template>
<UPage v-if="page">
<UPageHeader :title="page.title" :links="page.links" :headline="headline">
<UPageHeader :title="page.title" :headline="headline">
<template #description>
<MDC v-if="page.description" :value="page.description" unwrap="p" />
</template>
<template #links>
<UButton
v-for="link in page.links"
:key="link.label"
color="neutral"
variant="outline"
v-bind="link"
>
<template v-if="link.avatar" #leading>
<UAvatar v-bind="link.avatar" size="2xs" />
</template>
</UButton>
</template>
</UPageHeader>
<UPageBody>

View File

@@ -251,10 +251,6 @@ This will give you access to the following:
| `emblaRef`{lang="ts-type"} | `Ref<HTMLElement \| null>`{lang="ts-type"} |
| `emblaApi`{lang="ts-type"} | [`Ref<EmblaCarouselType \| null>`{lang="ts-type"}](https://www.embla-carousel.com/api/methods/#typescript) |
::note{to="https://vuejs.org/api/composition-api-helpers.html#usetemplateref" target="_blank"}
You can use `useTemplateRef` to get the component instance.
::
## Theme
:component-theme

View File

@@ -1,21 +1,406 @@
---
description: A responsive table element to display data in rows and columns.
links:
- label: TanStack Table
avatar:
src: https://github.com/tanstack.png
to: https://tanstack.com/table/latest
- label: GitHub
icon: i-simple-icons-github
to: https://github.com/nuxt/ui/tree/v3/src/runtime/components/Table.vue
navigation:
badge:
label: Todo
color: neutral
disabled: true
---
## Usage
The Table component is built on top of [TanStack Table](https://tanstack.com/table/latest) and is powered by the [useVueTable](https://tanstack.com/table/latest/docs/framework/vue/vue-table#usevuetable) composable to provide a flexible and fully type-safe API.
::note
Some features of **TanStack Table** are not supported yet, we'll add more over time.
::
::component-example
---
source: false
name: 'table-example'
class: '!p-0'
---
::
::callout{icon="i-simple-icons-github" to="https://github.com/nuxt/ui/tree/v3/docs/app/components/content/examples/table/TableExample.vue"}
This example demonstrates the most common use case of the `Table` component. Check out the source code on GitHub.
::
### Data
Use the `data` prop as an array of objects, the columns will be generated based on the keys of the objects.
::component-code
---
collapse: true
class: '!p-0'
ignore:
- data
- class
external:
- data
props:
data:
- 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
class: 'flex-1'
---
::
### Columns
Use the `columns` prop as an array of [ColumnDef](https://tanstack.com/table/latest/docs/api/core/column-def) objects with properties like:
- `accessorKey`: [The key of the row object to use when extracting the value for the column.]{class="text-[var(--ui-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-[var(--ui-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-[var(--ui-text-muted)]"}
In order to render components or other HTML elements, you will need to use the Vue [`h` function](https://vuejs.org/api/render-function.html#h) inside the `header` and `cell` props. This is different from other components that use slots but allows for more flexibility.
::component-example
---
prettier: true
collapse: true
class: '!p-0'
name: 'table-columns-example'
highlights:
- 53
- 105
---
::
::tip
When rendering components with the `h` function, you can utilize the `resolveComponent` function to dynamically resolve and reference components.
::
### Loading
Use the `loading` prop to display a loading state, the `loading-color` prop to change its color and the `loading-animation` prop to change its animation.
::component-code
---
collapse: true
class: '!p-0'
ignore:
- data
- class
external:
- data
props:
loading: true
loadingColor: primary
loadingAnimation: carousel
data:
- 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
class: 'flex-1'
---
::
### Sticky
Use the `sticky` prop to make the header sticky.
::component-code
---
collapse: true
class: '!p-0'
ignore:
- data
- class
external:
- data
props:
sticky: true
data:
- 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
- id: '4595'
date: '2024-03-10T15:55:00'
status: 'paid'
email: 'ethan.harris@example.com'
amount: 639
- id: '4594'
date: '2024-03-10T15:55:00'
status: 'paid'
email: 'ethan.harris@example.com'
amount: 639
class: 'flex-1 max-h-[312px]'
---
::
## Examples
<!-- ## API
### With row actions
You can add a new column that renders a [DropdownMenu](/components/dropdown-menu) component inside the `cell` to render row actions.
::component-example
---
prettier: true
collapse: true
name: 'table-row-actions-example'
highlights:
- 110
- 134
class: '!p-0'
---
::
### With expandable rows
You can add a new column that renders a [Button](/components/button) component inside the `cell` to toggle the expandable state of a row using the TanStack Table [Expanding APIs](https://tanstack.com/table/latest/docs/api/features/expanding).
::caution
You need to define the `#expanded` slot to render the expanded content which will receive the row as a parameter.
::
::component-example
---
prettier: true
collapse: true
name: 'table-row-expandable-example'
highlights:
- 55
- 71
class: '!p-0'
---
::
::tip
You can use the `expanded` prop to control the expandable state of the rows (can be binded with `v-model`).
::
::note
You could also add this action to the [DropdownMenu](/components/dropdown-menu) component inside the `actions` column.
::
### With row selection
You can add a new column that renders a [Checkbox](/components/checkbox) component inside the `header` and `cell` to select rows using the TanStack Table [Row Selection APIs](https://tanstack.com/table/latest/docs/api/features/row-selection).
::component-example
---
prettier: true
collapse: true
name: 'table-row-selection-example'
highlights:
- 55
- 70
class: '!p-0'
---
::
::tip
You can use the `row-selection` prop to control the selection state of the rows (can be binded with `v-model`).
::
### 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).
::component-example
---
prettier: true
collapse: true
name: 'table-column-sorting-example'
highlights:
- 90
- 105
class: '!p-0'
---
::
::tip
You can use the `sorting` prop to control the sorting state of the columns (can be binded with `v-model`).
::
You can also create a reusable component to make any column header sortable.
::component-example
---
prettier: true
collapse: true
name: 'table-column-sorting-reusable-example'
highlights:
- 110
- 161
class: '!p-0'
---
::
::note
In this example, we use a function to define the column header but you can also create an actual component.
::
### With column pinning
You can update a column `header` to render a [Button](/components/button) component inside the `header` to toggle the pinning state using the TanStack Table [Pinning APIs](https://tanstack.com/table/latest/docs/api/features/row-pinning).
::note
A pinned column will become sticky on the left or right side of the table.
::
::component-example
---
prettier: true
collapse: true
name: 'table-column-pinning-example'
highlights:
- 100
- 113
class: '!p-0 overflow-clip'
---
::
::tip
You can use the `column-pinning` prop to control the pinning state of the columns (can be binded with `v-model`).
::
### With column visibility
You can add use [DropdownMenu](/components/dropdown-menu) component to toggle the visibility of the columns using the TanStack Table [Column Visibility APIs](https://tanstack.com/table/latest/docs/api/features/column-visibility).
::component-example
---
prettier: true
collapse: true
name: 'table-column-visibility-example'
highlights:
- 135
- 142
class: '!p-0'
---
::
::tip
You can use the `column-visibility` prop to control the visibility state of the columns (can be binded with `v-model`).
::
### With column filters
You can use an [Input](/components/input) component to filter per column the rows using the TanStack Table [Column Filtering APIs](https://tanstack.com/table/latest/docs/api/features/column-filtering).
::component-example
---
prettier: true
collapse: true
name: 'table-column-filters-example'
highlights:
- 135
- 142
class: '!p-0'
---
::
::tip
You can use the `column-filters` prop to control the filters state of the columns (can be binded with `v-model`).
::
### With global filter
You can use an [Input](/components/input) component to filter the rows using the TanStack Table [Global Filtering APIs](https://tanstack.com/table/latest/docs/api/features/global-filtering).
::component-example
---
prettier: true
collapse: true
name: 'table-global-filter-example'
class: '!p-0'
---
::
::tip
You can use the `global-filter` prop to control the global filter state (can be binded with `v-model`).
::
### With fetched data
You can fetch data from an API and use them in the Table.
::component-example
---
prettier: true
collapse: true
name: 'table-fetch-example'
class: '!p-0'
---
::
## API
### Props
@@ -25,10 +410,26 @@ navigation:
:component-slots
### Emits
### Expose
:component-emits
You can access the typed component instance using [`useTemplateRef`](https://vuejs.org/api/composition-api-helpers.html#usetemplateref).
```vue
<script setup lang="ts">
const table = useTemplateRef('table')
</script>
<template>
<UTable ref="table" />
</template>
```
This will give you access to the following:
| Name | Type |
| ---- | ---- |
| `tableApi`{lang="ts-type"} | [`Ref<Table \| null>`{lang="ts-type"}](https://tanstack.com/table/latest/docs/api/core/table#table-api) |
## Theme
:component-theme -->
:component-theme

View File

@@ -179,6 +179,7 @@ export default defineNuxtConfig({
'USlider',
'USlideover',
'USwitch',
'UTable',
'UTabs',
'UTextarea',
'UTooltip'

View File

@@ -9,7 +9,7 @@
"@nuxt/content": "^2.13.4",
"@nuxt/image": "^1.8.1",
"@nuxt/ui": "latest",
"@nuxt/ui-pro": "https://pkg.pr.new/@nuxt/ui-pro@041ca1f",
"@nuxt/ui-pro": "https://pkg.pr.new/@nuxt/ui-pro@5c9e5b4",
"@nuxthub/core": "^0.7.33",
"@nuxtjs/plausible": "^1.0.3",
"@octokit/rest": "^21.0.2",

View File

@@ -53,6 +53,7 @@
"@nuxtjs/color-mode": "^3.5.1",
"@tailwindcss/postcss": "4.0.0-alpha.28",
"@tailwindcss/vite": "4.0.0-alpha.28",
"@tanstack/vue-table": "^8.20.5",
"@vueuse/core": "^11.1.0",
"@vueuse/integrations": "^11.1.0",
"defu": "^6.1.4",

View File

@@ -42,6 +42,7 @@ const components = [
'slider',
'switch',
'tabs',
'table',
'textarea',
'toast',
'tooltip'

View File

@@ -0,0 +1,354 @@
<script setup lang="ts">
import { h, resolveComponent } from 'vue'
import { upperFirst } from 'scule'
import type { TableColumn } from '@nuxt/ui'
const UButton = resolveComponent('UButton')
const UCheckbox = resolveComponent('UCheckbox')
const UBadge = resolveComponent('UBadge')
const UDropdownMenu = resolveComponent('UDropdownMenu')
const toast = useToast()
type Payment = {
id: string
date: string
status: 'paid' | 'failed' | 'refunded'
email: string
amount: number
}
const table = useTemplateRef('table')
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
}, {
id: '4595',
date: '2024-03-10T13:40:00',
status: 'refunded',
email: 'ava.thomas@example.com',
amount: 428
}, {
id: '4594',
date: '2024-03-10T09:15:00',
status: 'paid',
email: 'michael.wilson@example.com',
amount: 683
}, {
id: '4593',
date: '2024-03-09T20:25:00',
status: 'failed',
email: 'olivia.taylor@example.com',
amount: 947
}, {
id: '4592',
date: '2024-03-09T18:45:00',
status: 'paid',
email: 'benjamin.jackson@example.com',
amount: 851
}, {
id: '4591',
date: '2024-03-09T16:05:00',
status: 'paid',
email: 'sophia.miller@example.com',
amount: 762
}, {
id: '4590',
date: '2024-03-09T14:20:00',
status: 'paid',
email: 'noah.clark@example.com',
amount: 573
}, {
id: '4589',
date: '2024-03-09T11:35:00',
status: 'failed',
email: 'isabella.lee@example.com',
amount: 389
}, {
id: '4588',
date: '2024-03-08T22:50:00',
status: 'refunded',
email: 'liam.walker@example.com',
amount: 701
}, {
id: '4587',
date: '2024-03-08T20:15:00',
status: 'paid',
email: 'charlotte.hall@example.com',
amount: 856
}, {
id: '4586',
date: '2024-03-08T17:40:00',
status: 'paid',
email: 'mason.young@example.com',
amount: 492
}, {
id: '4585',
date: '2024-03-08T14:55:00',
status: 'failed',
email: 'amelia.king@example.com',
amount: 637
}, {
id: '4584',
date: '2024-03-08T12:30:00',
status: 'paid',
email: 'elijah.wright@example.com',
amount: 784
}, {
id: '4583',
date: '2024-03-08T09:45:00',
status: 'refunded',
email: 'harper.scott@example.com',
amount: 345
}, {
id: '4582',
date: '2024-03-07T23:10:00',
status: 'paid',
email: 'evelyn.green@example.com',
amount: 918
}, {
id: '4581',
date: '2024-03-07T20:25:00',
status: 'paid',
email: 'logan.baker@example.com',
amount: 567
}])
const columns: TableColumn<Payment>[] = [{
id: 'select',
header: ({ table }) => h(UCheckbox, {
'modelValue': table.getIsAllPageRowsSelected(),
'indeterminate': table.getIsSomePageRowsSelected(),
'onUpdate:modelValue': (value: boolean) => table.toggleAllPageRowsSelected(!!value),
'ariaLabel': 'Select all'
}),
cell: ({ row }) => h(UCheckbox, {
'modelValue': row.getIsSelected(),
'onUpdate:modelValue': (value: boolean) => row.toggleSelected(!!value),
'ariaLabel': 'Select row'
}),
enableSorting: false,
enableHiding: false
}, {
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: ({ column }) => {
const isSorted = column.getIsSorted()
return h(UButton, {
color: 'neutral',
variant: 'ghost',
label: 'Email',
icon: isSorted ? (isSorted === 'asc' ? 'i-heroicons-bars-arrow-up-20-solid' : 'i-heroicons-bars-arrow-down-20-solid') : 'i-heroicons-arrows-up-down-20-solid',
class: '-mx-2.5',
onClick: () => column.toggleSorting(column.getIsSorted() === 'asc')
})
},
cell: ({ row }) => h('div', { class: 'lowercase' }, row.getValue('email'))
}, {
accessorKey: 'amount',
header: () => h('div', { class: 'text-right' }, 'Amount'),
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)
}
}, {
id: 'actions',
enableHiding: false,
cell: ({ row }) => {
const items = [{
type: 'label',
label: 'Actions'
}, {
label: 'Copy payment ID',
onSelect() {
navigator.clipboard.writeText(row.original.id)
toast.add({
title: 'Payment ID copied to clipboard!',
color: 'success',
icon: 'i-heroicons-check-circle'
})
}
}, {
label: row.getIsExpanded() ? 'Collapse' : 'Expand',
onSelect() {
row.toggleExpanded()
}
}, {
type: 'separator'
}, {
label: 'View customer'
}, {
label: 'View payment details'
}]
return h('div', { class: 'text-right' }, h(UDropdownMenu, {
content: {
align: 'end'
},
items
}, () => h(UButton, {
icon: 'i-heroicons-ellipsis-vertical-20-solid',
color: 'neutral',
variant: 'ghost',
class: 'ml-auto'
})))
}
}]
const loading = ref(true)
const columnPinning = ref({
left: ['id'],
right: ['actions']
})
function randomize() {
data.value = [...data.value].sort(() => Math.random() - 0.5)
}
onMounted(() => {
setTimeout(() => {
loading.value = false
}, 1300)
})
</script>
<template>
<div class="h-full flex flex-col flex-1 gap-4 w-full -my-8">
<div class="flex gap-2 items-center">
<UInput
:model-value="(table?.tableApi?.getColumn('email')?.getFilterValue() as string)"
class="max-w-sm"
placeholder="Filter emails..."
@update:model-value="table?.tableApi?.getColumn('email')?.setFilterValue($event)"
/>
<UButton color="neutral" label="Randomize" @click="randomize" />
<UDropdownMenu
:items="table?.tableApi?.getAllColumns().filter(column => column.getCanHide()).map(column => ({
label: upperFirst(column.id),
type: 'checkbox' as const,
checked: column.getIsVisible(),
onUpdateChecked(checked: boolean) {
table?.tableApi?.getColumn(column.id)?.toggleVisibility(!!checked)
},
onSelect(e?: Event) {
e?.preventDefault()
}
}))"
:content="{ align: 'end' }"
>
<UButton
label="Columns"
color="neutral"
variant="outline"
trailing-icon="i-heroicons-chevron-down-20-solid"
class="ml-auto"
/>
</UDropdownMenu>
</div>
<UTable
ref="table"
:data="data"
:columns="columns"
:column-pinning="columnPinning"
:loading="loading"
sticky
class="border border-[var(--ui-border-accented)] rounded-[var(--ui-radius)] flex-1"
>
<template #expanded="{ row }">
<pre>{{ row.original }}</pre>
</template>
</UTable>
<div class="flex items-center justify-between gap-3">
<div class="text-sm text-[var(--ui-text-muted)]">
{{ table?.tableApi?.getFilteredSelectedRowModel().rows.length || 0 }} of
{{ table?.tableApi?.getFilteredRowModel().rows.length || 0 }} row(s) selected.
</div>
<!-- <div class="flex items-center gap-1.5">
<UButton
color="neutral"
variant="outline"
:disabled="!table?.tableApi?.getCanPreviousPage()"
@click="table?.tableApi?.previousPage()"
>
Prev
</UButton>
<UButton
color="neutral"
variant="outline"
:disabled="!table?.tableApi?.getCanNextPage()"
@click="table?.tableApi?.nextPage()"
>
Next
</UButton>
</div> -->
</div>
</div>
</template>

32
pnpm-lock.yaml generated
View File

@@ -34,6 +34,9 @@ importers:
'@tailwindcss/vite':
specifier: 4.0.0-alpha.28
version: 4.0.0-alpha.28(vite@5.4.9(@types/node@22.7.7)(lightningcss@1.27.0)(terser@5.36.0))
'@tanstack/vue-table':
specifier: ^8.20.5
version: 8.20.5(vue@3.5.12(typescript@5.6.3))
'@vueuse/core':
specifier: ^11.1.0
version: 11.1.0(vue@3.5.12(typescript@5.6.3))
@@ -183,8 +186,8 @@ importers:
specifier: workspace:*
version: link:..
'@nuxt/ui-pro':
specifier: https://pkg.pr.new/@nuxt/ui-pro@041ca1f
version: https://pkg.pr.new/@nuxt/ui-pro@041ca1f(magicast@0.3.5)(rollup@4.24.0)(typescript@5.6.3)(vue@3.5.12(typescript@5.6.3))
specifier: https://pkg.pr.new/@nuxt/ui-pro@5c9e5b4
version: https://pkg.pr.new/@nuxt/ui-pro@5c9e5b4(magicast@0.3.5)(rollup@4.24.0)(typescript@5.6.3)(vue@3.5.12(typescript@5.6.3))
'@nuxthub/core':
specifier: ^0.7.33
version: 0.7.34(ioredis@5.4.1)(magicast@0.3.5)(rollup@4.24.0)(vite@5.4.9(@types/node@22.7.7)(lightningcss@1.27.0)(terser@5.36.0))
@@ -1613,9 +1616,9 @@ packages:
vitest:
optional: true
'@nuxt/ui-pro@https://pkg.pr.new/@nuxt/ui-pro@041ca1f':
resolution: {tarball: https://pkg.pr.new/@nuxt/ui-pro@041ca1f}
version: 2.0.0-alpha.6
'@nuxt/ui-pro@https://pkg.pr.new/@nuxt/ui-pro@5c9e5b4':
resolution: {tarball: https://pkg.pr.new/@nuxt/ui-pro@5c9e5b4}
version: 3.0.0-alpha.6
peerDependencies:
typescript: ^5.6.3
@@ -2222,9 +2225,19 @@ packages:
peerDependencies:
vite: ^5.2.0
'@tanstack/table-core@8.20.5':
resolution: {integrity: sha512-P9dF7XbibHph2PFRz8gfBKEXEY/HJPOhym8CHmjF8y3q5mWpKx9xtZapXQUWCgkqvsK0R46Azuz+VaxD4Xl+Tg==}
engines: {node: '>=12'}
'@tanstack/virtual-core@3.10.8':
resolution: {integrity: sha512-PBu00mtt95jbKFi6Llk9aik8bnR3tR/oQP1o3TSi+iG//+Q2RTIzCEgKkHG8BB86kxMNW6O8wku+Lmi+QFR6jA==}
'@tanstack/vue-table@8.20.5':
resolution: {integrity: sha512-2xixT3BEgSDw+jOSqPt6ylO/eutDI107t2WdFMVYIZZ45UmTHLySqNriNs0+dMaKR56K5z3t+97P6VuVnI2L+Q==}
engines: {node: '>=12'}
peerDependencies:
vue: '>=3.2'
'@tanstack/vue-virtual@3.10.8':
resolution: {integrity: sha512-DB5QA8c/LfqOqIUCpSs3RdOTVroRRdqeHMqBkYrcashSZtOzIv8xbiqHgg7RYxDfkH5F3Y+e0MkuuyGNDVB0BQ==}
peerDependencies:
@@ -8344,7 +8357,7 @@ snapshots:
- supports-color
- webpack-sources
'@nuxt/ui-pro@https://pkg.pr.new/@nuxt/ui-pro@041ca1f(magicast@0.3.5)(rollup@4.24.0)(typescript@5.6.3)(vue@3.5.12(typescript@5.6.3))':
'@nuxt/ui-pro@https://pkg.pr.new/@nuxt/ui-pro@5c9e5b4(magicast@0.3.5)(rollup@4.24.0)(typescript@5.6.3)(vue@3.5.12(typescript@5.6.3))':
dependencies:
'@nuxt/kit': 3.13.2(magicast@0.3.5)(rollup@4.24.0)
'@nuxt/schema': 3.13.2(rollup@4.24.0)
@@ -9050,8 +9063,15 @@ snapshots:
tailwindcss: 4.0.0-alpha.28
vite: 5.4.9(@types/node@22.7.7)(lightningcss@1.27.0)(terser@5.36.0)
'@tanstack/table-core@8.20.5': {}
'@tanstack/virtual-core@3.10.8': {}
'@tanstack/vue-table@8.20.5(vue@3.5.12(typescript@5.6.3))':
dependencies:
'@tanstack/table-core': 8.20.5
vue: 3.5.12(typescript@5.6.3)
'@tanstack/vue-virtual@3.10.8(vue@3.5.12(typescript@5.6.3))':
dependencies:
'@tanstack/virtual-core': 3.10.8

View File

@@ -10,40 +10,40 @@ export interface ModuleOptions {
/**
* Prefix for components
* @defaultValue `U`
* @see https://ui3.nuxt.dev/getting-started/installation#prefix
* @link https://ui3.nuxt.dev/getting-started/installation#prefix
*/
prefix?: string
/**
* Enable or disable `@nuxt/fonts` module
* @defaultValue `true`
* @see https://ui3.nuxt.dev/getting-started/installation#fonts
* @link https://ui3.nuxt.dev/getting-started/installation#fonts
*/
fonts?: boolean
/**
* Enable or disable `@nuxtjs/color-mode` module
* @defaultValue `true`
* @see https://ui3.nuxt.dev/getting-started/installation#colormode
* @link https://ui3.nuxt.dev/getting-started/installation#colormode
*/
colorMode?: boolean
/**
* Customize how the theme is generated
* @see https://ui3.nuxt.dev/getting-started/theme
* @link https://ui3.nuxt.dev/getting-started/theme
*/
theme?: {
/**
* Define the color aliases available for components
* @defaultValue `['primary', 'secondary', 'success', 'info', 'warning', 'error']`
* @see https://ui3.nuxt.dev/getting-started/installation#themecolors
* @link https://ui3.nuxt.dev/getting-started/installation#themecolors
*/
colors?: string[]
/**
* Enable or disable transitions on components
* @defaultValue `true`
* @see https://ui3.nuxt.dev/getting-started/installation#themetransitions
* @link https://ui3.nuxt.dev/getting-started/installation#themetransitions
*/
transitions?: boolean
}

View File

@@ -55,32 +55,32 @@ export interface CarouselProps<T> extends Omit<EmblaOptionsType, 'axis' | 'conta
items?: T[]
/**
* Enable Autoplay plugin
* @see https://www.embla-carousel.com/plugins/autoplay/
* @link https://www.embla-carousel.com/plugins/autoplay/
*/
autoplay?: boolean | AutoplayOptionsType
/**
* Enable Auto Scroll plugin
* @see https://www.embla-carousel.com/plugins/auto-scroll/
* @link https://www.embla-carousel.com/plugins/auto-scroll/
*/
autoScroll?: boolean | AutoScrollOptionsType
/**
* Enable Auto Height plugin
* @see https://www.embla-carousel.com/plugins/auto-height/
* @link https://www.embla-carousel.com/plugins/auto-height/
*/
autoHeight?: boolean | AutoHeightOptionsType
/**
* Enable Class Names plugin
* @see https://www.embla-carousel.com/plugins/class-names/
* @link https://www.embla-carousel.com/plugins/class-names/
*/
classNames?: boolean | ClassNamesOptionsType
/**
* Enable Fade plugin
* @see https://www.embla-carousel.com/plugins/fade/
* @link https://www.embla-carousel.com/plugins/fade/
*/
fade?: boolean | FadeOptionsType
/**
* Enable Wheel Gestures plugin
* @see https://www.embla-carousel.com/plugins/wheel-gestures/
* @link https://www.embla-carousel.com/plugins/wheel-gestures/
*/
wheelGestures?: boolean | WheelGesturesPluginOptions
class?: any

View File

@@ -0,0 +1,232 @@
<!-- eslint-disable vue/block-tag-newline -->
<script lang="ts">
import type { Ref } from 'vue'
import { tv, type VariantProps } from 'tailwind-variants'
import type { AppConfig } from '@nuxt/schema'
import type {
Row,
ColumnDef,
ColumnFiltersState,
ColumnPinningState,
RowSelectionState,
SortingState,
ExpandedState,
VisibilityState,
GlobalFilterOptions,
ColumnFiltersOptions,
ColumnPinningOptions,
VisibilityOptions,
ExpandedOptions,
SortingOptions,
RowSelectionOptions,
Updater
} from '@tanstack/vue-table'
import _appConfig from '#build/app.config'
import theme from '#build/ui/table'
const appConfig = _appConfig as AppConfig & { ui: { table: Partial<typeof theme> } }
const table = tv({ extend: tv(theme), ...(appConfig.ui?.table || {}) })
type TableVariants = VariantProps<typeof table>
export type TableColumn<T> = ColumnDef<T>
export interface TableData {
[key: string]: any
}
export interface TableProps<T> {
data?: T[]
columns?: TableColumn<T>[]
/**
* Whether the table should have a sticky header.
* @defaultValue false
*/
sticky?: boolean
/** Whether the table should be in loading state. */
loading?: boolean
loadingColor?: TableVariants['loadingColor']
loadingAnimation?: TableVariants['loadingAnimation']
/**
* @link [API Docs](https://tanstack.com/table/v8/docs/api/features/global-filtering#table-options)
* @link [Guide](https://tanstack.com/table/v8/docs/guide/global-filtering)
*/
globalFilterOptions?: Omit<GlobalFilterOptions<T>, 'onGlobalFilterChange'>
/**
* @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-filtering#table-options)
* @link [Guide](https://tanstack.com/table/v8/docs/guide/column-filtering)
*/
columnFiltersOptions?: Omit<ColumnFiltersOptions<T>, 'getFilteredRowModel' | 'onColumnFiltersChange'>
/**
* @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-pinning#table-options)
* @link [Guide](https://tanstack.com/table/v8/docs/guide/column-pinning)
*/
columnPinningOptions?: Omit<ColumnPinningOptions, 'onColumnPinningChange'>
/**
* @link [API Docs](https://tanstack.com/table/v8/docs/api/features/column-visibility#table-options)
* @link [Guide](https://tanstack.com/table/v8/docs/guide/column-visibility)
*/
visibilityOptions?: Omit<VisibilityOptions, 'onColumnVisibilityChange'>
/**
* @link [API Docs](https://tanstack.com/table/v8/docs/api/features/sorting#table-options)
* @link [Guide](https://tanstack.com/table/v8/docs/guide/sorting)
*/
sortingOptions?: Omit<SortingOptions<T>, 'getSortedRowModel' | 'onSortingChange'>
/**
* @link [API Docs](https://tanstack.com/table/v8/docs/api/features/expanding#table-options)
* @link [Guide](https://tanstack.com/table/v8/docs/guide/expanding)
*/
expandedOptions?: Omit<ExpandedOptions<T>, 'getExpandedRowModel' | 'onExpandedChange'>
/**
* @link [API Docs](https://tanstack.com/table/v8/docs/api/features/row-selection#table-options)
* @link [Guide](https://tanstack.com/table/v8/docs/guide/row-selection)
*/
rowSelectionOptions?: Omit<RowSelectionOptions<T>, 'onRowSelectionChange'>
class?: any
ui?: Partial<typeof table.slots>
}
export interface TableSlots<T> {
expanded(props: { row: Row<T> }): any
empty(props?: {}): any
}
</script>
<script setup lang="ts" generic="T extends TableData">
import { computed } from 'vue'
import {
FlexRender,
getCoreRowModel,
getFilteredRowModel,
getSortedRowModel,
getExpandedRowModel,
useVueTable
} from '@tanstack/vue-table'
import { upperFirst } from 'scule'
const props = defineProps<TableProps<T>>()
defineSlots<TableSlots<T>>()
const data = computed(() => props.data ?? [])
const columns = computed<TableColumn<T>[]>(() => props.columns ?? Object.keys(data.value[0] ?? {}).map((accessorKey: string) => ({ accessorKey, header: upperFirst(accessorKey) })))
const ui = computed(() => table({
sticky: props.sticky,
loading: props.loading,
loadingColor: props.loadingColor,
loadingAnimation: props.loadingAnimation
}))
const globalFilterState = defineModel<string>('globalFilter', { default: undefined })
const columnFiltersState = defineModel<ColumnFiltersState>('columnFilters', { default: [] })
const columnVisibilityState = defineModel<VisibilityState>('columnVisibility', { default: {} })
const columnPinningState = defineModel<ColumnPinningState>('columnPinning', { default: {} })
const rowSelectionState = defineModel<RowSelectionState>('rowSelection', { default: {} })
const sortingState = defineModel<SortingState>('sorting', { default: [] })
const expandedState = defineModel<ExpandedState>('expanded', { default: {} })
const tableApi = useVueTable({
data,
columns: columns.value,
getCoreRowModel: getCoreRowModel(),
...(props.globalFilterOptions || {}),
onGlobalFilterChange: updaterOrValue => valueUpdater(updaterOrValue, globalFilterState),
...(props.columnFiltersOptions || {}),
getFilteredRowModel: getFilteredRowModel(),
onColumnFiltersChange: updaterOrValue => valueUpdater(updaterOrValue, columnFiltersState),
...(props.visibilityOptions || {}),
onColumnVisibilityChange: updaterOrValue => valueUpdater(updaterOrValue, columnVisibilityState),
...(props.columnPinningOptions || {}),
onColumnPinningChange: updaterOrValue => valueUpdater(updaterOrValue, columnPinningState),
...(props.rowSelectionOptions || {}),
onRowSelectionChange: updaterOrValue => valueUpdater(updaterOrValue, rowSelectionState),
...(props.sortingOptions || {}),
getSortedRowModel: getSortedRowModel(),
onSortingChange: updaterOrValue => valueUpdater(updaterOrValue, sortingState),
...(props.expandedOptions || {}),
getExpandedRowModel: getExpandedRowModel(),
onExpandedChange: updaterOrValue => valueUpdater(updaterOrValue, expandedState),
state: {
get globalFilter() {
return globalFilterState.value
},
get columnFilters() {
return columnFiltersState.value
},
get columnVisibility() {
return columnVisibilityState.value
},
get columnPinning() {
return columnPinningState.value
},
get expanded() {
return expandedState.value
},
get rowSelection() {
return rowSelectionState.value
},
get sorting() {
return sortingState.value
}
}
})
function valueUpdater<T extends Updater<any>>(updaterOrValue: T, ref: Ref) {
ref.value = typeof updaterOrValue === 'function' ? updaterOrValue(ref.value) : updaterOrValue
}
defineExpose({
tableApi
})
</script>
<template>
<div :class="ui.root({ class: [props.class, props.ui?.root] })">
<table :class="ui.base({ class: [props.ui?.base] })">
<thead :class="ui.thead({ class: [props.ui?.thead] })">
<tr v-for="headerGroup in tableApi.getHeaderGroups()" :key="headerGroup.id" :class="ui.tr({ class: [props.ui?.tr] })">
<th
v-for="header in headerGroup.headers"
:key="header.id"
:data-pinned="header.column.getIsPinned()"
:class="ui.th({ class: [props.ui?.th], pinned: !!header.column.getIsPinned() })"
>
<FlexRender v-if="!header.isPlaceholder" :render="header.column.columnDef.header" :props="header.getContext()" />
</th>
</tr>
</thead>
<tbody :class="ui.tbody({ class: [props.ui?.tbody] })">
<template v-if="tableApi.getRowModel().rows?.length">
<template v-for="row in tableApi.getRowModel().rows" :key="row.id">
<tr :data-selected="row.getIsSelected()" :data-expanded="row.getIsExpanded()" :class="ui.tr({ class: [props.ui?.tr] })">
<td
v-for="cell in row.getVisibleCells()"
:key="cell.id"
:data-pinned="cell.column.getIsPinned()"
:class="ui.td({ class: [props.ui?.td], pinned: !!cell.column.getIsPinned() })"
>
<FlexRender :render="cell.column.columnDef.cell" :props="cell.getContext()" />
</td>
</tr>
<tr v-if="row.getIsExpanded()" :class="ui.tr({ class: [props.ui?.tr] })">
<td :colspan="row.getAllCells().length" :class="ui.td({ class: [props.ui?.td] })">
<slot name="expanded" :row="row" />
</td>
</tr>
</template>
</template>
<tr v-else :class="ui.tr({ class: [props.ui?.tr] })">
<td :colspan="columns?.length" :class="ui.empty({ class: props.ui?.empty })">
<slot name="empty">
No results
</slot>
</td>
</tr>
</tbody>
</table>
</div>
</template>

View File

@@ -1,8 +1,8 @@
import { ref, inject } from 'vue'
import type { ShallowRef, Component, InjectionKey } from 'vue'
import type { ComponentProps } from 'vue-component-type-helpers'
import { createSharedComposable } from '@vueuse/core'
import type { ModalProps } from '../types'
import type { ComponentProps } from '../types/component'
export interface ModalState {
component: Component | string

View File

@@ -1,8 +1,8 @@
import { ref, inject } from 'vue'
import type { ShallowRef, Component, InjectionKey } from 'vue'
import type { ComponentProps } from 'vue-component-type-helpers'
import { createSharedComposable } from '@vueuse/core'
import type { SlideoverProps } from '../types'
import type { ComponentProps } from '../types/component'
export interface SlideoverState {
component: Component | string

View File

@@ -1,14 +0,0 @@
export type ComponentProps<T> =
T extends new () => { $props: infer P } ? NonNullable<P> :
T extends (props: infer P, ...args: any) => any ? P :
Record<string, never>
export type ComponentSlots<T> =
T extends new () => { $slots: infer S } ? NonNullable<S> :
T extends (props: any, ctx: { slots: infer S, attrs: any, emit: any }, ...args: any) => any ? NonNullable<S> :
Record<string, never>
export type ComponentEmit<T> =
T extends new () => { $emit: infer E } ? NonNullable<E> :
T extends (props: any, ctx: { slots: any, attrs: any, emit: infer E }, ...args: any) => any ? NonNullable<E> :
Record<string, never>

View File

@@ -35,6 +35,7 @@ export * from '../components/Skeleton.vue'
export * from '../components/Slideover.vue'
export * from '../components/Slider.vue'
export * from '../components/Switch.vue'
export * from '../components/Table.vue'
export * from '../components/Tabs.vue'
export * from '../components/Textarea.vue'
export * from '../components/Toast.vue'

View File

@@ -8,7 +8,7 @@ export default (options: Required<ModuleOptions>) => ({
content: 'relative overflow-hidden',
viewport: 'divide-y divide-[var(--ui-border)] scroll-py-1',
group: 'p-1 isolate',
empty: 'py-6 text-center text-sm',
empty: 'py-6 text-center text-sm text-[var(--ui-text-muted)]',
label: 'px-2 py-1.5 text-xs font-semibold text-[var(--ui-text-highlighted)]',
item: ['group relative w-full flex items-center gap-2 px-2 py-1.5 text-sm select-none outline-none before:absolute before:z-[-1] before:inset-px before:rounded-[calc(var(--ui-radius)*1.5)] data-disabled:cursor-not-allowed data-disabled:opacity-75 text-[var(--ui-text)] data-highlighted:text-[var(--ui-text-highlighted)] data-highlighted:before:bg-[var(--ui-bg-elevated)]/50', options.theme.transitions && 'transition-colors before:transition-colors'],
itemLeadingIcon: ['shrink-0 size-5 text-[var(--ui-text-dimmed)] group-data-highlighted:text-[var(--ui-text)]', options.theme.transitions && 'transition-colors'],

View File

@@ -35,6 +35,7 @@ export { default as skeleton } from './skeleton'
export { default as slideover } from './slideover'
export { default as slider } from './slider'
export { default as switch } from './switch'
export { default as table } from './table'
export { default as tabs } from './tabs'
export { default as textarea } from './textarea'
export { default as toast } from './toast'

83
src/theme/table.ts Normal file
View File

@@ -0,0 +1,83 @@
import type { ModuleOptions } from '../module'
export default (options: Required<ModuleOptions>) => ({
slots: {
root: 'relative overflow-auto',
base: 'min-w-full overflow-clip',
thead: 'relative [&>tr]:after:absolute [&>tr]:after:inset-x-0 [&>tr]:after:bottom-0 [&>tr]:after:h-px [&>tr]:after:bg-[var(--ui-border-accented)]',
tbody: 'divide-y divide-[var(--ui-border)]',
tr: 'data-[selected=true]:bg-[var(--ui-bg-elevated)]/50',
th: 'px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0',
td: 'p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0',
empty: 'py-6 text-center text-sm text-[var(--ui-text-muted)]'
},
variants: {
pinned: {
true: {
th: 'sticky bg-[var(--ui-bg)]/75 data-[pinned=left]:left-0 data-[pinned=right]:right-0',
td: 'sticky bg-[var(--ui-bg)]/75 data-[pinned=left]:left-0 data-[pinned=right]:right-0'
}
},
sticky: {
true: {
thead: 'sticky top-0 inset-x-0 bg-[var(--ui-bg)]/75 z-[1] backdrop-blur'
}
},
loading: {
true: {
thead: 'after:absolute after:bottom-0 after:inset-x-0 after:h-px'
}
},
loadingAnimation: {
'carousel': '',
'carousel-inverse': '',
'swing': '',
'elastic': ''
},
loadingColor: {
...Object.fromEntries((options.theme.colors || []).map((color: string) => [color, ''])),
neutral: ''
}
},
compoundVariants: [...(options.theme.colors || []).map((loadingColor: string) => ({
loading: true,
loadingColor,
class: {
thead: `after:bg-[var(--ui-${loadingColor})]`
}
})), {
loading: true,
loadingColor: 'neutral',
class: {
thead: 'after:bg-[var(--ui-bg-inverted)]'
}
}, {
loading: true,
loadingAnimation: 'carousel',
class: {
thead: 'after:animate-[carousel_2s_ease-in-out_infinite]'
}
}, {
loading: true,
loadingAnimation: 'carousel-inverse',
class: {
thead: 'after:animate-[carousel-inverse_2s_ease-in-out_infinite]'
}
}, {
loading: true,
loadingAnimation: 'swing',
class: {
thead: 'after:animate-[swing_2s_ease-in-out_infinite]'
}
}, {
loading: true,
loadingAnimation: 'elastic',
class: {
thead: 'after:animate-[elastic_2s_ease-in-out_infinite]'
}
}],
defaultVariants: {
loadingColor: 'primary',
loadingAnimation: 'carousel'
}
})

View File

@@ -62,6 +62,7 @@ describe('CommandPalette', () => {
it.each([
// Props
['with groups', { props }],
['without results', {}],
['with modelValue', { props: { ...props, modelValue: groups[2].items[0] } }],
['with defaultValue', { props: { ...props, defaultValue: groups[2].items[0] } }],
['with labelKey', { props: { ...props, labelKey: 'icon' } }],
@@ -69,7 +70,7 @@ describe('CommandPalette', () => {
['with disabled', { props: { ...props, disabled: true } }],
['with icon', { props: { ...props, icon: 'i-heroicons-command-line' } }],
['with loading', { props: { ...props, loading: true } }],
['with loadingIcon', { props: { loading: true, loadingIcon: 'i-heroicons-sparkles' } }],
['with loadingIcon', { props: { ...props, loading: true, loadingIcon: 'i-heroicons-sparkles' } }],
['with selectedIcon', { props: { ...props, selectedIcon: 'i-heroicons-check-badge', modelValue: groups[2].items[0] } }],
['with close', { props: { ...props, close: true } }],
['with closeIcon', { props: { ...props, close: true, closeIcon: 'i-heroicons-trash' } }],

View File

@@ -0,0 +1,164 @@
import { h, resolveComponent } from 'vue'
import { describe, it, expect } from 'vitest'
import Table, { type TableProps, type TableSlots, type TableColumn } from '../../src/runtime/components/Table.vue'
import ComponentRender from '../component-render'
import theme from '#build/ui/table'
describe('Table', () => {
const loadingColors = Object.keys(theme.variants.loadingColor) as any
const loadingAnimations = Object.keys(theme.variants.loadingAnimation) as any
const UButton = resolveComponent('UButton')
const UCheckbox = resolveComponent('UCheckbox')
const UBadge = resolveComponent('UBadge')
const UDropdownMenu = resolveComponent('UDropdownMenu')
const data = [{
id: 'm5gr84i9',
amount: 316,
status: 'success',
email: 'ken99@yahoo.com'
}, {
id: '3u1reuv4',
amount: 242,
status: 'success',
email: 'Abe45@gmail.com'
}, {
id: 'derv1ws0',
amount: 837,
status: 'processing',
email: 'Monserrat44@gmail.com'
}, {
id: '5kma53ae',
amount: 874,
status: 'success',
email: 'Silas22@gmail.com'
}, {
id: 'bhqecj4p',
amount: 721,
status: 'failed',
email: 'carmella@hotmail.com'
}]
const columns: TableColumn<typeof data[number]>[] = [{
id: 'select',
header: ({ table }) => h(UCheckbox, {
'modelValue': table.getIsAllPageRowsSelected(),
'indeterminate': table.getIsSomePageRowsSelected(),
'onUpdate:modelValue': (value: boolean) => table.toggleAllPageRowsSelected(!!value),
'ariaLabel': 'Select all'
}),
cell: ({ row }) => h(UCheckbox, {
'modelValue': row.getIsSelected(),
'onUpdate:modelValue': (value: boolean) => row.toggleSelected(!!value),
'ariaLabel': 'Select row'
}),
enableSorting: false,
enableHiding: false
}, {
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: ({ column }) => {
const isSorted = column.getIsSorted()
return h(UButton, {
color: 'neutral',
variant: 'ghost',
label: 'Email',
icon: isSorted ? (isSorted === 'asc' ? 'i-heroicons-bars-arrow-up-20-solid' : 'i-heroicons-bars-arrow-down-20-solid') : 'i-heroicons-arrows-up-down-20-solid',
class: '-mx-2.5',
onClick: () => column.toggleSorting(column.getIsSorted() === 'asc')
})
},
cell: ({ row }) => h('div', { class: 'lowercase' }, row.getValue('email'))
}, {
accessorKey: 'amount',
header: () => h('div', { class: 'text-right' }, 'Amount'),
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)
}
}, {
id: 'actions',
enableHiding: false,
cell: ({ row }) => {
const items = [{
type: 'label',
label: 'Actions'
}, {
label: 'Copy payment ID'
}, {
label: row.getIsExpanded() ? 'Collapse' : 'Expand'
}, {
type: 'separator'
}, {
label: 'View customer'
}, {
label: 'View payment details'
}]
return h('div', { class: 'text-right' }, h(UDropdownMenu, {
content: {
align: 'end'
},
items
}, () => h(UButton, {
icon: 'i-heroicons-ellipsis-vertical-20-solid',
color: 'neutral',
variant: 'ghost',
class: 'ml-auto'
})))
}
}]
const props = { data }
it.each([
// Props
['with data', { props }],
['without results', {}],
['with columns', { props: { ...props, columns } }],
['with sticky', { props: { ...props, sticky: true } }],
['with loading', { props: { ...props, loading: true } }],
...loadingColors.map((loadingColor: string) => [`with loading color ${loadingColor}`, { props: { ...props, loading: true, loadingColor } }]),
...loadingAnimations.map((loadingAnimation: string) => [`with loading animation ${loadingAnimation}`, { props: { ...props, loading: true, loadingAnimation } }]),
['with class', { props: { ...props, class: 'absolute' } }],
['with ui', { props: { ...props, ui: { base: 'table-auto' } } }]
])('renders %s correctly', async (nameOrHtml: string, options: { props?: TableProps<typeof data[number]>, slots?: Partial<TableSlots<typeof data[number]>> }) => {
const html = await ComponentRender(nameOrHtml, options, Table)
expect(html).toMatchSnapshot()
})
})

View File

@@ -984,13 +984,45 @@ exports[`CommandPalette > renders with loading correctly 1`] = `
exports[`CommandPalette > renders with loadingIcon correctly 1`] = `
"<div style="pointer-events: auto;" dir="ltr" class="flex flex-col min-h-0 min-w-0 divide-y divide-[var(--ui-border)]">
<div class="relative inline-flex items-center [&>input]:h-12"><input type="text" placeholder="Type a command or search..." class="w-full rounded-[calc(var(--ui-radius)*1.5)] border-0 placeholder:text-[var(--ui-text-dimmed)] focus:outline-none disabled:cursor-not-allowed disabled:opacity-75 transition-colors px-3 py-2 text-sm gap-2 text-[var(--ui-text-highlighted)] pl-10" autocomplete="false" aria-expanded="true" aria-controls="" aria-disabled="false" aria-autocomplete="list" role="combobox" value=""><span class="absolute inset-y-0 start-0 flex items-center pl-3"><span class="iconify i-heroicons:sparkles shrink-0 text-[var(--ui-text-dimmed)] size-5 animate-spin" aria-hidden="true"></span></span>
<div class="relative inline-flex items-center [&>input]:h-12"><input type="text" placeholder="Type a command or search..." class="w-full rounded-[calc(var(--ui-radius)*1.5)] border-0 placeholder:text-[var(--ui-text-dimmed)] focus:outline-none disabled:cursor-not-allowed disabled:opacity-75 transition-colors px-3 py-2 text-sm gap-2 text-[var(--ui-text-highlighted)] pl-10" autocomplete="false" aria-expanded="true" aria-disabled="false" aria-autocomplete="list" role="combobox" aria-controls="radix-vue-combobox-content-v-0-0-0" aria-activedescendant="radix-vue-combobox-option-v-0-0-3" value=""><span class="absolute inset-y-0 start-0 flex items-center pl-3"><span class="iconify i-heroicons:sparkles shrink-0 text-[var(--ui-text-dimmed)] size-5 animate-spin" aria-hidden="true"></span></span>
<!--v-if-->
</div>
<!--teleport start-->
<div id="radix-vue-combobox-content-v-0-0-0" role="listbox" data-state="open" style="display: flex; flex-direction: column; outline-color: none; outline-style: none; outline-width: initial;" class="relative overflow-hidden">
<div class="py-6 text-center text-sm">No results</div>
<div class="divide-y divide-[var(--ui-border)] scroll-py-1" data-radix-combobox-viewport="" role="presentation" style="position: relative; flex-grow: 1; flex-shrink: 1; flex-basis: 0%; overflow: auto;"></div>
<!---->
<div class="divide-y divide-[var(--ui-border)] scroll-py-1" data-radix-combobox-viewport="" role="presentation" style="position: relative; flex-grow: 1; flex-shrink: 1; flex-basis: 0%; overflow: auto;">
<div role="group" aria-labelledby="radix-vue-combobox-group-v-0-0-1" class="p-1 isolate">
<!--v-if-->
<div id="radix-vue-combobox-option-v-0-0-3" role="option" tabindex="-1" aria-labelledby="radix-vue-combobox-item-v-0-0-2" aria-selected="false" data-state="unchecked" class="group relative w-full flex items-center gap-2 px-2 py-1.5 text-sm select-none outline-none before:absolute before:z-[-1] before:inset-px before:rounded-[calc(var(--ui-radius)*1.5)] data-disabled:cursor-not-allowed data-disabled:opacity-75 text-[var(--ui-text)] data-highlighted:text-[var(--ui-text-highlighted)] data-highlighted:before:bg-[var(--ui-bg-elevated)]/50 transition-colors before:transition-colors" data-radix-vue-combobox-item="" data-highlighted=""><span class="iconify i-heroicons:document-plus shrink-0 size-5 text-[var(--ui-text-dimmed)] group-data-highlighted:text-[var(--ui-text)] transition-colors" aria-hidden="true"></span><span class="truncate space-x-1"><!--v-if--><span class="text-[var(--ui-text-highlighted)] [&>mark]:text-[var(--ui-bg)] [&>mark]:bg-[var(--ui-primary)]">Add new file</span><span class="text-[var(--ui-text-dimmed)] [&>mark]:text-[var(--ui-bg)] [&>mark]:bg-[var(--ui-primary)]">Create a new file in the current directory or workspace.</span></span><span class="ms-auto inline-flex gap-1.5 items-center"><span class="hidden lg:inline-flex items-center shrink-0 gap-0.5"><kbd class="inline-flex items-center justify-center px-1 rounded-[var(--ui-radius)] font-medium font-sans bg-[var(--ui-bg)] text-[var(--ui-text-highlighted)] ring ring-inset ring-[var(--ui-border-accented)] h-5 min-w-[20px] text-[11px]">⌃</kbd><kbd class="inline-flex items-center justify-center px-1 rounded-[var(--ui-radius)] font-medium font-sans bg-[var(--ui-bg)] text-[var(--ui-text-highlighted)] ring ring-inset ring-[var(--ui-border-accented)] h-5 min-w-[20px] text-[11px]">N</kbd></span>
<!----></span>
</div>
<div id="radix-vue-combobox-option-v-0-0-5" role="option" tabindex="-1" aria-labelledby="radix-vue-combobox-item-v-0-0-4" aria-selected="false" data-state="unchecked" class="group relative w-full flex items-center gap-2 px-2 py-1.5 text-sm select-none outline-none before:absolute before:z-[-1] before:inset-px before:rounded-[calc(var(--ui-radius)*1.5)] data-disabled:cursor-not-allowed data-disabled:opacity-75 text-[var(--ui-text)] data-highlighted:text-[var(--ui-text-highlighted)] data-highlighted:before:bg-[var(--ui-bg-elevated)]/50 transition-colors before:transition-colors" data-radix-vue-combobox-item=""><span class="iconify i-heroicons:folder-plus shrink-0 size-5 text-[var(--ui-text-dimmed)] group-data-highlighted:text-[var(--ui-text)] transition-colors" aria-hidden="true"></span><span class="truncate space-x-1"><!--v-if--><span class="text-[var(--ui-text-highlighted)] [&>mark]:text-[var(--ui-bg)] [&>mark]:bg-[var(--ui-primary)]">Add new folder</span><span class="text-[var(--ui-text-dimmed)] [&>mark]:text-[var(--ui-bg)] [&>mark]:bg-[var(--ui-primary)]">Create a new folder in the current directory or workspace.</span></span><span class="ms-auto inline-flex gap-1.5 items-center"><span class="hidden lg:inline-flex items-center shrink-0 gap-0.5"><kbd class="inline-flex items-center justify-center px-1 rounded-[var(--ui-radius)] font-medium font-sans bg-[var(--ui-bg)] text-[var(--ui-text-highlighted)] ring ring-inset ring-[var(--ui-border-accented)] h-5 min-w-[20px] text-[11px]">⌃</kbd><kbd class="inline-flex items-center justify-center px-1 rounded-[var(--ui-radius)] font-medium font-sans bg-[var(--ui-bg)] text-[var(--ui-text-highlighted)] ring ring-inset ring-[var(--ui-border-accented)] h-5 min-w-[20px] text-[11px]">F</kbd></span>
<!----></span>
</div>
<div id="radix-vue-combobox-option-v-0-0-7" role="option" tabindex="-1" aria-labelledby="radix-vue-combobox-item-v-0-0-6" aria-selected="false" data-state="unchecked" class="group relative w-full flex items-center gap-2 px-2 py-1.5 text-sm select-none outline-none before:absolute before:z-[-1] before:inset-px before:rounded-[calc(var(--ui-radius)*1.5)] data-disabled:cursor-not-allowed data-disabled:opacity-75 text-[var(--ui-text)] data-highlighted:text-[var(--ui-text-highlighted)] data-highlighted:before:bg-[var(--ui-bg-elevated)]/50 transition-colors before:transition-colors" data-radix-vue-combobox-item=""><span class="iconify i-heroicons:hashtag shrink-0 size-5 text-[var(--ui-text-dimmed)] group-data-highlighted:text-[var(--ui-text)] transition-colors" aria-hidden="true"></span><span class="truncate space-x-1"><!--v-if--><span class="text-[var(--ui-text-highlighted)] [&>mark]:text-[var(--ui-bg)] [&>mark]:bg-[var(--ui-primary)]">Add hashtag</span><span class="text-[var(--ui-text-dimmed)] [&>mark]:text-[var(--ui-bg)] [&>mark]:bg-[var(--ui-primary)]">Add a hashtag to the current item.</span></span><span class="ms-auto inline-flex gap-1.5 items-center"><span class="hidden lg:inline-flex items-center shrink-0 gap-0.5"><kbd class="inline-flex items-center justify-center px-1 rounded-[var(--ui-radius)] font-medium font-sans bg-[var(--ui-bg)] text-[var(--ui-text-highlighted)] ring ring-inset ring-[var(--ui-border-accented)] h-5 min-w-[20px] text-[11px]">⌃</kbd><kbd class="inline-flex items-center justify-center px-1 rounded-[var(--ui-radius)] font-medium font-sans bg-[var(--ui-bg)] text-[var(--ui-text-highlighted)] ring ring-inset ring-[var(--ui-border-accented)] h-5 min-w-[20px] text-[11px]">H</kbd></span>
<!----></span>
</div>
<div id="radix-vue-combobox-option-v-0-0-9" role="option" tabindex="-1" aria-labelledby="radix-vue-combobox-item-v-0-0-8" aria-selected="false" data-state="unchecked" class="group relative w-full flex items-center gap-2 px-2 py-1.5 text-sm select-none outline-none before:absolute before:z-[-1] before:inset-px before:rounded-[calc(var(--ui-radius)*1.5)] data-disabled:cursor-not-allowed data-disabled:opacity-75 text-[var(--ui-text)] data-highlighted:text-[var(--ui-text-highlighted)] data-highlighted:before:bg-[var(--ui-bg-elevated)]/50 transition-colors before:transition-colors" data-radix-vue-combobox-item=""><span class="iconify i-heroicons:tag shrink-0 size-5 text-[var(--ui-text-dimmed)] group-data-highlighted:text-[var(--ui-text)] transition-colors" aria-hidden="true"></span><span class="truncate space-x-1"><!--v-if--><span class="text-[var(--ui-text-highlighted)] [&>mark]:text-[var(--ui-bg)] [&>mark]:bg-[var(--ui-primary)]">Add label</span><span class="text-[var(--ui-text-dimmed)] [&>mark]:text-[var(--ui-bg)] [&>mark]:bg-[var(--ui-primary)]">Add a label to the current item.</span></span><span class="ms-auto inline-flex gap-1.5 items-center"><span class="hidden lg:inline-flex items-center shrink-0 gap-0.5"><kbd class="inline-flex items-center justify-center px-1 rounded-[var(--ui-radius)] font-medium font-sans bg-[var(--ui-bg)] text-[var(--ui-text-highlighted)] ring ring-inset ring-[var(--ui-border-accented)] h-5 min-w-[20px] text-[11px]">⌃</kbd><kbd class="inline-flex items-center justify-center px-1 rounded-[var(--ui-radius)] font-medium font-sans bg-[var(--ui-bg)] text-[var(--ui-text-highlighted)] ring ring-inset ring-[var(--ui-border-accented)] h-5 min-w-[20px] text-[11px]">L</kbd></span>
<!----></span>
</div>
</div>
<div role="group" aria-labelledby="radix-vue-combobox-group-v-0-0-10" class="p-1 isolate">
<div id="radix-vue-combobox-group-v-0-0-10" class="px-2 py-1.5 text-xs font-semibold text-[var(--ui-text-highlighted)]">Labels</div>
<div id="radix-vue-combobox-option-v-0-0-12" role="option" tabindex="-1" aria-labelledby="radix-vue-combobox-item-v-0-0-11" aria-selected="false" data-state="unchecked" class="group relative w-full flex items-center gap-2 px-2 py-1.5 text-sm select-none outline-none before:absolute before:z-[-1] before:inset-px before:rounded-[calc(var(--ui-radius)*1.5)] data-disabled:cursor-not-allowed data-disabled:opacity-75 text-[var(--ui-text)] data-highlighted:text-[var(--ui-text-highlighted)] data-highlighted:before:bg-[var(--ui-bg-elevated)]/50 transition-colors before:transition-colors" data-radix-vue-combobox-item="">
<div class="relative inline-flex items-center justify-center shrink-0 size-5"><span class="rounded-full ring ring-[var(--ui-bg)] flex items-center justify-center text-[var(--ui-bg)] font-medium whitespace-nowrap bg-[var(--ui-error)] h-[8px] min-w-[8px] text-[8px] top-0 right-0"></span></div><span class="truncate space-x-1"><!--v-if--><span class="text-[var(--ui-text-highlighted)] [&>mark]:text-[var(--ui-bg)] [&>mark]:bg-[var(--ui-primary)]">bug</span><span class="text-[var(--ui-text-dimmed)] [&>mark]:text-[var(--ui-bg)] [&>mark]:bg-[var(--ui-primary)]"></span></span><span class="ms-auto inline-flex gap-1.5 items-center"><!--v-if--><!----></span>
</div>
<div id="radix-vue-combobox-option-v-0-0-14" role="option" tabindex="-1" aria-labelledby="radix-vue-combobox-item-v-0-0-13" aria-selected="false" data-state="unchecked" class="group relative w-full flex items-center gap-2 px-2 py-1.5 text-sm select-none outline-none before:absolute before:z-[-1] before:inset-px before:rounded-[calc(var(--ui-radius)*1.5)] data-disabled:cursor-not-allowed data-disabled:opacity-75 text-[var(--ui-text)] data-highlighted:text-[var(--ui-text-highlighted)] data-highlighted:before:bg-[var(--ui-bg-elevated)]/50 transition-colors before:transition-colors" data-radix-vue-combobox-item="">
<div class="relative inline-flex items-center justify-center shrink-0 size-5"><span class="rounded-full ring ring-[var(--ui-bg)] flex items-center justify-center text-[var(--ui-bg)] font-medium whitespace-nowrap bg-[var(--ui-success)] h-[8px] min-w-[8px] text-[8px] top-0 right-0"></span></div><span class="truncate space-x-1"><!--v-if--><span class="text-[var(--ui-text-highlighted)] [&>mark]:text-[var(--ui-bg)] [&>mark]:bg-[var(--ui-primary)]">feature</span><span class="text-[var(--ui-text-dimmed)] [&>mark]:text-[var(--ui-bg)] [&>mark]:bg-[var(--ui-primary)]"></span></span><span class="ms-auto inline-flex gap-1.5 items-center"><!--v-if--><!----></span>
</div>
<div id="radix-vue-combobox-option-v-0-0-16" role="option" tabindex="-1" aria-labelledby="radix-vue-combobox-item-v-0-0-15" aria-selected="false" data-state="unchecked" class="group relative w-full flex items-center gap-2 px-2 py-1.5 text-sm select-none outline-none before:absolute before:z-[-1] before:inset-px before:rounded-[calc(var(--ui-radius)*1.5)] data-disabled:cursor-not-allowed data-disabled:opacity-75 text-[var(--ui-text)] data-highlighted:text-[var(--ui-text-highlighted)] data-highlighted:before:bg-[var(--ui-bg-elevated)]/50 transition-colors before:transition-colors" data-radix-vue-combobox-item="">
<div class="relative inline-flex items-center justify-center shrink-0 size-5"><span class="rounded-full ring ring-[var(--ui-bg)] flex items-center justify-center text-[var(--ui-bg)] font-medium whitespace-nowrap bg-[var(--ui-info)] h-[8px] min-w-[8px] text-[8px] top-0 right-0"></span></div><span class="truncate space-x-1"><!--v-if--><span class="text-[var(--ui-text-highlighted)] [&>mark]:text-[var(--ui-bg)] [&>mark]:bg-[var(--ui-primary)]">enhancement</span><span class="text-[var(--ui-text-dimmed)] [&>mark]:text-[var(--ui-bg)] [&>mark]:bg-[var(--ui-primary)]"></span></span><span class="ms-auto inline-flex gap-1.5 items-center"><!--v-if--><!----></span>
</div>
</div>
<div role="group" aria-labelledby="radix-vue-combobox-group-v-0-0-17" class="p-1 isolate">
<div id="radix-vue-combobox-group-v-0-0-17" class="px-2 py-1.5 text-xs font-semibold text-[var(--ui-text-highlighted)]">Users</div>
<div id="radix-vue-combobox-option-v-0-0-19" role="option" tabindex="-1" aria-labelledby="radix-vue-combobox-item-v-0-0-18" aria-selected="false" data-state="unchecked" class="group relative w-full flex items-center gap-2 px-2 py-1.5 text-sm select-none outline-none before:absolute before:z-[-1] before:inset-px before:rounded-[calc(var(--ui-radius)*1.5)] data-disabled:cursor-not-allowed data-disabled:opacity-75 text-[var(--ui-text)] data-highlighted:text-[var(--ui-text-highlighted)] data-highlighted:before:bg-[var(--ui-bg-elevated)]/50 transition-colors before:transition-colors" data-radix-vue-combobox-item=""><span class="inline-flex items-center justify-center select-none overflow-hidden rounded-full align-middle bg-[var(--ui-bg-elevated)] size-5 text-[10px] shrink-0"><img role="img" src="https://github.com/benjamincanac.png" class="h-full w-full rounded-[inherit] object-cover" style="display: none;"><span class="font-medium leading-none text-[var(--ui-text-muted)] truncate"></span></span><span class="truncate space-x-1"><!--v-if--><span class="text-[var(--ui-text-highlighted)] [&>mark]:text-[var(--ui-bg)] [&>mark]:bg-[var(--ui-primary)]">benjamincanac</span><span class="text-[var(--ui-text-dimmed)] [&>mark]:text-[var(--ui-bg)] [&>mark]:bg-[var(--ui-primary)]"></span></span><span class="ms-auto inline-flex gap-1.5 items-center"><!--v-if--><!----></span></div>
</div>
</div>
<style>
/* Hide scrollbars cross-browser and enable momentum scroll for touch devices */
[data-radix-combobox-viewport] {
@@ -1244,3 +1276,30 @@ exports[`CommandPalette > renders with ui correctly 1`] = `
<!---->
</div>"
`;
exports[`CommandPalette > renders without results correctly 1`] = `
"<div style="pointer-events: auto;" dir="ltr" class="flex flex-col min-h-0 min-w-0 divide-y divide-[var(--ui-border)]">
<div class="relative inline-flex items-center [&>input]:h-12"><input type="text" placeholder="Type a command or search..." class="w-full rounded-[calc(var(--ui-radius)*1.5)] border-0 placeholder:text-[var(--ui-text-dimmed)] focus:outline-none disabled:cursor-not-allowed disabled:opacity-75 transition-colors px-3 py-2 text-sm gap-2 text-[var(--ui-text-highlighted)] pl-10" autocomplete="false" aria-expanded="true" aria-controls="" aria-disabled="false" aria-autocomplete="list" role="combobox" value=""><span class="absolute inset-y-0 start-0 flex items-center pl-3"><span class="iconify i-heroicons:magnifying-glass-20-solid shrink-0 text-[var(--ui-text-dimmed)] size-5" aria-hidden="true"></span></span>
<!--v-if-->
</div>
<!--teleport start-->
<div id="radix-vue-combobox-content-v-0-0-0" role="listbox" data-state="open" style="display: flex; flex-direction: column; outline-color: none; outline-style: none; outline-width: initial;" class="relative overflow-hidden">
<div class="py-6 text-center text-sm text-[var(--ui-text-muted)]">No results</div>
<div class="divide-y divide-[var(--ui-border)] scroll-py-1" data-radix-combobox-viewport="" role="presentation" style="position: relative; flex-grow: 1; flex-shrink: 1; flex-basis: 0%; overflow: auto;"></div>
<style>
/* Hide scrollbars cross-browser and enable momentum scroll for touch devices */
[data-radix-combobox-viewport] {
scrollbar-width: none;
-ms-overflow-style: none;
-webkit-overflow-scrolling: touch;
}
[data-radix-combobox-viewport]::-webkit-scrollbar {
display: none;
}
</style>
</div>
<!--teleport end-->
<!---->
</div>"
`;

View File

@@ -0,0 +1,986 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`Table > renders with class correctly 1`] = `
"<div class="overflow-auto absolute">
<table class="min-w-full overflow-clip">
<thead class="relative [&>tr]:after:absolute [&>tr]:after:inset-x-0 [&>tr]:after:bottom-0 [&>tr]:after:h-px [&>tr]:after:bg-[var(--ui-border-accented)]">
<tr class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Id</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Amount</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Status</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Email</th>
</tr>
</thead>
<tbody class="divide-y divide-[var(--ui-border)]">
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">m5gr84i9</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">316</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">ken99@yahoo.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">3u1reuv4</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">242</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Abe45@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">derv1ws0</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">837</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">processing</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Monserrat44@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">5kma53ae</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">874</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Silas22@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">bhqecj4p</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">721</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">failed</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">carmella@hotmail.com</td>
</tr>
<!--v-if-->
</tbody>
</table>
</div>"
`;
exports[`Table > renders with columns correctly 1`] = `
"<div class="relative overflow-auto">
<table class="min-w-full overflow-clip">
<thead class="relative [&>tr]:after:absolute [&>tr]:after:inset-x-0 [&>tr]:after:bottom-0 [&>tr]:after:h-px [&>tr]:after:bg-[var(--ui-border-accented)]">
<tr class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">
<ucheckbox modelvalue="false" indeterminate="false" arialabel="Select all"></ucheckbox>
</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">#</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Date</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Status</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">
<ubutton color="neutral" variant="ghost" label="Email" icon="i-heroicons-arrows-up-down-20-solid" class="-mx-2.5"></ubutton>
</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">
<div class="text-right">Amount</div>
</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">
<!---->
</th>
</tr>
</thead>
<tbody class="divide-y divide-[var(--ui-border)]">
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">
<ucheckbox modelvalue="false" arialabel="Select row"></ucheckbox>
</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">#m5gr84i9</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Invalid Date</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">
<ubadge class="capitalize" variant="subtle"></ubadge>
</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">
<div class="lowercase">ken99@yahoo.com</div>
</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">
<div class="text-right font-medium">€316.00</div>
</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">
<div class="text-right">
<udropdownmenu content="[object Object]" items="[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]"></udropdownmenu>
</div>
</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">
<ucheckbox modelvalue="false" arialabel="Select row"></ucheckbox>
</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">#3u1reuv4</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Invalid Date</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">
<ubadge class="capitalize" variant="subtle"></ubadge>
</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">
<div class="lowercase">Abe45@gmail.com</div>
</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">
<div class="text-right font-medium">€242.00</div>
</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">
<div class="text-right">
<udropdownmenu content="[object Object]" items="[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]"></udropdownmenu>
</div>
</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">
<ucheckbox modelvalue="false" arialabel="Select row"></ucheckbox>
</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">#derv1ws0</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Invalid Date</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">
<ubadge class="capitalize" variant="subtle"></ubadge>
</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">
<div class="lowercase">Monserrat44@gmail.com</div>
</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">
<div class="text-right font-medium">€837.00</div>
</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">
<div class="text-right">
<udropdownmenu content="[object Object]" items="[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]"></udropdownmenu>
</div>
</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">
<ucheckbox modelvalue="false" arialabel="Select row"></ucheckbox>
</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">#5kma53ae</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Invalid Date</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">
<ubadge class="capitalize" variant="subtle"></ubadge>
</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">
<div class="lowercase">Silas22@gmail.com</div>
</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">
<div class="text-right font-medium">€874.00</div>
</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">
<div class="text-right">
<udropdownmenu content="[object Object]" items="[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]"></udropdownmenu>
</div>
</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">
<ucheckbox modelvalue="false" arialabel="Select row"></ucheckbox>
</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">#bhqecj4p</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Invalid Date</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">
<ubadge class="capitalize" variant="subtle" color="error"></ubadge>
</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">
<div class="lowercase">carmella@hotmail.com</div>
</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">
<div class="text-right font-medium">€721.00</div>
</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">
<div class="text-right">
<udropdownmenu content="[object Object]" items="[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]"></udropdownmenu>
</div>
</td>
</tr>
<!--v-if-->
</tbody>
</table>
</div>"
`;
exports[`Table > renders with data correctly 1`] = `
"<div class="relative overflow-auto">
<table class="min-w-full overflow-clip">
<thead class="relative [&>tr]:after:absolute [&>tr]:after:inset-x-0 [&>tr]:after:bottom-0 [&>tr]:after:h-px [&>tr]:after:bg-[var(--ui-border-accented)]">
<tr class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Id</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Amount</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Status</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Email</th>
</tr>
</thead>
<tbody class="divide-y divide-[var(--ui-border)]">
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">m5gr84i9</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">316</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">ken99@yahoo.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">3u1reuv4</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">242</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Abe45@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">derv1ws0</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">837</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">processing</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Monserrat44@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">5kma53ae</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">874</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Silas22@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">bhqecj4p</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">721</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">failed</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">carmella@hotmail.com</td>
</tr>
<!--v-if-->
</tbody>
</table>
</div>"
`;
exports[`Table > renders with loading animation carousel correctly 1`] = `
"<div class="relative overflow-auto">
<table class="min-w-full overflow-clip">
<thead class="relative [&>tr]:after:absolute [&>tr]:after:inset-x-0 [&>tr]:after:bottom-0 [&>tr]:after:h-px [&>tr]:after:bg-[var(--ui-border-accented)] after:absolute after:bottom-0 after:inset-x-0 after:h-px after:bg-[var(--ui-primary)] after:animate-[carousel_2s_ease-in-out_infinite]">
<tr class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Id</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Amount</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Status</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Email</th>
</tr>
</thead>
<tbody class="divide-y divide-[var(--ui-border)]">
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">m5gr84i9</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">316</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">ken99@yahoo.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">3u1reuv4</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">242</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Abe45@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">derv1ws0</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">837</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">processing</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Monserrat44@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">5kma53ae</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">874</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Silas22@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">bhqecj4p</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">721</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">failed</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">carmella@hotmail.com</td>
</tr>
<!--v-if-->
</tbody>
</table>
</div>"
`;
exports[`Table > renders with loading animation carousel-inverse correctly 1`] = `
"<div class="relative overflow-auto">
<table class="min-w-full overflow-clip">
<thead class="relative [&>tr]:after:absolute [&>tr]:after:inset-x-0 [&>tr]:after:bottom-0 [&>tr]:after:h-px [&>tr]:after:bg-[var(--ui-border-accented)] after:absolute after:bottom-0 after:inset-x-0 after:h-px after:bg-[var(--ui-primary)] after:animate-[carousel-inverse_2s_ease-in-out_infinite]">
<tr class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Id</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Amount</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Status</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Email</th>
</tr>
</thead>
<tbody class="divide-y divide-[var(--ui-border)]">
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">m5gr84i9</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">316</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">ken99@yahoo.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">3u1reuv4</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">242</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Abe45@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">derv1ws0</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">837</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">processing</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Monserrat44@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">5kma53ae</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">874</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Silas22@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">bhqecj4p</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">721</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">failed</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">carmella@hotmail.com</td>
</tr>
<!--v-if-->
</tbody>
</table>
</div>"
`;
exports[`Table > renders with loading animation elastic correctly 1`] = `
"<div class="relative overflow-auto">
<table class="min-w-full overflow-clip">
<thead class="relative [&>tr]:after:absolute [&>tr]:after:inset-x-0 [&>tr]:after:bottom-0 [&>tr]:after:h-px [&>tr]:after:bg-[var(--ui-border-accented)] after:absolute after:bottom-0 after:inset-x-0 after:h-px after:bg-[var(--ui-primary)] after:animate-[elastic_2s_ease-in-out_infinite]">
<tr class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Id</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Amount</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Status</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Email</th>
</tr>
</thead>
<tbody class="divide-y divide-[var(--ui-border)]">
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">m5gr84i9</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">316</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">ken99@yahoo.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">3u1reuv4</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">242</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Abe45@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">derv1ws0</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">837</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">processing</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Monserrat44@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">5kma53ae</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">874</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Silas22@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">bhqecj4p</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">721</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">failed</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">carmella@hotmail.com</td>
</tr>
<!--v-if-->
</tbody>
</table>
</div>"
`;
exports[`Table > renders with loading animation swing correctly 1`] = `
"<div class="relative overflow-auto">
<table class="min-w-full overflow-clip">
<thead class="relative [&>tr]:after:absolute [&>tr]:after:inset-x-0 [&>tr]:after:bottom-0 [&>tr]:after:h-px [&>tr]:after:bg-[var(--ui-border-accented)] after:absolute after:bottom-0 after:inset-x-0 after:h-px after:bg-[var(--ui-primary)] after:animate-[swing_2s_ease-in-out_infinite]">
<tr class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Id</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Amount</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Status</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Email</th>
</tr>
</thead>
<tbody class="divide-y divide-[var(--ui-border)]">
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">m5gr84i9</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">316</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">ken99@yahoo.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">3u1reuv4</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">242</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Abe45@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">derv1ws0</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">837</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">processing</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Monserrat44@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">5kma53ae</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">874</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Silas22@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">bhqecj4p</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">721</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">failed</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">carmella@hotmail.com</td>
</tr>
<!--v-if-->
</tbody>
</table>
</div>"
`;
exports[`Table > renders with loading color error correctly 1`] = `
"<div class="relative overflow-auto">
<table class="min-w-full overflow-clip">
<thead class="relative [&>tr]:after:absolute [&>tr]:after:inset-x-0 [&>tr]:after:bottom-0 [&>tr]:after:h-px [&>tr]:after:bg-[var(--ui-border-accented)] after:absolute after:bottom-0 after:inset-x-0 after:h-px after:bg-[var(--ui-error)] after:animate-[carousel_2s_ease-in-out_infinite]">
<tr class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Id</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Amount</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Status</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Email</th>
</tr>
</thead>
<tbody class="divide-y divide-[var(--ui-border)]">
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">m5gr84i9</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">316</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">ken99@yahoo.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">3u1reuv4</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">242</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Abe45@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">derv1ws0</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">837</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">processing</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Monserrat44@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">5kma53ae</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">874</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Silas22@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">bhqecj4p</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">721</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">failed</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">carmella@hotmail.com</td>
</tr>
<!--v-if-->
</tbody>
</table>
</div>"
`;
exports[`Table > renders with loading color info correctly 1`] = `
"<div class="relative overflow-auto">
<table class="min-w-full overflow-clip">
<thead class="relative [&>tr]:after:absolute [&>tr]:after:inset-x-0 [&>tr]:after:bottom-0 [&>tr]:after:h-px [&>tr]:after:bg-[var(--ui-border-accented)] after:absolute after:bottom-0 after:inset-x-0 after:h-px after:bg-[var(--ui-info)] after:animate-[carousel_2s_ease-in-out_infinite]">
<tr class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Id</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Amount</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Status</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Email</th>
</tr>
</thead>
<tbody class="divide-y divide-[var(--ui-border)]">
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">m5gr84i9</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">316</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">ken99@yahoo.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">3u1reuv4</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">242</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Abe45@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">derv1ws0</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">837</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">processing</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Monserrat44@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">5kma53ae</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">874</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Silas22@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">bhqecj4p</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">721</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">failed</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">carmella@hotmail.com</td>
</tr>
<!--v-if-->
</tbody>
</table>
</div>"
`;
exports[`Table > renders with loading color neutral correctly 1`] = `
"<div class="relative overflow-auto">
<table class="min-w-full overflow-clip">
<thead class="relative [&>tr]:after:absolute [&>tr]:after:inset-x-0 [&>tr]:after:bottom-0 [&>tr]:after:h-px [&>tr]:after:bg-[var(--ui-border-accented)] after:absolute after:bottom-0 after:inset-x-0 after:h-px after:bg-[var(--ui-bg-inverted)] after:animate-[carousel_2s_ease-in-out_infinite]">
<tr class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Id</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Amount</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Status</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Email</th>
</tr>
</thead>
<tbody class="divide-y divide-[var(--ui-border)]">
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">m5gr84i9</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">316</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">ken99@yahoo.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">3u1reuv4</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">242</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Abe45@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">derv1ws0</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">837</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">processing</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Monserrat44@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">5kma53ae</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">874</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Silas22@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">bhqecj4p</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">721</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">failed</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">carmella@hotmail.com</td>
</tr>
<!--v-if-->
</tbody>
</table>
</div>"
`;
exports[`Table > renders with loading color primary correctly 1`] = `
"<div class="relative overflow-auto">
<table class="min-w-full overflow-clip">
<thead class="relative [&>tr]:after:absolute [&>tr]:after:inset-x-0 [&>tr]:after:bottom-0 [&>tr]:after:h-px [&>tr]:after:bg-[var(--ui-border-accented)] after:absolute after:bottom-0 after:inset-x-0 after:h-px after:bg-[var(--ui-primary)] after:animate-[carousel_2s_ease-in-out_infinite]">
<tr class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Id</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Amount</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Status</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Email</th>
</tr>
</thead>
<tbody class="divide-y divide-[var(--ui-border)]">
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">m5gr84i9</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">316</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">ken99@yahoo.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">3u1reuv4</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">242</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Abe45@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">derv1ws0</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">837</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">processing</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Monserrat44@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">5kma53ae</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">874</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Silas22@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">bhqecj4p</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">721</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">failed</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">carmella@hotmail.com</td>
</tr>
<!--v-if-->
</tbody>
</table>
</div>"
`;
exports[`Table > renders with loading color secondary correctly 1`] = `
"<div class="relative overflow-auto">
<table class="min-w-full overflow-clip">
<thead class="relative [&>tr]:after:absolute [&>tr]:after:inset-x-0 [&>tr]:after:bottom-0 [&>tr]:after:h-px [&>tr]:after:bg-[var(--ui-border-accented)] after:absolute after:bottom-0 after:inset-x-0 after:h-px after:bg-[var(--ui-secondary)] after:animate-[carousel_2s_ease-in-out_infinite]">
<tr class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Id</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Amount</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Status</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Email</th>
</tr>
</thead>
<tbody class="divide-y divide-[var(--ui-border)]">
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">m5gr84i9</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">316</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">ken99@yahoo.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">3u1reuv4</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">242</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Abe45@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">derv1ws0</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">837</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">processing</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Monserrat44@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">5kma53ae</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">874</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Silas22@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">bhqecj4p</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">721</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">failed</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">carmella@hotmail.com</td>
</tr>
<!--v-if-->
</tbody>
</table>
</div>"
`;
exports[`Table > renders with loading color success correctly 1`] = `
"<div class="relative overflow-auto">
<table class="min-w-full overflow-clip">
<thead class="relative [&>tr]:after:absolute [&>tr]:after:inset-x-0 [&>tr]:after:bottom-0 [&>tr]:after:h-px [&>tr]:after:bg-[var(--ui-border-accented)] after:absolute after:bottom-0 after:inset-x-0 after:h-px after:bg-[var(--ui-success)] after:animate-[carousel_2s_ease-in-out_infinite]">
<tr class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Id</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Amount</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Status</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Email</th>
</tr>
</thead>
<tbody class="divide-y divide-[var(--ui-border)]">
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">m5gr84i9</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">316</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">ken99@yahoo.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">3u1reuv4</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">242</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Abe45@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">derv1ws0</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">837</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">processing</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Monserrat44@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">5kma53ae</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">874</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Silas22@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">bhqecj4p</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">721</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">failed</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">carmella@hotmail.com</td>
</tr>
<!--v-if-->
</tbody>
</table>
</div>"
`;
exports[`Table > renders with loading color warning correctly 1`] = `
"<div class="relative overflow-auto">
<table class="min-w-full overflow-clip">
<thead class="relative [&>tr]:after:absolute [&>tr]:after:inset-x-0 [&>tr]:after:bottom-0 [&>tr]:after:h-px [&>tr]:after:bg-[var(--ui-border-accented)] after:absolute after:bottom-0 after:inset-x-0 after:h-px after:bg-[var(--ui-warning)] after:animate-[carousel_2s_ease-in-out_infinite]">
<tr class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Id</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Amount</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Status</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Email</th>
</tr>
</thead>
<tbody class="divide-y divide-[var(--ui-border)]">
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">m5gr84i9</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">316</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">ken99@yahoo.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">3u1reuv4</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">242</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Abe45@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">derv1ws0</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">837</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">processing</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Monserrat44@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">5kma53ae</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">874</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Silas22@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">bhqecj4p</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">721</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">failed</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">carmella@hotmail.com</td>
</tr>
<!--v-if-->
</tbody>
</table>
</div>"
`;
exports[`Table > renders with loading correctly 1`] = `
"<div class="relative overflow-auto">
<table class="min-w-full overflow-clip">
<thead class="relative [&>tr]:after:absolute [&>tr]:after:inset-x-0 [&>tr]:after:bottom-0 [&>tr]:after:h-px [&>tr]:after:bg-[var(--ui-border-accented)] after:absolute after:bottom-0 after:inset-x-0 after:h-px after:bg-[var(--ui-primary)] after:animate-[carousel_2s_ease-in-out_infinite]">
<tr class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Id</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Amount</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Status</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Email</th>
</tr>
</thead>
<tbody class="divide-y divide-[var(--ui-border)]">
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">m5gr84i9</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">316</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">ken99@yahoo.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">3u1reuv4</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">242</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Abe45@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">derv1ws0</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">837</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">processing</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Monserrat44@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">5kma53ae</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">874</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Silas22@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">bhqecj4p</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">721</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">failed</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">carmella@hotmail.com</td>
</tr>
<!--v-if-->
</tbody>
</table>
</div>"
`;
exports[`Table > renders with sticky correctly 1`] = `
"<div class="relative overflow-auto">
<table class="min-w-full overflow-clip">
<thead class="[&>tr]:after:absolute [&>tr]:after:inset-x-0 [&>tr]:after:bottom-0 [&>tr]:after:h-px [&>tr]:after:bg-[var(--ui-border-accented)] sticky top-0 inset-x-0 bg-[var(--ui-bg)]/75 z-[1] backdrop-blur">
<tr class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Id</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Amount</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Status</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Email</th>
</tr>
</thead>
<tbody class="divide-y divide-[var(--ui-border)]">
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">m5gr84i9</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">316</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">ken99@yahoo.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">3u1reuv4</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">242</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Abe45@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">derv1ws0</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">837</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">processing</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Monserrat44@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">5kma53ae</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">874</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Silas22@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">bhqecj4p</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">721</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">failed</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">carmella@hotmail.com</td>
</tr>
<!--v-if-->
</tbody>
</table>
</div>"
`;
exports[`Table > renders with ui correctly 1`] = `
"<div class="relative overflow-auto">
<table class="min-w-full overflow-clip table-auto">
<thead class="relative [&>tr]:after:absolute [&>tr]:after:inset-x-0 [&>tr]:after:bottom-0 [&>tr]:after:h-px [&>tr]:after:bg-[var(--ui-border-accented)]">
<tr class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Id</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Amount</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Status</th>
<th data-pinned="false" class="px-4 py-3.5 text-sm text-[var(--ui-text-highlighted)] text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pr-0">Email</th>
</tr>
</thead>
<tbody class="divide-y divide-[var(--ui-border)]">
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">m5gr84i9</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">316</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">ken99@yahoo.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">3u1reuv4</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">242</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Abe45@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">derv1ws0</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">837</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">processing</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Monserrat44@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">5kma53ae</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">874</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">success</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">Silas22@gmail.com</td>
</tr>
<!--v-if-->
<tr data-selected="false" data-expanded="false" class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">bhqecj4p</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">721</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">failed</td>
<td data-pinned="false" class="p-4 text-sm text-[var(--ui-text-muted)] whitespace-nowrap [&:has([role=checkbox])]:pr-0">carmella@hotmail.com</td>
</tr>
<!--v-if-->
</tbody>
</table>
</div>"
`;
exports[`Table > renders without results correctly 1`] = `
"<div class="relative overflow-auto">
<table class="min-w-full overflow-clip">
<thead class="relative [&>tr]:after:absolute [&>tr]:after:inset-x-0 [&>tr]:after:bottom-0 [&>tr]:after:h-px [&>tr]:after:bg-[var(--ui-border-accented)]">
<tr class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50"></tr>
</thead>
<tbody class="divide-y divide-[var(--ui-border)]">
<tr class="data-[selected=true]:bg-[var(--ui-bg-elevated)]/50">
<td colspan="0" class="py-6 text-center text-sm text-[var(--ui-text-muted)]"> No results </td>
</tr>
</tbody>
</table>
</div>"
`;