-
Notifications
You must be signed in to change notification settings - Fork 22
/
Table.tsx
103 lines (97 loc) · 2.84 KB
/
Table.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
import clsx from 'clsx'
import { ReactNode } from 'react'
export type TableItem =
| ReactNode
| {
value: ReactNode
className?: string
}
export type TableProps = {
// The table headers.
headers: TableItem[]
// The table rows. Each row is an array of items.
rows: TableItem[][]
// This makes the first column take up all the remaining space, and the rest
// of the columns will be sized to fit their content. Often the first column
// is a sort of descriptor for the row, and the rest of the columns are
// relevant data. Default is true.
expandFirstColumn?: boolean
// Padding around each cell. Default is 'medium'.
padding?: 'none' | 'small' | 'medium' | 'large'
// If true, the headers will be bolded. Default is true.
boldHeaders?: boolean
// Optional class name to apply to the table container.
className?: string
}
export const Table = ({
headers,
rows,
expandFirstColumn = true,
padding = 'medium',
boldHeaders = true,
className,
}: TableProps) => {
const numColumns = Math.max(headers.length, ...rows.map((row) => row.length))
const paddingClass = {
none: '',
small: 'p-2',
medium: 'p-4',
large: 'p-6',
}[padding]
return (
<div
className={clsx(
'grid-rows-auto grid items-stretch justify-items-stretch',
className
)}
style={{
gridTemplateColumns: [
expandFirstColumn ? '1fr' : 'auto',
...[...Array(numColumns - 1)].map(() => 'auto'),
].join(' '),
}}
>
{headers.map((header, index) => (
<div
key={index}
className={clsx(
'bg-background-primary',
paddingClass,
boldHeaders && 'font-bold',
index === 0 ? 'rounded-tl-md' : 'border-l border-border-secondary',
index === headers.length - 1 && 'rounded-tr-md',
typeof header === 'object' &&
header &&
'className' in header &&
header.className
)}
>
{header}
</div>
))}
{rows.flatMap((row, rowIndex) =>
row.map((item, colIndex) => (
<div
key={`${rowIndex}-${colIndex}`}
className={clsx(
paddingClass,
// Every other row, alternating background.
rowIndex % 2 !== 0 && 'bg-background-tertiary',
rowIndex === rows.length - 1 && colIndex === 0 && 'rounded-bl-md',
rowIndex === rows.length - 1 &&
colIndex === row.length - 1 &&
'rounded-br-md',
colIndex > 0 && 'border-l border-border-secondary',
typeof item === 'object' &&
item &&
'className' in item &&
item.className
)}
>
{item}
</div>
))
)}
</div>
)
}