@proyecto-viviana/ui 0.2.5 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +210 -557
- package/dist/index.js.map +7 -1
- package/dist/index.jsx +6658 -0
- package/dist/index.jsx.map +7 -0
- package/dist/index.ssr.js +42 -399
- package/dist/index.ssr.js.map +7 -1
- package/dist/radio/index.d.ts +27 -12
- package/dist/radio/index.d.ts.map +1 -1
- package/package.json +11 -12
- package/src/alert/index.tsx +0 -48
- package/src/assets/favicon.png +0 -0
- package/src/assets/fire.gif +0 -0
- package/src/autocomplete/index.tsx +0 -313
- package/src/avatar/index.tsx +0 -75
- package/src/badge/index.tsx +0 -43
- package/src/breadcrumbs/index.tsx +0 -207
- package/src/button/Button.tsx +0 -74
- package/src/button/index.ts +0 -2
- package/src/button/types.ts +0 -24
- package/src/calendar/DateField.tsx +0 -200
- package/src/calendar/DatePicker.tsx +0 -298
- package/src/calendar/RangeCalendar.tsx +0 -236
- package/src/calendar/TimeField.tsx +0 -196
- package/src/calendar/index.tsx +0 -223
- package/src/checkbox/index.tsx +0 -257
- package/src/color/index.tsx +0 -687
- package/src/combobox/index.tsx +0 -383
- package/src/components.css +0 -1077
- package/src/custom/calendar-card/index.tsx +0 -66
- package/src/custom/chip/index.tsx +0 -46
- package/src/custom/conversation/index.tsx +0 -105
- package/src/custom/event-card/index.tsx +0 -132
- package/src/custom/header/index.tsx +0 -33
- package/src/custom/lateral-nav/index.tsx +0 -88
- package/src/custom/logo/index.tsx +0 -58
- package/src/custom/nav-header/index.tsx +0 -42
- package/src/custom/page-layout/index.tsx +0 -29
- package/src/custom/profile-card/index.tsx +0 -64
- package/src/custom/project-card/index.tsx +0 -59
- package/src/custom/timeline-item/index.tsx +0 -105
- package/src/dialog/Dialog.tsx +0 -260
- package/src/dialog/index.tsx +0 -3
- package/src/disclosure/index.tsx +0 -307
- package/src/gridlist/index.tsx +0 -403
- package/src/icon/icons/GitHubIcon.tsx +0 -20
- package/src/icon/index.tsx +0 -48
- package/src/index.ts +0 -322
- package/src/landmark/index.tsx +0 -231
- package/src/link/index.tsx +0 -130
- package/src/listbox/index.tsx +0 -231
- package/src/menu/index.tsx +0 -297
- package/src/meter/index.tsx +0 -163
- package/src/numberfield/index.tsx +0 -482
- package/src/popover/index.tsx +0 -260
- package/src/progress-bar/index.tsx +0 -169
- package/src/radio/index.tsx +0 -173
- package/src/searchfield/index.tsx +0 -453
- package/src/select/index.tsx +0 -349
- package/src/separator/index.tsx +0 -141
- package/src/slider/index.tsx +0 -382
- package/src/styles.css +0 -450
- package/src/switch/ToggleSwitch.tsx +0 -112
- package/src/switch/index.tsx +0 -90
- package/src/table/index.tsx +0 -531
- package/src/tabs/index.tsx +0 -273
- package/src/tag-group/index.tsx +0 -240
- package/src/test-utils/index.ts +0 -32
- package/src/textfield/index.tsx +0 -211
- package/src/theme.css +0 -101
- package/src/toast/index.tsx +0 -324
- package/src/toolbar/index.tsx +0 -108
- package/src/tooltip/index.tsx +0 -197
- package/src/tree/index.tsx +0 -494
package/src/table/index.tsx
DELETED
|
@@ -1,531 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Table component for proyecto-viviana-ui
|
|
3
|
-
*
|
|
4
|
-
* Styled table component built on top of solidaria-components.
|
|
5
|
-
* Inspired by Spectrum 2's Table component patterns.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { type JSX, splitProps, createContext, useContext, Show } from 'solid-js'
|
|
9
|
-
import {
|
|
10
|
-
Table as HeadlessTable,
|
|
11
|
-
TableHeader as HeadlessTableHeader,
|
|
12
|
-
TableColumn as HeadlessTableColumn,
|
|
13
|
-
TableBody as HeadlessTableBody,
|
|
14
|
-
TableRow as HeadlessTableRow,
|
|
15
|
-
TableCell as HeadlessTableCell,
|
|
16
|
-
TableSelectionCheckbox as HeadlessTableSelectionCheckbox,
|
|
17
|
-
TableSelectAllCheckbox as HeadlessTableSelectAllCheckbox,
|
|
18
|
-
type TableProps as HeadlessTableProps,
|
|
19
|
-
type TableHeaderProps as HeadlessTableHeaderProps,
|
|
20
|
-
type TableColumnProps as HeadlessTableColumnProps,
|
|
21
|
-
type TableBodyProps as HeadlessTableBodyProps,
|
|
22
|
-
type TableRowProps as HeadlessTableRowProps,
|
|
23
|
-
type TableCellProps as HeadlessTableCellProps,
|
|
24
|
-
type TableRenderProps,
|
|
25
|
-
type TableColumnRenderProps,
|
|
26
|
-
type TableRowRenderProps,
|
|
27
|
-
type TableCellRenderProps,
|
|
28
|
-
} from '@proyecto-viviana/solidaria-components'
|
|
29
|
-
import type { Key, SortDescriptor, ColumnDefinition } from '@proyecto-viviana/solid-stately'
|
|
30
|
-
|
|
31
|
-
// ============================================
|
|
32
|
-
// SIZE CONTEXT
|
|
33
|
-
// ============================================
|
|
34
|
-
|
|
35
|
-
export type TableSize = 'sm' | 'md' | 'lg'
|
|
36
|
-
export type TableVariant = 'default' | 'striped' | 'bordered'
|
|
37
|
-
|
|
38
|
-
interface TableContextValue {
|
|
39
|
-
size: TableSize
|
|
40
|
-
variant: TableVariant
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const TableSizeContext = createContext<TableContextValue>({ size: 'md', variant: 'default' })
|
|
44
|
-
|
|
45
|
-
// ============================================
|
|
46
|
-
// TYPES
|
|
47
|
-
// ============================================
|
|
48
|
-
|
|
49
|
-
export interface TableProps<T extends object>
|
|
50
|
-
extends Omit<HeadlessTableProps<T>, 'class' | 'style' | 'children'> {
|
|
51
|
-
/** The size of the table. */
|
|
52
|
-
size?: TableSize
|
|
53
|
-
/** The visual variant of the table. */
|
|
54
|
-
variant?: TableVariant
|
|
55
|
-
/** Additional CSS class name. */
|
|
56
|
-
class?: string
|
|
57
|
-
/** Title for the table. */
|
|
58
|
-
title?: string
|
|
59
|
-
/** Description for the table. */
|
|
60
|
-
description?: string
|
|
61
|
-
/** Children components (TableHeader, TableBody). */
|
|
62
|
-
children?: JSX.Element | (() => JSX.Element)
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export interface TableHeaderProps extends Omit<HeadlessTableHeaderProps, 'class' | 'style'> {
|
|
66
|
-
/** Additional CSS class name. */
|
|
67
|
-
class?: string
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export interface TableColumnProps extends Omit<HeadlessTableColumnProps, 'class' | 'style'> {
|
|
71
|
-
/** Additional CSS class name. */
|
|
72
|
-
class?: string
|
|
73
|
-
/** Text alignment for the column. */
|
|
74
|
-
align?: 'left' | 'center' | 'right'
|
|
75
|
-
/** Width of the column (CSS value). */
|
|
76
|
-
width?: string
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
export interface TableBodyProps<T> extends Omit<HeadlessTableBodyProps<T>, 'class' | 'style'> {
|
|
80
|
-
/** Additional CSS class name. */
|
|
81
|
-
class?: string
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export interface TableRowProps<T> extends Omit<HeadlessTableRowProps<T>, 'class' | 'style'> {
|
|
85
|
-
/** Additional CSS class name. */
|
|
86
|
-
class?: string
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
export interface TableCellProps extends Omit<HeadlessTableCellProps, 'class' | 'style'> {
|
|
90
|
-
/** Additional CSS class name. */
|
|
91
|
-
class?: string
|
|
92
|
-
/** Text alignment for the cell. */
|
|
93
|
-
align?: 'left' | 'center' | 'right'
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// ============================================
|
|
97
|
-
// STYLES
|
|
98
|
-
// ============================================
|
|
99
|
-
|
|
100
|
-
const sizeStyles = {
|
|
101
|
-
sm: {
|
|
102
|
-
table: 'text-sm',
|
|
103
|
-
headerCell: 'px-3 py-2',
|
|
104
|
-
cell: 'px-3 py-2',
|
|
105
|
-
checkbox: 'w-4 h-4',
|
|
106
|
-
},
|
|
107
|
-
md: {
|
|
108
|
-
table: 'text-base',
|
|
109
|
-
headerCell: 'px-4 py-3',
|
|
110
|
-
cell: 'px-4 py-3',
|
|
111
|
-
checkbox: 'w-5 h-5',
|
|
112
|
-
},
|
|
113
|
-
lg: {
|
|
114
|
-
table: 'text-lg',
|
|
115
|
-
headerCell: 'px-5 py-4',
|
|
116
|
-
cell: 'px-5 py-4',
|
|
117
|
-
checkbox: 'w-6 h-6',
|
|
118
|
-
},
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const variantStyles = {
|
|
122
|
-
default: {
|
|
123
|
-
wrapper: 'rounded-lg border border-bg-300 overflow-hidden',
|
|
124
|
-
header: 'bg-bg-300 border-b border-bg-400',
|
|
125
|
-
row: '',
|
|
126
|
-
rowHover: 'hover:bg-bg-200/50',
|
|
127
|
-
rowSelected: 'bg-accent/10',
|
|
128
|
-
},
|
|
129
|
-
striped: {
|
|
130
|
-
wrapper: 'rounded-lg border border-bg-300 overflow-hidden',
|
|
131
|
-
header: 'bg-bg-300 border-b border-bg-400',
|
|
132
|
-
row: 'even:bg-bg-200/30',
|
|
133
|
-
rowHover: 'hover:bg-bg-200/50',
|
|
134
|
-
rowSelected: 'bg-accent/10',
|
|
135
|
-
},
|
|
136
|
-
bordered: {
|
|
137
|
-
wrapper: 'rounded-lg border-2 border-bg-400 overflow-hidden',
|
|
138
|
-
header: 'bg-bg-300 border-b-2 border-bg-400',
|
|
139
|
-
row: 'border-b border-bg-300 last:border-b-0',
|
|
140
|
-
rowHover: 'hover:bg-bg-200/50',
|
|
141
|
-
rowSelected: 'bg-accent/10',
|
|
142
|
-
},
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
const alignStyles = {
|
|
146
|
-
left: 'text-left',
|
|
147
|
-
center: 'text-center',
|
|
148
|
-
right: 'text-right',
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// ============================================
|
|
152
|
-
// TABLE COMPONENT
|
|
153
|
-
// ============================================
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* A table displays data in rows and columns and enables a user to navigate its contents
|
|
157
|
-
* via directional navigation keys, and optionally supports row selection and sorting.
|
|
158
|
-
*
|
|
159
|
-
* Built on solidaria-components Table for full accessibility support.
|
|
160
|
-
*
|
|
161
|
-
* @example
|
|
162
|
-
* ```tsx
|
|
163
|
-
* const columns = [
|
|
164
|
-
* { key: 'name', name: 'Name' },
|
|
165
|
-
* { key: 'role', name: 'Role' },
|
|
166
|
-
* { key: 'status', name: 'Status' },
|
|
167
|
-
* ]
|
|
168
|
-
*
|
|
169
|
-
* const rows = [
|
|
170
|
-
* { id: '1', name: 'John', role: 'Developer', status: 'Active' },
|
|
171
|
-
* { id: '2', name: 'Jane', role: 'Designer', status: 'Active' },
|
|
172
|
-
* ]
|
|
173
|
-
*
|
|
174
|
-
* <Table items={rows} columns={columns} selectionMode="multiple">
|
|
175
|
-
* {() => (
|
|
176
|
-
* <>
|
|
177
|
-
* <TableHeader>
|
|
178
|
-
* {() => (
|
|
179
|
-
* <For each={columns}>
|
|
180
|
-
* {(col) => <TableColumn id={col.key}>{col.name}</TableColumn>}
|
|
181
|
-
* </For>
|
|
182
|
-
* )}
|
|
183
|
-
* </TableHeader>
|
|
184
|
-
* <TableBody>
|
|
185
|
-
* {(row) => (
|
|
186
|
-
* <TableRow id={row.id}>
|
|
187
|
-
* {() => (
|
|
188
|
-
* <>
|
|
189
|
-
* <TableCell>{row.name}</TableCell>
|
|
190
|
-
* <TableCell>{row.role}</TableCell>
|
|
191
|
-
* <TableCell>{row.status}</TableCell>
|
|
192
|
-
* </>
|
|
193
|
-
* )}
|
|
194
|
-
* </TableRow>
|
|
195
|
-
* )}
|
|
196
|
-
* </TableBody>
|
|
197
|
-
* </>
|
|
198
|
-
* )}
|
|
199
|
-
* </Table>
|
|
200
|
-
* ```
|
|
201
|
-
*/
|
|
202
|
-
export function Table<T extends object>(props: TableProps<T>): JSX.Element {
|
|
203
|
-
const [local, headlessProps] = splitProps(props, [
|
|
204
|
-
'size',
|
|
205
|
-
'variant',
|
|
206
|
-
'class',
|
|
207
|
-
'title',
|
|
208
|
-
'description',
|
|
209
|
-
])
|
|
210
|
-
|
|
211
|
-
const size = () => local.size ?? 'md'
|
|
212
|
-
const variant = () => local.variant ?? 'default'
|
|
213
|
-
const styles = () => sizeStyles[size()]
|
|
214
|
-
const variantStyle = () => variantStyles[variant()]
|
|
215
|
-
const customClass = local.class ?? ''
|
|
216
|
-
|
|
217
|
-
const getClassName = (renderProps: TableRenderProps): string => {
|
|
218
|
-
const base = 'w-full bg-bg-400'
|
|
219
|
-
const sizeClass = styles().table
|
|
220
|
-
|
|
221
|
-
let stateClass = ''
|
|
222
|
-
if (renderProps.isEmpty) {
|
|
223
|
-
stateClass = ''
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
const focusClass = renderProps.isFocusVisible
|
|
227
|
-
? 'ring-2 ring-accent-300 ring-offset-2 ring-offset-bg-400'
|
|
228
|
-
: ''
|
|
229
|
-
|
|
230
|
-
return [base, sizeClass, stateClass, focusClass, customClass].filter(Boolean).join(' ')
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
const contextValue = () => ({ size: size(), variant: variant() })
|
|
234
|
-
|
|
235
|
-
return (
|
|
236
|
-
<TableSizeContext.Provider value={contextValue()}>
|
|
237
|
-
<div class="flex flex-col gap-2">
|
|
238
|
-
<Show when={local.title}>
|
|
239
|
-
<h3 class="text-lg font-semibold text-primary-100">{local.title}</h3>
|
|
240
|
-
</Show>
|
|
241
|
-
<Show when={local.description}>
|
|
242
|
-
<p class="text-sm text-primary-400">{local.description}</p>
|
|
243
|
-
</Show>
|
|
244
|
-
<div class={variantStyle().wrapper}>
|
|
245
|
-
<HeadlessTable {...headlessProps} class={getClassName}>
|
|
246
|
-
{props.children}
|
|
247
|
-
</HeadlessTable>
|
|
248
|
-
</div>
|
|
249
|
-
</div>
|
|
250
|
-
</TableSizeContext.Provider>
|
|
251
|
-
)
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
// ============================================
|
|
255
|
-
// TABLE HEADER COMPONENT
|
|
256
|
-
// ============================================
|
|
257
|
-
|
|
258
|
-
/**
|
|
259
|
-
* A header row in a table containing column headers.
|
|
260
|
-
*/
|
|
261
|
-
export function TableHeader(props: TableHeaderProps): JSX.Element {
|
|
262
|
-
const [local, headlessProps] = splitProps(props, ['class'])
|
|
263
|
-
const context = useContext(TableSizeContext)
|
|
264
|
-
const variantStyle = variantStyles[context.variant]
|
|
265
|
-
const customClass = local.class ?? ''
|
|
266
|
-
|
|
267
|
-
const className = [variantStyle.header, customClass].filter(Boolean).join(' ')
|
|
268
|
-
|
|
269
|
-
return (
|
|
270
|
-
<HeadlessTableHeader {...headlessProps} class={className}>
|
|
271
|
-
{props.children}
|
|
272
|
-
</HeadlessTableHeader>
|
|
273
|
-
)
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
// ============================================
|
|
277
|
-
// TABLE COLUMN COMPONENT
|
|
278
|
-
// ============================================
|
|
279
|
-
|
|
280
|
-
/**
|
|
281
|
-
* A column header in a table.
|
|
282
|
-
*/
|
|
283
|
-
export function TableColumn(props: TableColumnProps): JSX.Element {
|
|
284
|
-
const [local, headlessProps] = splitProps(props, ['class', 'align', 'width'])
|
|
285
|
-
const context = useContext(TableSizeContext)
|
|
286
|
-
const sizeStyle = sizeStyles[context.size]
|
|
287
|
-
const customClass = local.class ?? ''
|
|
288
|
-
|
|
289
|
-
const getClassName = (renderProps: TableColumnRenderProps): string => {
|
|
290
|
-
const base = 'font-semibold text-primary-200 select-none'
|
|
291
|
-
const sizeClass = sizeStyle.headerCell
|
|
292
|
-
const alignClass = alignStyles[local.align ?? 'left']
|
|
293
|
-
|
|
294
|
-
let sortClass = ''
|
|
295
|
-
if (renderProps.isSortable) {
|
|
296
|
-
sortClass = 'cursor-pointer'
|
|
297
|
-
if (renderProps.isHovered) {
|
|
298
|
-
sortClass += ' text-primary-100'
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
const focusClass = renderProps.isFocusVisible
|
|
303
|
-
? 'ring-2 ring-inset ring-accent-300'
|
|
304
|
-
: ''
|
|
305
|
-
|
|
306
|
-
return [base, sizeClass, alignClass, sortClass, focusClass, customClass].filter(Boolean).join(' ')
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
const getStyle = (): JSX.CSSProperties | undefined => {
|
|
310
|
-
if (local.width) {
|
|
311
|
-
return { width: local.width }
|
|
312
|
-
}
|
|
313
|
-
return undefined
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
return (
|
|
317
|
-
<HeadlessTableColumn {...headlessProps} class={getClassName} style={getStyle()}>
|
|
318
|
-
{(renderProps: TableColumnRenderProps) => (
|
|
319
|
-
<div class="flex items-center gap-2">
|
|
320
|
-
<span class="flex-1">
|
|
321
|
-
{typeof props.children === 'function'
|
|
322
|
-
? props.children(renderProps)
|
|
323
|
-
: props.children}
|
|
324
|
-
</span>
|
|
325
|
-
<Show when={renderProps.isSortable && renderProps.sortDirection}>
|
|
326
|
-
<SortIcon direction={renderProps.sortDirection!} class="w-4 h-4" />
|
|
327
|
-
</Show>
|
|
328
|
-
</div>
|
|
329
|
-
)}
|
|
330
|
-
</HeadlessTableColumn>
|
|
331
|
-
)
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
// ============================================
|
|
335
|
-
// TABLE BODY COMPONENT
|
|
336
|
-
// ============================================
|
|
337
|
-
|
|
338
|
-
/**
|
|
339
|
-
* The body of a table containing data rows.
|
|
340
|
-
*/
|
|
341
|
-
export function TableBody<T extends object>(props: TableBodyProps<T>): JSX.Element {
|
|
342
|
-
const [local, headlessProps] = splitProps(props, ['class', 'renderEmptyState'])
|
|
343
|
-
const customClass = local.class ?? ''
|
|
344
|
-
|
|
345
|
-
const defaultEmptyState = () => (
|
|
346
|
-
<tr>
|
|
347
|
-
<td colSpan={100} class="py-8 text-center text-primary-400">
|
|
348
|
-
<div class="flex flex-col items-center gap-2">
|
|
349
|
-
<EmptyIcon class="w-12 h-12 text-primary-500" />
|
|
350
|
-
<span>No data available</span>
|
|
351
|
-
</div>
|
|
352
|
-
</td>
|
|
353
|
-
</tr>
|
|
354
|
-
)
|
|
355
|
-
|
|
356
|
-
return (
|
|
357
|
-
<HeadlessTableBody
|
|
358
|
-
{...headlessProps}
|
|
359
|
-
class={customClass}
|
|
360
|
-
renderEmptyState={local.renderEmptyState ?? defaultEmptyState}
|
|
361
|
-
>
|
|
362
|
-
{props.children}
|
|
363
|
-
</HeadlessTableBody>
|
|
364
|
-
)
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
// ============================================
|
|
368
|
-
// TABLE ROW COMPONENT
|
|
369
|
-
// ============================================
|
|
370
|
-
|
|
371
|
-
/**
|
|
372
|
-
* A row in a table.
|
|
373
|
-
*/
|
|
374
|
-
export function TableRow<T extends object>(props: TableRowProps<T>): JSX.Element {
|
|
375
|
-
const [local, headlessProps] = splitProps(props, ['class'])
|
|
376
|
-
const context = useContext(TableSizeContext)
|
|
377
|
-
const variantStyle = variantStyles[context.variant]
|
|
378
|
-
const customClass = local.class ?? ''
|
|
379
|
-
|
|
380
|
-
const getClassName = (renderProps: TableRowRenderProps): string => {
|
|
381
|
-
const base = 'transition-colors duration-150 outline-none'
|
|
382
|
-
const variantClass = variantStyle.row
|
|
383
|
-
|
|
384
|
-
let stateClass = ''
|
|
385
|
-
if (renderProps.isDisabled) {
|
|
386
|
-
stateClass = 'opacity-50 cursor-not-allowed'
|
|
387
|
-
} else if (renderProps.isSelected) {
|
|
388
|
-
stateClass = variantStyle.rowSelected
|
|
389
|
-
} else if (renderProps.isHovered) {
|
|
390
|
-
stateClass = variantStyle.rowHover
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
const focusClass = renderProps.isFocusVisible
|
|
394
|
-
? 'ring-2 ring-inset ring-accent-300'
|
|
395
|
-
: ''
|
|
396
|
-
|
|
397
|
-
const pressedClass = renderProps.isPressed ? 'bg-bg-200/70' : ''
|
|
398
|
-
|
|
399
|
-
return [base, variantClass, stateClass, focusClass, pressedClass, customClass]
|
|
400
|
-
.filter(Boolean)
|
|
401
|
-
.join(' ')
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
return (
|
|
405
|
-
<HeadlessTableRow {...headlessProps} class={getClassName}>
|
|
406
|
-
{props.children}
|
|
407
|
-
</HeadlessTableRow>
|
|
408
|
-
)
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
// ============================================
|
|
412
|
-
// TABLE CELL COMPONENT
|
|
413
|
-
// ============================================
|
|
414
|
-
|
|
415
|
-
/**
|
|
416
|
-
* A cell in a table row.
|
|
417
|
-
*/
|
|
418
|
-
export function TableCell(props: TableCellProps): JSX.Element {
|
|
419
|
-
const [local, headlessProps] = splitProps(props, ['class', 'align'])
|
|
420
|
-
const context = useContext(TableSizeContext)
|
|
421
|
-
const sizeStyle = sizeStyles[context.size]
|
|
422
|
-
const customClass = local.class ?? ''
|
|
423
|
-
|
|
424
|
-
const getClassName = (renderProps: TableCellRenderProps): string => {
|
|
425
|
-
const base = 'text-primary-200'
|
|
426
|
-
const sizeClass = sizeStyle.cell
|
|
427
|
-
const alignClass = alignStyles[local.align ?? 'left']
|
|
428
|
-
|
|
429
|
-
const focusClass = renderProps.isFocusVisible
|
|
430
|
-
? 'ring-2 ring-inset ring-accent-300'
|
|
431
|
-
: ''
|
|
432
|
-
|
|
433
|
-
return [base, sizeClass, alignClass, focusClass, customClass].filter(Boolean).join(' ')
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
return (
|
|
437
|
-
<HeadlessTableCell {...headlessProps} class={getClassName}>
|
|
438
|
-
{props.children}
|
|
439
|
-
</HeadlessTableCell>
|
|
440
|
-
)
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
// ============================================
|
|
444
|
-
// TABLE SELECTION CHECKBOX COMPONENT
|
|
445
|
-
// ============================================
|
|
446
|
-
|
|
447
|
-
/**
|
|
448
|
-
* A styled checkbox cell for row selection.
|
|
449
|
-
*/
|
|
450
|
-
export function TableSelectionCheckbox(props: { rowKey: Key }): JSX.Element {
|
|
451
|
-
const context = useContext(TableSizeContext)
|
|
452
|
-
const sizeStyle = sizeStyles[context.size]
|
|
453
|
-
const checkboxClass = `${sizeStyle.checkbox} rounded border-2 border-primary-500 bg-bg-400 text-accent cursor-pointer checked:bg-accent checked:border-accent focus:ring-2 focus:ring-accent-300 focus:ring-offset-1 focus:ring-offset-bg-400`
|
|
454
|
-
|
|
455
|
-
return (
|
|
456
|
-
<td class={`${sizeStyle.cell} w-px`}>
|
|
457
|
-
<span class={checkboxClass}>
|
|
458
|
-
<HeadlessTableSelectionCheckbox rowKey={props.rowKey} />
|
|
459
|
-
</span>
|
|
460
|
-
</td>
|
|
461
|
-
)
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
/**
|
|
465
|
-
* A styled checkbox for select-all functionality.
|
|
466
|
-
*/
|
|
467
|
-
export function TableSelectAllCheckbox(): JSX.Element {
|
|
468
|
-
const context = useContext(TableSizeContext)
|
|
469
|
-
const sizeStyle = sizeStyles[context.size]
|
|
470
|
-
const checkboxClass = `${sizeStyle.checkbox} rounded border-2 border-primary-500 bg-bg-400 text-accent cursor-pointer checked:bg-accent checked:border-accent focus:ring-2 focus:ring-accent-300 focus:ring-offset-1 focus:ring-offset-bg-400`
|
|
471
|
-
|
|
472
|
-
return (
|
|
473
|
-
<th class={`${sizeStyle.headerCell} w-px`}>
|
|
474
|
-
<span class={checkboxClass}>
|
|
475
|
-
<HeadlessTableSelectAllCheckbox />
|
|
476
|
-
</span>
|
|
477
|
-
</th>
|
|
478
|
-
)
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
// ============================================
|
|
482
|
-
// ICONS
|
|
483
|
-
// ============================================
|
|
484
|
-
|
|
485
|
-
function SortIcon(props: { direction: 'ascending' | 'descending'; class?: string }): JSX.Element {
|
|
486
|
-
return (
|
|
487
|
-
<svg
|
|
488
|
-
class={props.class}
|
|
489
|
-
fill="none"
|
|
490
|
-
viewBox="0 0 24 24"
|
|
491
|
-
stroke="currentColor"
|
|
492
|
-
stroke-width="2"
|
|
493
|
-
>
|
|
494
|
-
{props.direction === 'ascending' ? (
|
|
495
|
-
<path stroke-linecap="round" stroke-linejoin="round" d="M5 15l7-7 7 7" />
|
|
496
|
-
) : (
|
|
497
|
-
<path stroke-linecap="round" stroke-linejoin="round" d="M19 9l-7 7-7-7" />
|
|
498
|
-
)}
|
|
499
|
-
</svg>
|
|
500
|
-
)
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
function EmptyIcon(props: { class?: string }): JSX.Element {
|
|
504
|
-
return (
|
|
505
|
-
<svg
|
|
506
|
-
class={props.class}
|
|
507
|
-
fill="none"
|
|
508
|
-
viewBox="0 0 24 24"
|
|
509
|
-
stroke="currentColor"
|
|
510
|
-
stroke-width="1.5"
|
|
511
|
-
>
|
|
512
|
-
<path
|
|
513
|
-
stroke-linecap="round"
|
|
514
|
-
stroke-linejoin="round"
|
|
515
|
-
d="M20 13V6a2 2 0 00-2-2H6a2 2 0 00-2 2v7m16 0v5a2 2 0 01-2 2H6a2 2 0 01-2-2v-5m16 0h-2.586a1 1 0 00-.707.293l-2.414 2.414a1 1 0 01-.707.293h-3.172a1 1 0 01-.707-.293l-2.414-2.414A1 1 0 006.586 13H4"
|
|
516
|
-
/>
|
|
517
|
-
</svg>
|
|
518
|
-
)
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
// Attach sub-components for convenience
|
|
522
|
-
Table.Header = TableHeader
|
|
523
|
-
Table.Column = TableColumn
|
|
524
|
-
Table.Body = TableBody
|
|
525
|
-
Table.Row = TableRow
|
|
526
|
-
Table.Cell = TableCell
|
|
527
|
-
Table.SelectionCheckbox = TableSelectionCheckbox
|
|
528
|
-
Table.SelectAllCheckbox = TableSelectAllCheckbox
|
|
529
|
-
|
|
530
|
-
// Re-export types for convenience
|
|
531
|
-
export type { Key, SortDescriptor, ColumnDefinition }
|