@fragments-sdk/ui 0.9.4 → 0.9.6

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.
Files changed (126) hide show
  1. package/dist/assets/ui.css +443 -247
  2. package/dist/blocks/components/index.d.ts +0 -2
  3. package/dist/blocks/components/index.d.ts.map +1 -1
  4. package/dist/codeblock.cjs +187 -184
  5. package/dist/codeblock.cjs.map +1 -1
  6. package/dist/codeblock.js +183 -180
  7. package/dist/codeblock.js.map +1 -1
  8. package/dist/components/Box/Box.module.scss.cjs +73 -0
  9. package/dist/components/Box/Box.module.scss.cjs.map +1 -1
  10. package/dist/components/Box/Box.module.scss.js +73 -0
  11. package/dist/components/Box/Box.module.scss.js.map +1 -1
  12. package/dist/components/ButtonGroup/ButtonGroup.module.scss.cjs +6 -0
  13. package/dist/components/ButtonGroup/ButtonGroup.module.scss.cjs.map +1 -1
  14. package/dist/components/ButtonGroup/ButtonGroup.module.scss.js +6 -0
  15. package/dist/components/ButtonGroup/ButtonGroup.module.scss.js.map +1 -1
  16. package/dist/components/CodeBlock/CodeBlock.module.scss.cjs +20 -23
  17. package/dist/components/CodeBlock/CodeBlock.module.scss.cjs.map +1 -1
  18. package/dist/components/CodeBlock/CodeBlock.module.scss.js +20 -23
  19. package/dist/components/CodeBlock/CodeBlock.module.scss.js.map +1 -1
  20. package/dist/components/CodeBlock/index.d.ts +11 -7
  21. package/dist/components/CodeBlock/index.d.ts.map +1 -1
  22. package/dist/components/Combobox/Combobox.module.scss.cjs +15 -15
  23. package/dist/components/Combobox/Combobox.module.scss.js +15 -15
  24. package/dist/components/DataTable/DataTable.module.scss.cjs +84 -0
  25. package/dist/components/DataTable/DataTable.module.scss.cjs.map +1 -0
  26. package/dist/components/DataTable/DataTable.module.scss.js +84 -0
  27. package/dist/components/DataTable/DataTable.module.scss.js.map +1 -0
  28. package/dist/components/DataTable/index.cjs +383 -0
  29. package/dist/components/DataTable/index.cjs.map +1 -0
  30. package/dist/components/DataTable/index.d.ts +78 -0
  31. package/dist/components/DataTable/index.d.ts.map +1 -0
  32. package/dist/components/DataTable/index.js +366 -0
  33. package/dist/components/DataTable/index.js.map +1 -0
  34. package/dist/components/Drawer/Drawer.module.scss.cjs +9 -0
  35. package/dist/components/Drawer/Drawer.module.scss.cjs.map +1 -1
  36. package/dist/components/Drawer/Drawer.module.scss.js +9 -0
  37. package/dist/components/Drawer/Drawer.module.scss.js.map +1 -1
  38. package/dist/components/Image/Image.module.scss.cjs +12 -0
  39. package/dist/components/Image/Image.module.scss.cjs.map +1 -1
  40. package/dist/components/Image/Image.module.scss.js +12 -0
  41. package/dist/components/Image/Image.module.scss.js.map +1 -1
  42. package/dist/components/Link/Link.module.scss.cjs +3 -0
  43. package/dist/components/Link/Link.module.scss.cjs.map +1 -1
  44. package/dist/components/Link/Link.module.scss.js +3 -0
  45. package/dist/components/Link/Link.module.scss.js.map +1 -1
  46. package/dist/components/List/List.module.scss.cjs +5 -0
  47. package/dist/components/List/List.module.scss.cjs.map +1 -1
  48. package/dist/components/List/List.module.scss.js +5 -0
  49. package/dist/components/List/List.module.scss.js.map +1 -1
  50. package/dist/components/Loading/Loading.module.scss.cjs +5 -0
  51. package/dist/components/Loading/Loading.module.scss.cjs.map +1 -1
  52. package/dist/components/Loading/Loading.module.scss.js +5 -0
  53. package/dist/components/Loading/Loading.module.scss.js.map +1 -1
  54. package/dist/components/Markdown/Markdown.module.scss.cjs +1 -1
  55. package/dist/components/Markdown/Markdown.module.scss.js +1 -1
  56. package/dist/components/Message/Message.module.scss.cjs +22 -16
  57. package/dist/components/Message/Message.module.scss.cjs.map +1 -1
  58. package/dist/components/Message/Message.module.scss.js +22 -16
  59. package/dist/components/Message/Message.module.scss.js.map +1 -1
  60. package/dist/components/Message/index.cjs +5 -3
  61. package/dist/components/Message/index.cjs.map +1 -1
  62. package/dist/components/Message/index.d.ts +5 -1
  63. package/dist/components/Message/index.d.ts.map +1 -1
  64. package/dist/components/Message/index.js +5 -3
  65. package/dist/components/Message/index.js.map +1 -1
  66. package/dist/components/Skeleton/Skeleton.module.scss.cjs +14 -0
  67. package/dist/components/Skeleton/Skeleton.module.scss.cjs.map +1 -1
  68. package/dist/components/Skeleton/Skeleton.module.scss.js +14 -0
  69. package/dist/components/Skeleton/Skeleton.module.scss.js.map +1 -1
  70. package/dist/components/Stack/Stack.module.scss.cjs +14 -0
  71. package/dist/components/Stack/Stack.module.scss.cjs.map +1 -1
  72. package/dist/components/Stack/Stack.module.scss.js +14 -0
  73. package/dist/components/Stack/Stack.module.scss.js.map +1 -1
  74. package/dist/components/Table/Table.module.scss.cjs +21 -36
  75. package/dist/components/Table/Table.module.scss.cjs.map +1 -1
  76. package/dist/components/Table/Table.module.scss.js +21 -36
  77. package/dist/components/Table/Table.module.scss.js.map +1 -1
  78. package/dist/components/Table/index.d.ts +35 -55
  79. package/dist/components/Table/index.d.ts.map +1 -1
  80. package/dist/components/Text/Text.module.scss.cjs +14 -0
  81. package/dist/components/Text/Text.module.scss.cjs.map +1 -1
  82. package/dist/components/Text/Text.module.scss.js +14 -0
  83. package/dist/components/Text/Text.module.scss.js.map +1 -1
  84. package/dist/components/Textarea/Textarea.module.scss.cjs +4 -0
  85. package/dist/components/Textarea/Textarea.module.scss.cjs.map +1 -1
  86. package/dist/components/Textarea/Textarea.module.scss.js +4 -0
  87. package/dist/components/Textarea/Textarea.module.scss.js.map +1 -1
  88. package/dist/components/ToggleGroup/ToggleGroup.module.scss.cjs +5 -0
  89. package/dist/components/ToggleGroup/ToggleGroup.module.scss.cjs.map +1 -1
  90. package/dist/components/ToggleGroup/ToggleGroup.module.scss.js +5 -0
  91. package/dist/components/ToggleGroup/ToggleGroup.module.scss.js.map +1 -1
  92. package/dist/index.cjs +119 -117
  93. package/dist/index.cjs.map +1 -1
  94. package/dist/index.d.ts +2 -1
  95. package/dist/index.d.ts.map +1 -1
  96. package/dist/index.js +3 -1
  97. package/dist/index.js.map +1 -1
  98. package/dist/table.cjs +44 -262
  99. package/dist/table.cjs.map +1 -1
  100. package/dist/table.js +47 -248
  101. package/dist/table.js.map +1 -1
  102. package/fragments.json +1 -1
  103. package/package.json +110 -118
  104. package/src/blocks/components/index.ts +0 -3
  105. package/src/components/CodeBlock/CodeBlock.module.scss +16 -34
  106. package/src/components/CodeBlock/index.tsx +351 -345
  107. package/src/components/Combobox/Combobox.module.scss +13 -9
  108. package/src/components/ConversationList/ConversationList.fragment.tsx +96 -129
  109. package/src/components/DataTable/DataTable.fragment.tsx +754 -0
  110. package/src/components/DataTable/DataTable.module.scss +300 -0
  111. package/src/components/DataTable/DataTable.test.tsx +224 -0
  112. package/src/components/DataTable/index.tsx +533 -0
  113. package/src/components/Message/Message.fragment.tsx +34 -0
  114. package/src/components/Message/Message.module.scss +11 -0
  115. package/src/components/Message/index.tsx +12 -3
  116. package/src/components/Table/Table.fragment.tsx +190 -175
  117. package/src/components/Table/Table.module.scss +15 -88
  118. package/src/components/Table/Table.test.tsx +184 -94
  119. package/src/components/Table/index.tsx +105 -374
  120. package/src/index.ts +15 -4
  121. package/src/tokens/_computed.scss +7 -6
  122. package/src/tokens/_density.scss +87 -47
  123. package/src/tokens/_variables.scss +46 -31
  124. package/dist/blocks/components/DataTable.d.ts +0 -19
  125. package/dist/blocks/components/DataTable.d.ts.map +0 -1
  126. package/src/blocks/components/DataTable.tsx +0 -124
