mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-28 19:00:35 +01:00
feat(Table): conditionally apply classes to tr and td (#3866)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
This commit is contained in:
@@ -105,6 +105,13 @@ highlights:
|
|||||||
When rendering components with `h`, you can either use the `resolveComponent` function or import from `#components`.
|
When rendering components with `h`, you can either use the `resolveComponent` function or import from `#components`.
|
||||||
::
|
::
|
||||||
|
|
||||||
|
### Meta
|
||||||
|
|
||||||
|
Use the `meta` prop as an object ([TableMeta](https://tanstack.com/table/latest/docs/api/core/table#meta)) to pass properties like:
|
||||||
|
|
||||||
|
- `class`:
|
||||||
|
- `tr`: [The classes to apply to the `tr` element.]{class="text-muted"}
|
||||||
|
|
||||||
### Loading
|
### 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.
|
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.
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Ref } from 'vue'
|
import type { Ref } from 'vue'
|
||||||
import type { AppConfig } from '@nuxt/schema'
|
import type { AppConfig } from '@nuxt/schema'
|
||||||
import type { RowData } from '@tanstack/table-core'
|
import type { Cell, Header, RowData, TableMeta } from '@tanstack/table-core'
|
||||||
import type {
|
import type {
|
||||||
CellContext,
|
CellContext,
|
||||||
ColumnDef,
|
ColumnDef,
|
||||||
@@ -39,13 +39,20 @@ import theme from '#build/ui/table'
|
|||||||
import type { ComponentConfig } from '../types/utils'
|
import type { ComponentConfig } from '../types/utils'
|
||||||
|
|
||||||
declare module '@tanstack/table-core' {
|
declare module '@tanstack/table-core' {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
interface ColumnMeta<TData extends RowData, TValue> {
|
interface ColumnMeta<TData extends RowData, TValue> {
|
||||||
class?: {
|
class?: {
|
||||||
th?: string
|
th?: string | ((cell: Header<TData, TValue>) => string)
|
||||||
td?: string
|
td?: string | ((cell: Cell<TData, TValue>) => string)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface TableMeta<TData> {
|
||||||
|
class?: {
|
||||||
|
tr?: string | ((row: Row<TData>) => string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Table = ComponentConfig<typeof theme, AppConfig, 'table'>
|
type Table = ComponentConfig<typeof theme, AppConfig, 'table'>
|
||||||
@@ -69,6 +76,7 @@ export interface TableProps<T extends TableData> extends TableOptions<T> {
|
|||||||
data?: T[]
|
data?: T[]
|
||||||
columns?: TableColumn<T>[]
|
columns?: TableColumn<T>[]
|
||||||
caption?: string
|
caption?: string
|
||||||
|
meta?: TableMeta<T>
|
||||||
/**
|
/**
|
||||||
* The text to display when the table is empty.
|
* The text to display when the table is empty.
|
||||||
* @defaultValue t('table.noData')
|
* @defaultValue t('table.noData')
|
||||||
@@ -184,6 +192,7 @@ const appConfig = useAppConfig() as Table['AppConfig']
|
|||||||
|
|
||||||
const data = computed(() => props.data ?? [])
|
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 columns = computed<TableColumn<T>[]>(() => props.columns ?? Object.keys(data.value[0] ?? {}).map((accessorKey: string) => ({ accessorKey, header: upperFirst(accessorKey) })))
|
||||||
|
const meta = computed(() => props.meta ?? {})
|
||||||
|
|
||||||
const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.table || {}) })({
|
const ui = computed(() => tv({ extend: tv(theme), ...(appConfig.ui?.table || {}) })({
|
||||||
sticky: props.sticky,
|
sticky: props.sticky,
|
||||||
@@ -212,6 +221,7 @@ const tableApi = useVueTable({
|
|||||||
...reactiveOmit(props, 'as', 'data', 'columns', 'caption', 'sticky', 'loading', 'loadingColor', 'loadingAnimation', 'class', 'ui'),
|
...reactiveOmit(props, 'as', 'data', 'columns', 'caption', 'sticky', 'loading', 'loadingColor', 'loadingAnimation', 'class', 'ui'),
|
||||||
data,
|
data,
|
||||||
columns: columns.value,
|
columns: columns.value,
|
||||||
|
meta: meta.value,
|
||||||
getCoreRowModel: getCoreRowModel(),
|
getCoreRowModel: getCoreRowModel(),
|
||||||
...(props.globalFilterOptions || {}),
|
...(props.globalFilterOptions || {}),
|
||||||
onGlobalFilterChange: updaterOrValue => valueUpdater(updaterOrValue, globalFilterState),
|
onGlobalFilterChange: updaterOrValue => valueUpdater(updaterOrValue, globalFilterState),
|
||||||
@@ -326,7 +336,13 @@ defineExpose({
|
|||||||
:key="header.id"
|
:key="header.id"
|
||||||
:data-pinned="header.column.getIsPinned()"
|
:data-pinned="header.column.getIsPinned()"
|
||||||
:colspan="header.colSpan > 1 ? header.colSpan : undefined"
|
:colspan="header.colSpan > 1 ? header.colSpan : undefined"
|
||||||
:class="ui.th({ class: [props.ui?.th, header.column.columnDef.meta?.class?.th], pinned: !!header.column.getIsPinned() })"
|
: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}-header`" v-bind="header.getContext()">
|
<slot :name="`${header.id}-header`" v-bind="header.getContext()">
|
||||||
<FlexRender v-if="!header.isPlaceholder" :render="header.column.columnDef.header" :props="header.getContext()" />
|
<FlexRender v-if="!header.isPlaceholder" :render="header.column.columnDef.header" :props="header.getContext()" />
|
||||||
@@ -344,14 +360,25 @@ defineExpose({
|
|||||||
:data-expanded="row.getIsExpanded()"
|
:data-expanded="row.getIsExpanded()"
|
||||||
:role="props.onSelect ? 'button' : undefined"
|
:role="props.onSelect ? 'button' : undefined"
|
||||||
:tabindex="props.onSelect ? 0 : undefined"
|
:tabindex="props.onSelect ? 0 : undefined"
|
||||||
:class="ui.tr({ class: [props.ui?.tr] })"
|
:class="ui.tr({
|
||||||
|
class: [
|
||||||
|
props.ui?.tr,
|
||||||
|
typeof tableApi.options.meta?.class?.tr === 'function' ? tableApi.options.meta.class.tr(row) : tableApi.options.meta?.class?.tr
|
||||||
|
]
|
||||||
|
})"
|
||||||
@click="handleRowSelect(row, $event)"
|
@click="handleRowSelect(row, $event)"
|
||||||
>
|
>
|
||||||
<td
|
<td
|
||||||
v-for="cell in row.getVisibleCells()"
|
v-for="cell in row.getVisibleCells()"
|
||||||
:key="cell.id"
|
:key="cell.id"
|
||||||
:data-pinned="cell.column.getIsPinned()"
|
:data-pinned="cell.column.getIsPinned()"
|
||||||
:class="ui.td({ class: [props.ui?.td, cell.column.columnDef.meta?.class?.td], pinned: !!cell.column.getIsPinned() })"
|
:class="ui.td({
|
||||||
|
class: [
|
||||||
|
props.ui?.td,
|
||||||
|
typeof cell.column.columnDef.meta?.class?.td === 'function' ? cell.column.columnDef.meta.class.td(cell) : cell.column.columnDef.meta?.class?.td
|
||||||
|
],
|
||||||
|
pinned: !!cell.column.getIsPinned()
|
||||||
|
})"
|
||||||
>
|
>
|
||||||
<slot :name="`${cell.column.id}-cell`" v-bind="cell.getContext()">
|
<slot :name="`${cell.column.id}-cell`" v-bind="cell.getContext()">
|
||||||
<FlexRender :render="cell.column.columnDef.cell" :props="cell.getContext()" />
|
<FlexRender :render="cell.column.columnDef.cell" :props="cell.getContext()" />
|
||||||
|
|||||||
Reference in New Issue
Block a user