Skip to content

Commit 7ef1933

Browse files
feat(Table): add support for colspan and rowspan (#4460)
Co-authored-by: Benjamin Canac <[email protected]>
1 parent d983af9 commit 7ef1933

File tree

1 file changed

+26
-7
lines changed

1 file changed

+26
-7
lines changed

src/runtime/components/Table.vue

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,13 @@ declare module '@tanstack/table-core' {
4949
th?: string | Record<string, string> | ((cell: Header<TData, TValue>) => string | Record<string, string>)
5050
td?: string | Record<string, string> | ((cell: Cell<TData, TValue>) => string | Record<string, string>)
5151
}
52+
colspan?: {
53+
td?: string | ((cell: Cell<TData, TValue>) => string)
54+
}
55+
rowspan?: {
56+
td?: string | ((cell: Cell<TData, TValue>) => string)
57+
}
58+
5259
}
5360
5461
interface TableMeta<TData> {
@@ -376,6 +383,14 @@ function onRowContextmenu(e: Event, row: TableRow<T>) {
376383
}
377384
}
378385
386+
function resolveValue<T, A = undefined>(prop: T | ((arg: A) => T), arg?: A): T | undefined {
387+
if (typeof prop === 'function') {
388+
// @ts-expect-error: TS can't know if prop is a function here
389+
return prop(arg)
390+
}
391+
return prop
392+
}
393+
379394
watch(
380395
() => props.data, () => {
381396
data.value = props.data ? [...props.data] : []
@@ -405,10 +420,11 @@ defineExpose({
405420
:data-pinned="header.column.getIsPinned()"
406421
:scope="header.colSpan > 1 ? 'colgroup' : 'col'"
407422
:colspan="header.colSpan > 1 ? header.colSpan : undefined"
423+
:rowspan="header.rowSpan > 1 ? header.rowSpan : undefined"
408424
:class="ui.th({
409425
class: [
410426
props.ui?.th,
411-
typeof header.column.columnDef.meta?.class?.th === 'function' ? header.column.columnDef.meta.class.th(header) : header.column.columnDef.meta?.class?.th
427+
resolveValue(header.column.columnDef.meta?.class?.th, header)
412428
],
413429
pinned: !!header.column.getIsPinned()
414430
})"
@@ -436,10 +452,10 @@ defineExpose({
436452
:class="ui.tr({
437453
class: [
438454
props.ui?.tr,
439-
typeof tableApi.options.meta?.class?.tr === 'function' ? tableApi.options.meta.class.tr(row) : tableApi.options.meta?.class?.tr
455+
resolveValue(tableApi.options.meta?.class?.tr, row)
440456
]
441457
})"
442-
:style="typeof tableApi.options.meta?.style?.tr === 'function' ? tableApi.options.meta?.style?.tr(row) : tableApi.options.meta?.style?.tr"
458+
:style="resolveValue(tableApi.options.meta?.style?.tr, row)"
443459
@click="onRowSelect($event, row)"
444460
@pointerenter="onRowHover($event, row)"
445461
@pointerleave="onRowHover($event, null)"
@@ -449,14 +465,16 @@ defineExpose({
449465
v-for="cell in row.getVisibleCells()"
450466
:key="cell.id"
451467
:data-pinned="cell.column.getIsPinned()"
468+
:colspan="resolveValue(cell.column.columnDef.meta?.colspan?.td, cell)"
469+
:rowspan="resolveValue(cell.column.columnDef.meta?.rowspan?.td, cell)"
452470
:class="ui.td({
453471
class: [
454472
props.ui?.td,
455-
typeof cell.column.columnDef.meta?.class?.td === 'function' ? cell.column.columnDef.meta.class.td(cell) : cell.column.columnDef.meta?.class?.td
473+
resolveValue(cell.column.columnDef.meta?.class?.td, cell)
456474
],
457475
pinned: !!cell.column.getIsPinned()
458476
})"
459-
:style="typeof cell.column.columnDef.meta?.style?.td === 'function' ? cell.column.columnDef.meta.style.td(cell) : cell.column.columnDef.meta?.style?.td"
477+
:style="resolveValue(cell.column.columnDef.meta?.style?.td, cell)"
460478
>
461479
<slot :name="`${cell.column.id}-cell`" v-bind="cell.getContext()">
462480
<FlexRender :render="cell.column.columnDef.cell" :props="cell.getContext()" />
@@ -497,14 +515,15 @@ defineExpose({
497515
:key="header.id"
498516
:data-pinned="header.column.getIsPinned()"
499517
:colspan="header.colSpan > 1 ? header.colSpan : undefined"
518+
:rowspan="header.rowSpan > 1 ? header.rowSpan : undefined"
500519
:class="ui.th({
501520
class: [
502521
props.ui?.th,
503-
typeof header.column.columnDef.meta?.class?.th === 'function' ? header.column.columnDef.meta.class.th(header) : header.column.columnDef.meta?.class?.th
522+
resolveValue(header.column.columnDef.meta?.class?.th, header)
504523
],
505524
pinned: !!header.column.getIsPinned()
506525
})"
507-
:style="typeof header.column.columnDef.meta?.style?.th === 'function' ? header.column.columnDef.meta.style.th(header) : header.column.columnDef.meta?.style?.th"
526+
:style="resolveValue(header.column.columnDef.meta?.style?.th, header)"
508527
>
509528
<slot :name="`${header.id}-footer`" v-bind="header.getContext()">
510529
<FlexRender v-if="!header.isPlaceholder" :render="header.column.columnDef.footer" :props="header.getContext()" />

0 commit comments

Comments
 (0)