@@ -6,418 +6,149 @@ import '../../styles/globals.scss';
6
6
  import styles from './Table.module.scss';
7
7
 
8
8
  // ============================================
9
- // Types (self-owned — no external dependency for types)
9
+ // Types
10
10
  // ============================================
11
11
 
12
- /** Column definition compatible with @tanstack/react-table */
13
- export type ColumnDef<TData = unknown, TValue = unknown> = {
14
- id?: string;
15
- accessorKey?: string;
16
- accessorFn?: (row: TData) => TValue;
17
- header?: string | ((context: any) => React.ReactNode);
18
- cell?: string | ((context: any) => React.ReactNode);
19
- size?: number;
20
- minSize?: number;
21
- maxSize?: number;
22
- enableSorting?: boolean;
23
- [key: string]: unknown;
24
- };
25
-
26
- export type SortingState = Array<{ id: string; desc: boolean }>;
27
- export type RowSelectionState = Record<string, boolean>;
28
- type OnChangeFn<T> = ((updaterOrValue: T | ((prev: T) => T)) => void);
29
-
30
- export type TableColumn<T> = ColumnDef<T, unknown>;
31
-
32
- // ============================================
33
- // Lazy-loaded dependency (@tanstack/react-table)
34
- // ============================================
35
-
36
- let _useReactTable: any = null;
37
- let _getCoreRowModel: any = null;
38
- let _getSortedRowModel: any = null;
39
- let _flexRender: any = null;
40
- let _tableLoaded = false;
41
- let _tableFailed = false;
42
-
43
- function loadTableDeps() {
44
- if (_tableLoaded) return;
45
- _tableLoaded = true;
46
- try {
47
- // eslint-disable-next-line @typescript-eslint/no-require-imports
48
- const rt = require('@tanstack/react-table');
49
- _useReactTable = rt.useReactTable;
50
- _getCoreRowModel = rt.getCoreRowModel;
51
- _getSortedRowModel = rt.getSortedRowModel;
52
- _flexRender = rt.flexRender;
53
- } catch {
54
- _tableFailed = true;
55
- }
56
- }
57
-
58
- export interface TableProps<T> extends Omit<React.HTMLAttributes<HTMLTableElement>, 'onClick'> {
59
- /** Column definitions */
60
- columns: TableColumn<T>[];
61
- /** Data array */
62
- data: T[];
63
- /** Unique key extractor for each row */
64
- getRowId?: (row: T) => string;
65
- /** Enable sorting */
66
- sortable?: boolean;
67
- /** Controlled sorting state */
68
- sorting?: SortingState;
69
- /** Sorting change handler */
70
- onSortingChange?: OnChangeFn<SortingState>;
71
- /** Enable row selection */
72
- selectable?: boolean;
73
- /** Controlled selection state */
74
- rowSelection?: RowSelectionState;
75
- /** Selection change handler */
76
- onRowSelectionChange?: OnChangeFn<RowSelectionState>;
77
- /** Row click handler */
78
- onRowClick?: (row: T) => void;
79
- /** Empty state message */
80
- emptyMessage?: string;
12
+ export interface TableProps extends React.HTMLAttributes<HTMLTableElement> {
81
13
  /** Size variant */
82
14
  size?: 'sm' | 'md';
83
- /** Visible caption for the table (recommended for accessibility) */
84
- caption?: string;
85
- /** Hide the caption visually but keep it for screen readers */
86
- captionHidden?: boolean;
87
15
  /** Show alternating row backgrounds */
88
16
  striped?: boolean;
89
17
  /** Wrap table in a bordered container */
90
18
  bordered?: boolean;
19
+ children?: React.ReactNode;
91
20
  }
92
21
 
93
- function TableRoot<T>({
94
- columns,
95
- data,
96
- getRowId,
97
- sortable = false,
98
- sorting: controlledSorting,
99
- onSortingChange,
100
- selectable = false,
101
- rowSelection: controlledRowSelection,
102
- onRowSelectionChange,
103
- onRowClick,
104
- emptyMessage = 'No data available',
105
- size = 'md',
106
- className,
107
- caption,
108
- captionHidden = false,
109
- striped = false,
110
- bordered = false,
111
- 'aria-label': ariaLabel,
112
- 'aria-describedby': ariaDescribedBy,
113
- ...htmlProps
114
- }: TableProps<T>) {
115
- loadTableDeps();
116
-
117
- // Internal sorting state when uncontrolled
118
- const [internalSorting, setInternalSorting] = React.useState<SortingState>([]);
119
- const sorting = controlledSorting ?? internalSorting;
120
- const handleSortingChange = onSortingChange ?? setInternalSorting;
22
+ export interface TableRowProps extends React.HTMLAttributes<HTMLTableRowElement> {
23
+ /** Mark row as selected */
24
+ selected?: boolean;
25
+ children?: React.ReactNode;
26
+ }
121
27
 
122
- // Internal selection state when uncontrolled
123
- const [internalRowSelection, setInternalRowSelection] = React.useState<RowSelectionState>({});
124
- const rowSelection = controlledRowSelection ?? internalRowSelection;
125
- const handleRowSelectionChange = onRowSelectionChange ?? setInternalRowSelection;
28
+ export interface TableCellProps extends React.TdHTMLAttributes<HTMLTableCellElement> {
29
+ children?: React.ReactNode;
30
+ }
126
31
 
127
- if (_tableFailed || !_useReactTable) {
128
- if (_tableFailed && process.env.NODE_ENV === 'development') {
129
- console.warn(
130
- '[@fragments-sdk/ui] Table: @tanstack/react-table is not installed. ' +
131
- 'Install it with: npm install @tanstack/react-table'
132
- );
133
- }
134
- return null;
135
- }
32
+ export interface TableHeaderCellProps extends React.ThHTMLAttributes<HTMLTableCellElement> {
33
+ /** Scope for the header cell */
34
+ scope?: string;
35
+ children?: React.ReactNode;
36
+ }
136
37
 
137
- const table = _useReactTable({
138
- data,
139
- columns,
140
- getRowId,
141
- getCoreRowModel: _getCoreRowModel(),
142
- getSortedRowModel: sortable ? _getSortedRowModel() : undefined,
143
- state: {
144
- sorting: sortable ? sorting : undefined,
145
- rowSelection: selectable ? rowSelection : undefined,
146
- },
147
- onSortingChange: sortable ? handleSortingChange : undefined,
148
- onRowSelectionChange: selectable ? handleRowSelectionChange : undefined,
149
- enableRowSelection: selectable,
150
- enableSorting: sortable,
151
- });
38
+ export interface TableCaptionProps extends React.HTMLAttributes<HTMLTableCaptionElement> {
39
+ /** Visually hide the caption (screen readers only) */
40
+ hidden?: boolean;
41
+ children?: React.ReactNode;
42
+ }
152
43
 
153
- const isEmpty = data.length === 0;
44
+ // ============================================
45
+ // Sub-components
46
+ // ============================================
154
47
 
155
- const hasExplicitColumnSizing = React.useMemo(
156
- () =>
157
- columns.some((column) =>
158
- column.size !== undefined ||
159
- column.minSize !== undefined ||
160
- column.maxSize !== undefined
161
- ),
162
- [columns]
48
+ function TableHead({ className, children, ...props }: React.HTMLAttributes<HTMLTableSectionElement>) {
49
+ return (
50
+ <thead className={[styles.thead, className].filter(Boolean).join(' ')} {...props}>
51
+ {children}
52
+ </thead>
163
53
  );
54
+ }
164
55
 
165
- const rootClasses = [
166
- styles.table,
167
- hasExplicitColumnSizing && styles.fixedLayout,
168
- styles[size],
169
- striped && styles.striped,
170
- className,
171
- ]
172
- .filter(Boolean)
173
- .join(' ');
174
-
175
- const getColumnSizeStyle = (
176
- column: {
177
- getSize: () => number;
178
- columnDef: { size?: number; minSize?: number; maxSize?: number };
179
- }
180
- ): React.CSSProperties | undefined => {
181
- const { size, minSize, maxSize } = column.columnDef;
182
- const hasExplicitSize = size !== undefined || minSize !== undefined || maxSize !== undefined;
183
-
184
- if (!hasExplicitSize) {
185
- return undefined;
186
- }
187
-
188
- const resolvedSize = column.getSize();
189
-
190
- return {
191
- width: resolvedSize,
192
- minWidth: minSize ?? resolvedSize,
193
- maxWidth: maxSize ?? resolvedSize,
194
- };
195
- };
196
-
197
- if (isEmpty) {
198
- return (
199
- <div className={styles.emptyState}>
200
- <span className={styles.emptyMessage}>{emptyMessage}</span>
201
- </div>
202
- );
203
- }
204
-
205
- const isInteractiveTarget = (
206
- target: EventTarget | null,
207
- currentTarget: HTMLTableRowElement
208
- ) => {
209
- if (!(target instanceof Element)) return false;
210
-
211
- const interactiveElement = target.closest(
212
- 'button, a, input, select, textarea, [role="button"], [role="link"], [role="checkbox"], [role="switch"]'
213
- );
214
-
215
- return Boolean(interactiveElement && currentTarget.contains(interactiveElement));
216
- };
217
-
56
+ function TableBody({ className, children, ...props }: React.HTMLAttributes<HTMLTableSectionElement>) {
218
57
  return (
219
- <div className={[styles.wrapper, bordered && styles.bordered].filter(Boolean).join(' ')}>
220
- <table
221
- {...htmlProps}
222
- className={rootClasses}
223
- aria-label={ariaLabel}
224
- aria-describedby={ariaDescribedBy}
225
- >
226
- {caption && (
227
- <caption className={captionHidden ? styles.captionHidden : styles.caption}>
228
- {caption}
229
- </caption>
230
- )}
231
- <thead className={styles.thead}>
232
- {table.getHeaderGroups().map((headerGroup: any) => (
233
- <tr key={headerGroup.id} className={styles.headerRow}>
234
- {headerGroup.headers.map((header: any) => {
235
- const canSort = sortable && header.column.getCanSort();
236
- const sortDirection = header.column.getIsSorted();
237
- const toggleSorting = canSort ? header.column.getToggleSortingHandler() : undefined;
238
-
239
- return (
240
- <th
241
- key={header.id}
242
- className={[styles.th, canSort && styles.thSortable].filter(Boolean).join(' ')}
243
- style={getColumnSizeStyle(header.column)}
244
- scope="col"
245
- aria-sort={
246
- sortDirection
247
- ? sortDirection === 'asc'
248
- ? 'ascending'
249
- : 'descending'
250
- : canSort
251
- ? 'none'
252
- : undefined
253
- }
254
- >
255
- {canSort ? (
256
- <button
257
- type="button"
258
- className={styles.sortButton}
259
- onClick={toggleSorting}
260
- >
261
- <span className={styles.headerContent}>
262
- {header.isPlaceholder
263
- ? null
264
- : _flexRender(
265
- header.column.columnDef.header,
266
- header.getContext()
267
- )}
268
- </span>
269
- <span className={styles.sortIndicator} aria-hidden="true">
270
- {sortDirection === 'asc' ? (
271
- <SortAscIcon />
272
- ) : sortDirection === 'desc' ? (
273
- <SortDescIcon />
274
- ) : (
275
- <SortIcon />
276
- )}
277
- </span>
278
- </button>
279
- ) : (
280
- <div className={styles.headerContent}>
281
- {header.isPlaceholder
282
- ? null
283
- : _flexRender(
284
- header.column.columnDef.header,
285
- header.getContext()
286
- )}
287
- </div>
288
- )}
289
- </th>
290
- );
291
- })}
292
- </tr>
293
- ))}
294
- </thead>
295
- <tbody className={styles.tbody}>
296
- {table.getRowModel().rows.map((row: any) => {
297
- const isClickable = !!onRowClick;
298
- const isSelected = selectable ? row.getIsSelected() : false;
299
- const handleRowClick = (event: React.MouseEvent<HTMLTableRowElement>) => {
300
- if (!onRowClick) return;
301
- if (isInteractiveTarget(event.target, event.currentTarget)) return;
302
- onRowClick(row.original);
303
- };
304
-
305
- const handleRowKeyDown = (event: React.KeyboardEvent<HTMLTableRowElement>) => {
306
- if (!onRowClick) return;
307
- if (isInteractiveTarget(event.target, event.currentTarget)) return;
308
- if (event.key === 'Enter' || event.key === ' ') {
309
- event.preventDefault();
310
- onRowClick(row.original);
311
- }
312
- };
58
+ <tbody className={[styles.tbody, className].filter(Boolean).join(' ')} {...props}>
59
+ {children}
60
+ </tbody>
61
+ );
62
+ }
313
63
 
314
- return (
315
- <tr
316
- key={row.id}
317
- className={[
318
- styles.row,
319
- isClickable && styles.clickable,
320
- isSelected && styles.selected,
321
- ]
322
- .filter(Boolean)
323
- .join(' ')}
324
- onClick={isClickable ? handleRowClick : undefined}
325
- onKeyDown={isClickable ? handleRowKeyDown : undefined}
326
- tabIndex={isClickable ? 0 : undefined}
327
- data-selected={isSelected || undefined}
328
- >
329
- {row.getVisibleCells().map((cell: any) => (
330
- <td key={cell.id} className={styles.td} style={getColumnSizeStyle(cell.column)}>
331
- {_flexRender(cell.column.columnDef.cell, cell.getContext())}
332
- </td>
333
- ))}
334
- </tr>
335
- );
336
- })}
337
- </tbody>
338
- </table>
339
- </div>
64
+ function TableFooter({ className, children, ...props }: React.HTMLAttributes<HTMLTableSectionElement>) {
65
+ return (
66
+ <tfoot className={[styles.tfoot, className].filter(Boolean).join(' ')} {...props}>
67
+ {children}
68
+ </tfoot>
340
69
  );
341
70
  }
342
71
 
343
- // Sort icons - minimal and functional
344
- function SortIcon() {
72
+ function TableRow({ className, selected, children, ...props }: TableRowProps) {
345
73
  return (
346
- <svg
347
- width="12"
348
- height="12"
349
- viewBox="0 0 12 12"
350
- fill="none"
351
- xmlns="http://www.w3.org/2000/svg"
352
- aria-hidden="true"
74
+ <tr
75
+ className={[styles.row, selected && styles.selected, className].filter(Boolean).join(' ')}
76
+ data-selected={selected || undefined}
77
+ {...props}
353
78
  >
354
- <path
355
- d="M6 2L8.5 5H3.5L6 2Z"
356
- fill="currentColor"
357
- opacity="0.3"
358
- />
359
- <path
360
- d="M6 10L3.5 7H8.5L6 10Z"
361
- fill="currentColor"
362
- opacity="0.3"
363
- />
364
- </svg>
79
+ {children}
80
+ </tr>
365
81
  );
366
82
  }
367
83
 
368
- function SortAscIcon() {
84
+ function TableCell({ className, children, ...props }: TableCellProps) {
369
85
  return (
370
- <svg
371
- width="12"
372
- height="12"
373
- viewBox="0 0 12 12"
374
- fill="none"
375
- xmlns="http://www.w3.org/2000/svg"
376
- aria-hidden="true"
377
- >
378
- <path d="M6 2L8.5 5H3.5L6 2Z" fill="currentColor" />
379
- </svg>
86
+ <td className={[styles.td, className].filter(Boolean).join(' ')} {...props}>
87
+ {children}
88
+ </td>
380
89
  );
381
90
  }
382
91
 
383
- function SortDescIcon() {
92
+ function TableHeaderCell({ className, scope = 'col', children, ...props }: TableHeaderCellProps) {
384
93
  return (
385
- <svg
386
- width="12"
387
- height="12"
388
- viewBox="0 0 12 12"
389
- fill="none"
390
- xmlns="http://www.w3.org/2000/svg"
391
- aria-hidden="true"
94
+ <th className={[styles.th, className].filter(Boolean).join(' ')} scope={scope} {...props}>
95
+ <div className={styles.headerContent}>{children}</div>
96
+ </th>
97
+ );
98
+ }
99
+
100
+ function TableCaption({ className, hidden: visuallyHidden, children, ...props }: TableCaptionProps) {
101
+ return (
102
+ <caption
103
+ className={[visuallyHidden ? styles.captionHidden : styles.caption, className].filter(Boolean).join(' ')}
104
+ {...props}
392
105
  >
393
- <path d="M6 10L3.5 7H8.5L6 10Z" fill="currentColor" />
394
- </svg>
106
+ {children}
107
+ </caption>
395
108
  );
396
109
  }
397
110
 
398
- // Helper to create simple columns without TanStack's createColumnHelper
399
- export function createColumns<T>(
400
- columns: Array<{
401
- key: string;
402
- header: string;
403
- width?: number;
404
- cell?: (row: T) => React.ReactNode;
405
- }>
406
- ): TableColumn<T>[] {
407
- return columns.map((col) => ({
408
- id: col.key,
409
- accessorKey: col.key,
410
- header: col.header,
411
- size: col.width,
412
- minSize: col.width,
413
- maxSize: col.width,
414
- cell: col.cell
415
- ? ({ row }) => col.cell!(row.original)
416
- : ({ getValue }) => getValue() ?? '--',
417
- }));
111
+ // ============================================
112
+ // Root component
113
+ // ============================================
114
+
115
+ function TableRoot({
116
+ size = 'md',
117
+ striped = false,
118
+ bordered = false,
119
+ className,
120
+ children,
121
+ ...htmlProps
122
+ }: TableProps) {
123
+ const tableClasses = [
124
+ styles.table,
125
+ styles[size],
126
+ striped && styles.striped,
127
+ className,
128
+ ]
129
+ .filter(Boolean)
130
+ .join(' ');
131
+
132
+ return (
133
+ <div className={[styles.wrapper, bordered && styles.bordered].filter(Boolean).join(' ')}>
134
+ <table className={tableClasses} {...htmlProps}>
135
+ {children}
136
+ </table>
137
+ </div>
138
+ );
418
139
  }
419
140
 
141
+ // ============================================
142
+ // Compound export
143
+ // ============================================
144
+
420
145
  export const Table = Object.assign(TableRoot, {
421
146
  Root: TableRoot,
422
- Columns: createColumns,
147
+ Head: TableHead,
148
+ Body: TableBody,
149
+ Footer: TableFooter,
150
+ Row: TableRow,
151
+ Cell: TableCell,
152
+ HeaderCell: TableHeaderCell,
153
+ Caption: TableCaption,
423
154
  });
package/src/index.ts CHANGED
@@ -210,16 +210,27 @@ export {
210
210
  type LoadingScreenProps,
211
211
  } from './components/Loading';
212
212
 
213
- // Table
213
+ // Table (simple semantic HTML table)
214
214
  export {
215
215
  Table,
216
- createColumns,
217
216
  type TableProps,
218
- type TableColumn,
217
+ type TableRowProps,
218
+ type TableCellProps,
219
+ type TableHeaderCellProps,
220
+ type TableCaptionProps,
221
+ } from './components/Table';
222
+
223
+ // DataTable (TanStack-powered data table)
224
+ export {
225
+ DataTable,
226
+ createColumns,
227
+ type DataTableProps,
228
+ type DataTableColumn,
219
229
  type ColumnDef,
220
230
  type SortingState,
221
231
  type RowSelectionState,
222
- } from './components/Table';
232
+ type ExpandedState,
233
+ } from './components/DataTable';
223
234
 
224
235
  // EmptyState
225
236
  export {
@@ -8,12 +8,12 @@
8
8
  //
9
9
  // ============================================
10
10
 
11
- @use 'sass:map';
12
- @use 'seeds' as seeds;
13
- @use 'palettes' as palettes;
14
- @use 'density' as density;
15
- @use 'radius' as radius;
16
- @use 'derive' as derive;
11
+ @use "sass:map";
12
+ @use "seeds" as seeds;
13
+ @use "palettes" as palettes;
14
+ @use "density" as density;
15
+ @use "radius" as radius;
16
+ @use "derive" as derive;
17
17
 
18
18
  // --------------------------------------------
19
19
  // Resolve Seed Values
@@ -60,6 +60,7 @@ $computed-padding-container-sm: map.get($_padding, container-sm);
60
60
  $computed-padding-container-md: map.get($_padding, container-md);
61
61
  $computed-padding-container-lg: map.get($_padding, container-lg);
62
62
  $computed-padding-container-xl: map.get($_padding, container-xl);
63
+ $computed-padding-inline-xs: map.get($_padding, inline-xs);
63
64
  $computed-padding-inline-sm: map.get($_padding, inline-sm);
64
65
  $computed-padding-inline-md: map.get($_padding, inline-md);
65
66
  $computed-padding-inline-lg: map.get($_padding, inline-lg);