mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-14 12:14:41 +01:00
feat(Table): add footer support to display column summary (#4194)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
<script setup lang="ts">
|
||||
import { h, resolveComponent } from 'vue'
|
||||
import type { TableColumn, TableRow } from '@nuxt/ui'
|
||||
|
||||
const UBadge = resolveComponent('UBadge')
|
||||
|
||||
type Payment = {
|
||||
id: string
|
||||
date: string
|
||||
status: 'paid' | 'failed' | 'refunded'
|
||||
email: string
|
||||
amount: number
|
||||
}
|
||||
|
||||
const data = ref<Payment[]>([{
|
||||
id: '4600',
|
||||
date: '2024-03-11T15:30:00',
|
||||
status: 'paid',
|
||||
email: 'james.anderson@example.com',
|
||||
amount: 594
|
||||
}, {
|
||||
id: '4599',
|
||||
date: '2024-03-11T10:10:00',
|
||||
status: 'failed',
|
||||
email: 'mia.white@example.com',
|
||||
amount: 276
|
||||
}, {
|
||||
id: '4598',
|
||||
date: '2024-03-11T08:50:00',
|
||||
status: 'refunded',
|
||||
email: 'william.brown@example.com',
|
||||
amount: 315
|
||||
}, {
|
||||
id: '4597',
|
||||
date: '2024-03-10T19:45:00',
|
||||
status: 'paid',
|
||||
email: 'emma.davis@example.com',
|
||||
amount: 529
|
||||
}, {
|
||||
id: '4596',
|
||||
date: '2024-03-10T15:55:00',
|
||||
status: 'paid',
|
||||
email: 'ethan.harris@example.com',
|
||||
amount: 639
|
||||
}])
|
||||
|
||||
const columns: TableColumn<Payment>[] = [{
|
||||
accessorKey: 'id',
|
||||
header: '#',
|
||||
cell: ({ row }) => `#${row.getValue('id')}`
|
||||
}, {
|
||||
accessorKey: 'date',
|
||||
header: 'Date',
|
||||
cell: ({ row }) => {
|
||||
return new Date(row.getValue('date')).toLocaleString('en-US', {
|
||||
day: 'numeric',
|
||||
month: 'short',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
hour12: false
|
||||
})
|
||||
}
|
||||
}, {
|
||||
accessorKey: 'status',
|
||||
header: 'Status',
|
||||
cell: ({ row }) => {
|
||||
const color = ({
|
||||
paid: 'success' as const,
|
||||
failed: 'error' as const,
|
||||
refunded: 'neutral' as const
|
||||
})[row.getValue('status') as string]
|
||||
|
||||
return h(UBadge, { class: 'capitalize', variant: 'subtle', color }, () => row.getValue('status'))
|
||||
}
|
||||
}, {
|
||||
accessorKey: 'email',
|
||||
header: 'Email'
|
||||
}, {
|
||||
accessorKey: 'amount',
|
||||
header: () => h('div', { class: 'text-right' }, 'Amount'),
|
||||
footer: ({ column }) => {
|
||||
const total = column.getFacetedRowModel().rows.reduce((acc: number, row: TableRow<Payment>) => acc + Number.parseFloat(row.getValue('amount')), 0)
|
||||
|
||||
const formatted = new Intl.NumberFormat('en-US', {
|
||||
style: 'currency',
|
||||
currency: 'EUR'
|
||||
}).format(total)
|
||||
|
||||
return h('div', { class: 'text-right font-medium' }, `Total: ${formatted}`)
|
||||
},
|
||||
cell: ({ row }) => {
|
||||
const amount = Number.parseFloat(row.getValue('amount'))
|
||||
|
||||
const formatted = new Intl.NumberFormat('en-US', {
|
||||
style: 'currency',
|
||||
currency: 'EUR'
|
||||
}).format(amount)
|
||||
|
||||
return h('div', { class: 'text-right font-medium' }, formatted)
|
||||
}
|
||||
}]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UTable :data="data" :columns="columns" class="flex-1" />
|
||||
</template>
|
||||
@@ -77,6 +77,7 @@ Use the `columns` prop as an array of [ColumnDef](https://tanstack.com/table/lat
|
||||
|
||||
- `accessorKey`: [The key of the row object to use when extracting the value for the column.]{class="text-muted"}
|
||||
- `header`: [The header to display for the column. If a string is passed, it can be used as a default for the column ID. If a function is passed, it will be passed a props object for the header and should return the rendered header value (the exact type depends on the adapter being used).]{class="text-muted"}
|
||||
- `footer`: [The footer to display for the column. Works exactly like header, but is displayed under the table.]{class="text-muted"}
|
||||
- `cell`: [The cell to display each row for the column. If a function is passed, it will be passed a props object for the cell and should return the rendered cell value (the exact type depends on the adapter being used).]{class="text-muted"}
|
||||
- `meta`: [Extra properties for the column.]{class="text-muted"}
|
||||
- `class`:
|
||||
@@ -161,7 +162,7 @@ props:
|
||||
|
||||
### Sticky
|
||||
|
||||
Use the `sticky` prop to make the header sticky.
|
||||
Use the `sticky` prop to make the header or footer sticky.
|
||||
|
||||
::component-code
|
||||
---
|
||||
@@ -172,6 +173,10 @@ ignore:
|
||||
- class
|
||||
external:
|
||||
- data
|
||||
items:
|
||||
sticky:
|
||||
- true
|
||||
- false
|
||||
props:
|
||||
sticky: true
|
||||
data:
|
||||
@@ -372,6 +377,22 @@ class: '!p-0'
|
||||
This example is similar as the Popover [with following cursor example](/components/popover#with-following-cursor) and uses a [`refDebounced`](https://vueuse.org/shared/refDebounced/#refdebounced) to prevent the Popover from opening and closing too quickly when moving the cursor from one row to another.
|
||||
::
|
||||
|
||||
### With column footer :badge{label="Soon" class="align-text-top"}
|
||||
|
||||
You can add a `footer` property to the column definition to render a footer for the column.
|
||||
|
||||
::component-example
|
||||
---
|
||||
prettier: true
|
||||
collapse: true
|
||||
name: 'table-column-footer-example'
|
||||
highlights:
|
||||
- 94
|
||||
- 108
|
||||
class: '!p-0'
|
||||
---
|
||||
::
|
||||
|
||||
### With column sorting
|
||||
|
||||
You can update a column `header` to render a [Button](/components/button) component inside the `header` to toggle the sorting state using the TanStack Table [Sorting APIs](https://tanstack.com/table/latest/docs/api/features/sorting).
|
||||
|
||||
@@ -242,6 +242,16 @@ const columns: TableColumn<Payment>[] = [{
|
||||
}, {
|
||||
accessorKey: 'amount',
|
||||
header: () => h('div', { class: 'text-right' }, 'Amount'),
|
||||
footer: ({ column }) => {
|
||||
const total = column.getFacetedRowModel().rows.reduce((acc: number, row: TableRow<Payment>) => acc + Number.parseFloat(row.getValue('amount')), 0)
|
||||
|
||||
const formatted = new Intl.NumberFormat('en-US', {
|
||||
style: 'currency',
|
||||
currency: 'EUR'
|
||||
}).format(total)
|
||||
|
||||
return h('div', { class: 'text-right font-medium' }, `Total: ${formatted}`)
|
||||
},
|
||||
cell: ({ row }) => {
|
||||
const amount = Number.parseFloat(row.getValue('amount'))
|
||||
|
||||
|
||||
@@ -83,10 +83,10 @@ export interface TableProps<T extends TableData = TableData> extends TableOption
|
||||
*/
|
||||
empty?: string
|
||||
/**
|
||||
* Whether the table should have a sticky header.
|
||||
* Whether the table should have a sticky header or footer. True for both, 'header' for header only, 'footer' for footer only.
|
||||
* @defaultValue false
|
||||
*/
|
||||
sticky?: boolean
|
||||
sticky?: boolean | 'header' | 'footer'
|
||||
/** Whether the table should be in loading state. */
|
||||
loading?: boolean
|
||||
/**
|
||||
@@ -172,6 +172,7 @@ export interface TableProps<T extends TableData = TableData> extends TableOption
|
||||
}
|
||||
|
||||
type DynamicHeaderSlots<T, K = keyof T> = Record<string, (props: HeaderContext<T, unknown>) => any> & Record<`${K extends string ? K : never}-header`, (props: HeaderContext<T, unknown>) => any>
|
||||
type DynamicFooterSlots<T, K = keyof T> = Record<string, (props: HeaderContext<T, unknown>) => any> & Record<`${K extends string ? K : never}-footer`, (props: HeaderContext<T, unknown>) => any>
|
||||
type DynamicCellSlots<T, K = keyof T> = Record<string, (props: CellContext<T, unknown>) => any> & Record<`${K extends string ? K : never}-cell`, (props: CellContext<T, unknown>) => any>
|
||||
|
||||
export type TableSlots<T extends TableData = TableData> = {
|
||||
@@ -181,7 +182,7 @@ export type TableSlots<T extends TableData = TableData> = {
|
||||
'caption': (props?: {}) => any
|
||||
'body-top': (props?: {}) => any
|
||||
'body-bottom': (props?: {}) => any
|
||||
} & DynamicHeaderSlots<T> & DynamicCellSlots<T>
|
||||
} & DynamicHeaderSlots<T> & DynamicFooterSlots<T> & DynamicCellSlots<T>
|
||||
|
||||
</script>
|
||||
|
||||
@@ -216,6 +217,22 @@ const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.table || {})
|
||||
loadingAnimation: props.loadingAnimation
|
||||
}))
|
||||
|
||||
const hasFooter = computed(() => {
|
||||
function hasFooterRecursive(columns: TableColumn<T>[]): boolean {
|
||||
for (const column of columns) {
|
||||
if ('footer' in column) {
|
||||
return true
|
||||
}
|
||||
if ('columns' in column && hasFooterRecursive(column.columns as TableColumn<T>[])) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
return hasFooterRecursive(columns.value)
|
||||
})
|
||||
|
||||
const globalFilterState = defineModel<string>('globalFilter', { default: undefined })
|
||||
const columnFiltersState = defineModel<ColumnFiltersState>('columnFilters', { default: [] })
|
||||
const columnOrderState = defineModel<ColumnOrderState>('columnOrder', { default: [] })
|
||||
@@ -461,6 +478,30 @@ defineExpose({
|
||||
|
||||
<slot name="body-bottom" />
|
||||
</tbody>
|
||||
|
||||
<tfoot v-if="hasFooter" :class="ui.tfoot({ class: [props.ui?.tfoot] })">
|
||||
<tr :class="ui.separator({ class: [props.ui?.separator] })" />
|
||||
|
||||
<tr v-for="footerGroup in tableApi.getFooterGroups()" :key="footerGroup.id" :class="ui.tr({ class: [props.ui?.tr] })">
|
||||
<th
|
||||
v-for="header in footerGroup.headers"
|
||||
:key="header.id"
|
||||
:data-pinned="header.column.getIsPinned()"
|
||||
:colspan="header.colSpan > 1 ? header.colSpan : undefined"
|
||||
:class="ui.th({
|
||||
class: [
|
||||
props.ui?.th,
|
||||
typeof header.column.columnDef.meta?.class?.th === 'function' ? header.column.columnDef.meta.class.th(header) : header.column.columnDef.meta?.class?.th
|
||||
],
|
||||
pinned: !!header.column.getIsPinned()
|
||||
})"
|
||||
>
|
||||
<slot :name="`${header.id}-footer`" v-bind="header.getContext()">
|
||||
<FlexRender v-if="!header.isPlaceholder" :render="header.column.columnDef.footer" :props="header.getContext()" />
|
||||
</slot>
|
||||
</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</Primitive>
|
||||
</template>
|
||||
|
||||
@@ -7,6 +7,7 @@ export default (options: Required<ModuleOptions>) => ({
|
||||
caption: 'sr-only',
|
||||
thead: 'relative',
|
||||
tbody: 'divide-y divide-default [&>tr]:data-[selectable=true]:hover:bg-elevated/50 [&>tr]:data-[selectable=true]:focus-visible:outline-primary',
|
||||
tfoot: 'relative',
|
||||
tr: 'data-[selected=true]:bg-elevated/50',
|
||||
th: 'px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0',
|
||||
td: 'p-4 text-sm text-muted whitespace-nowrap [&:has([role=checkbox])]:pe-0',
|
||||
@@ -23,7 +24,14 @@ export default (options: Required<ModuleOptions>) => ({
|
||||
},
|
||||
sticky: {
|
||||
true: {
|
||||
thead: 'sticky top-0 inset-x-0 bg-default/75 z-[1] backdrop-blur',
|
||||
tfoot: 'sticky bottom-0 inset-x-0 bg-default/75 z-[1] backdrop-blur'
|
||||
},
|
||||
header: {
|
||||
thead: 'sticky top-0 inset-x-0 bg-default/75 z-[1] backdrop-blur'
|
||||
},
|
||||
footer: {
|
||||
tfoot: 'sticky bottom-0 inset-x-0 bg-default/75 z-[1] backdrop-blur'
|
||||
}
|
||||
},
|
||||
loading: {
|
||||
|
||||
@@ -4,7 +4,7 @@ import { flushPromises } from '@vue/test-utils'
|
||||
import { mountSuspended } from '@nuxt/test-utils/runtime'
|
||||
import { UCheckbox, UButton, UBadge, UDropdownMenu } from '#components'
|
||||
import Table from '../../src/runtime/components/Table.vue'
|
||||
import type { TableProps, TableSlots, TableColumn } from '../../src/runtime/components/Table.vue'
|
||||
import type { TableProps, TableSlots, TableColumn, TableRow } from '../../src/runtime/components/Table.vue'
|
||||
import ComponentRender from '../component-render'
|
||||
import theme from '#build/ui/table'
|
||||
|
||||
@@ -99,6 +99,16 @@ describe('Table', () => {
|
||||
}, {
|
||||
accessorKey: 'amount',
|
||||
header: () => h('div', { class: 'text-right' }, 'Amount'),
|
||||
footer: ({ column }) => {
|
||||
const total = column.getFacetedRowModel().rows.reduce((acc: number, row: TableRow<typeof data[number]>) => acc + Number.parseFloat(row.getValue('amount')), 0)
|
||||
|
||||
const formatted = new Intl.NumberFormat('en-US', {
|
||||
style: 'currency',
|
||||
currency: 'EUR'
|
||||
}).format(total)
|
||||
|
||||
return h('div', { class: 'text-right font-medium' }, `Total: ${formatted}`)
|
||||
},
|
||||
cell: ({ row }) => {
|
||||
const amount = Number.parseFloat(row.getValue('amount'))
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ exports[`Table > renders with as correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</section>"
|
||||
`;
|
||||
@@ -104,6 +105,7 @@ exports[`Table > renders with body-bottom slot correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->Body bottom slot
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -157,6 +159,7 @@ exports[`Table > renders with body-top slot correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -211,6 +214,7 @@ exports[`Table > renders with caption correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -265,6 +269,7 @@ exports[`Table > renders with caption slot correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -319,6 +324,7 @@ exports[`Table > renders with cell slot correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -373,6 +379,7 @@ exports[`Table > renders with class correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -564,6 +571,32 @@ exports[`Table > renders with columns correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<tfoot class="relative">
|
||||
<tr class="absolute z-[1] left-0 w-full h-px bg-(--ui-border-accented)"></tr>
|
||||
<tr class="data-[selected=true]:bg-elevated/50">
|
||||
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0">
|
||||
<!---->
|
||||
</th>
|
||||
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0">
|
||||
<!---->
|
||||
</th>
|
||||
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0">
|
||||
<!---->
|
||||
</th>
|
||||
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0">
|
||||
<!---->
|
||||
</th>
|
||||
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0">
|
||||
<!---->
|
||||
</th>
|
||||
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0">
|
||||
<div class="text-right font-medium">Total: €2,990.00</div>
|
||||
</th>
|
||||
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0">
|
||||
<!---->
|
||||
</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -618,6 +651,7 @@ exports[`Table > renders with data correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -635,6 +669,7 @@ exports[`Table > renders with empty correctly 1`] = `
|
||||
<td colspan="0" class="py-6 text-center text-sm text-muted">There is no data</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -674,6 +709,32 @@ exports[`Table > renders with empty slot correctly 1`] = `
|
||||
<td colspan="7" class="py-6 text-center text-sm text-muted">Empty slot</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tfoot class="relative">
|
||||
<tr class="absolute z-[1] left-0 w-full h-px bg-(--ui-border-accented)"></tr>
|
||||
<tr class="data-[selected=true]:bg-elevated/50">
|
||||
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0">
|
||||
<!---->
|
||||
</th>
|
||||
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0">
|
||||
<!---->
|
||||
</th>
|
||||
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0">
|
||||
<!---->
|
||||
</th>
|
||||
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0">
|
||||
<!---->
|
||||
</th>
|
||||
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0">
|
||||
<!---->
|
||||
</th>
|
||||
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0">
|
||||
<div class="text-right font-medium">Total: €0.00</div>
|
||||
</th>
|
||||
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0">
|
||||
<!---->
|
||||
</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -728,6 +789,7 @@ exports[`Table > renders with expanded slot correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -782,6 +844,7 @@ exports[`Table > renders with header slot correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -836,6 +899,7 @@ exports[`Table > renders with loading animation carousel correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -890,6 +954,7 @@ exports[`Table > renders with loading animation carousel-inverse correctly 1`] =
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -944,6 +1009,7 @@ exports[`Table > renders with loading animation elastic correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -998,6 +1064,7 @@ exports[`Table > renders with loading animation swing correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -1052,6 +1119,7 @@ exports[`Table > renders with loading color error correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -1106,6 +1174,7 @@ exports[`Table > renders with loading color info correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -1160,6 +1229,7 @@ exports[`Table > renders with loading color neutral correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -1214,6 +1284,7 @@ exports[`Table > renders with loading color primary correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -1268,6 +1339,7 @@ exports[`Table > renders with loading color secondary correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -1322,6 +1394,7 @@ exports[`Table > renders with loading color success correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -1376,6 +1449,7 @@ exports[`Table > renders with loading color warning correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -1430,6 +1504,7 @@ exports[`Table > renders with loading correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -1469,6 +1544,32 @@ exports[`Table > renders with loading slot correctly 1`] = `
|
||||
<td colspan="7" class="py-6 text-center">Loading slot</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tfoot class="relative">
|
||||
<tr class="absolute z-[1] left-0 w-full h-px bg-(--ui-border-accented)"></tr>
|
||||
<tr class="data-[selected=true]:bg-elevated/50">
|
||||
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0">
|
||||
<!---->
|
||||
</th>
|
||||
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0">
|
||||
<!---->
|
||||
</th>
|
||||
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0">
|
||||
<!---->
|
||||
</th>
|
||||
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0">
|
||||
<!---->
|
||||
</th>
|
||||
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0">
|
||||
<!---->
|
||||
</th>
|
||||
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0">
|
||||
<div class="text-right font-medium">Total: €0.00</div>
|
||||
</th>
|
||||
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0">
|
||||
<!---->
|
||||
</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -1523,6 +1624,7 @@ exports[`Table > renders with sticky correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -1577,6 +1679,7 @@ exports[`Table > renders with ui correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -1594,6 +1697,7 @@ exports[`Table > renders without data correctly 1`] = `
|
||||
<td colspan="0" class="py-6 text-center text-sm text-muted">No data</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
|
||||
@@ -50,6 +50,7 @@ exports[`Table > renders with as correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</section>"
|
||||
`;
|
||||
@@ -104,6 +105,7 @@ exports[`Table > renders with body-bottom slot correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->Body bottom slot
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -157,6 +159,7 @@ exports[`Table > renders with body-top slot correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -211,6 +214,7 @@ exports[`Table > renders with caption correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -265,6 +269,7 @@ exports[`Table > renders with caption slot correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -319,6 +324,7 @@ exports[`Table > renders with cell slot correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -373,6 +379,7 @@ exports[`Table > renders with class correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -564,6 +571,32 @@ exports[`Table > renders with columns correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<tfoot class="relative">
|
||||
<tr class="absolute z-[1] left-0 w-full h-px bg-(--ui-border-accented)"></tr>
|
||||
<tr class="data-[selected=true]:bg-elevated/50">
|
||||
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0">
|
||||
<!---->
|
||||
</th>
|
||||
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0">
|
||||
<!---->
|
||||
</th>
|
||||
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0">
|
||||
<!---->
|
||||
</th>
|
||||
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0">
|
||||
<!---->
|
||||
</th>
|
||||
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0">
|
||||
<!---->
|
||||
</th>
|
||||
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0">
|
||||
<div class="text-right font-medium">Total: €2,990.00</div>
|
||||
</th>
|
||||
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0">
|
||||
<!---->
|
||||
</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -618,6 +651,7 @@ exports[`Table > renders with data correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -635,6 +669,7 @@ exports[`Table > renders with empty correctly 1`] = `
|
||||
<td colspan="0" class="py-6 text-center text-sm text-muted">There is no data</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -674,6 +709,32 @@ exports[`Table > renders with empty slot correctly 1`] = `
|
||||
<td colspan="7" class="py-6 text-center text-sm text-muted">Empty slot</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tfoot class="relative">
|
||||
<tr class="absolute z-[1] left-0 w-full h-px bg-(--ui-border-accented)"></tr>
|
||||
<tr class="data-[selected=true]:bg-elevated/50">
|
||||
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0">
|
||||
<!---->
|
||||
</th>
|
||||
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0">
|
||||
<!---->
|
||||
</th>
|
||||
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0">
|
||||
<!---->
|
||||
</th>
|
||||
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0">
|
||||
<!---->
|
||||
</th>
|
||||
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0">
|
||||
<!---->
|
||||
</th>
|
||||
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0">
|
||||
<div class="text-right font-medium">Total: €0.00</div>
|
||||
</th>
|
||||
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0">
|
||||
<!---->
|
||||
</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -728,6 +789,7 @@ exports[`Table > renders with expanded slot correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -782,6 +844,7 @@ exports[`Table > renders with header slot correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -836,6 +899,7 @@ exports[`Table > renders with loading animation carousel correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -890,6 +954,7 @@ exports[`Table > renders with loading animation carousel-inverse correctly 1`] =
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -944,6 +1009,7 @@ exports[`Table > renders with loading animation elastic correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -998,6 +1064,7 @@ exports[`Table > renders with loading animation swing correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -1052,6 +1119,7 @@ exports[`Table > renders with loading color error correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -1106,6 +1174,7 @@ exports[`Table > renders with loading color info correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -1160,6 +1229,7 @@ exports[`Table > renders with loading color neutral correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -1214,6 +1284,7 @@ exports[`Table > renders with loading color primary correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -1268,6 +1339,7 @@ exports[`Table > renders with loading color secondary correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -1322,6 +1394,7 @@ exports[`Table > renders with loading color success correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -1376,6 +1449,7 @@ exports[`Table > renders with loading color warning correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -1430,6 +1504,7 @@ exports[`Table > renders with loading correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -1469,6 +1544,32 @@ exports[`Table > renders with loading slot correctly 1`] = `
|
||||
<td colspan="7" class="py-6 text-center">Loading slot</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tfoot class="relative">
|
||||
<tr class="absolute z-[1] left-0 w-full h-px bg-(--ui-border-accented)"></tr>
|
||||
<tr class="data-[selected=true]:bg-elevated/50">
|
||||
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0">
|
||||
<!---->
|
||||
</th>
|
||||
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0">
|
||||
<!---->
|
||||
</th>
|
||||
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0">
|
||||
<!---->
|
||||
</th>
|
||||
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0">
|
||||
<!---->
|
||||
</th>
|
||||
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0">
|
||||
<!---->
|
||||
</th>
|
||||
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0">
|
||||
<div class="text-right font-medium">Total: €0.00</div>
|
||||
</th>
|
||||
<th data-pinned="false" class="px-4 py-3.5 text-sm text-highlighted text-left rtl:text-right font-semibold [&:has([role=checkbox])]:pe-0">
|
||||
<!---->
|
||||
</th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -1523,6 +1624,7 @@ exports[`Table > renders with sticky correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -1577,6 +1679,7 @@ exports[`Table > renders with ui correctly 1`] = `
|
||||
</tr>
|
||||
<!--v-if-->
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
@@ -1594,6 +1697,7 @@ exports[`Table > renders without data correctly 1`] = `
|
||||
<td colspan="0" class="py-6 text-center text-sm text-muted">No data</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<!--v-if-->
|
||||
</table>
|
||||
</div>"
|
||||
`;
|
||||
|
||||
Reference in New Issue
Block a user