@duro-app/ui 0.32.0 → 0.34.0
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/components/Table/FromTanstack.d.ts +45 -0
- package/dist/components/Table/FromTanstack.d.ts.map +1 -0
- package/dist/components/Table/SortChip.d.ts +28 -0
- package/dist/components/Table/SortChip.d.ts.map +1 -0
- package/dist/components/Table/Table.d.ts +49 -7
- package/dist/components/Table/Table.d.ts.map +1 -1
- package/dist/components/Table/Table.stories.d.ts +3 -0
- package/dist/components/Table/Table.stories.d.ts.map +1 -1
- package/dist/components/Table/styles.css.d.ts +62 -5
- package/dist/components/Table/styles.css.d.ts.map +1 -1
- package/dist/components/Table/tanstack-augmentation.d.ts +13 -0
- package/dist/components/Table/tanstack-augmentation.d.ts.map +1 -0
- package/dist/index.css +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2442 -2194
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/components/Table/FromTanstack.tsx +159 -0
- package/src/components/Table/SortChip.tsx +52 -0
- package/src/components/Table/Table.stories.tsx +254 -0
- package/src/components/Table/Table.tsx +259 -50
- package/src/components/Table/styles.css.ts +214 -16
- package/src/components/Table/tanstack-augmentation.ts +28 -0
- package/src/index.ts +5 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
type ReactElement,
|
|
2
3
|
type ReactNode,
|
|
3
4
|
type MutableRefObject,
|
|
4
5
|
createContext,
|
|
@@ -12,6 +13,7 @@ import {styles} from './styles.css'
|
|
|
12
13
|
import {Pagination} from './Pagination'
|
|
13
14
|
import {SortIndicator} from './SortIndicator'
|
|
14
15
|
import {ColumnFilter} from './ColumnFilter'
|
|
16
|
+
import {SortChip} from './SortChip'
|
|
15
17
|
|
|
16
18
|
// --- Types ---
|
|
17
19
|
|
|
@@ -23,6 +25,10 @@ export type TableSize = 'sm' | 'md'
|
|
|
23
25
|
interface TableContextValue {
|
|
24
26
|
variant: TableVariant
|
|
25
27
|
size: TableSize
|
|
28
|
+
responsive: boolean
|
|
29
|
+
/** Header labels indexed by column position. Populated synchronously by
|
|
30
|
+
* extractColumnMeta() during Root render so SSR HTML carries them. */
|
|
31
|
+
labels: ReadonlyArray<string>
|
|
26
32
|
/** Mutable ref: header Row writes inferred template, Root reads it */
|
|
27
33
|
inferredTemplateRef: MutableRefObject<string | null>
|
|
28
34
|
}
|
|
@@ -39,33 +45,95 @@ function useTable() {
|
|
|
39
45
|
|
|
40
46
|
const HeaderContext = createContext(false)
|
|
41
47
|
|
|
42
|
-
// ---
|
|
48
|
+
// --- Dev-only warn registry ---
|
|
49
|
+
//
|
|
50
|
+
// One-shot per warning code per process: long-running dev sessions
|
|
51
|
+
// shouldn't drown the console on every re-render of a misconfigured table.
|
|
52
|
+
const _IS_PROD = typeof process !== 'undefined' && process.env?.NODE_ENV === 'production'
|
|
53
|
+
const _devWarned = new Set<string>()
|
|
54
|
+
function devWarnOnce(code: string, message: string) {
|
|
55
|
+
if (_IS_PROD || _devWarned.has(code)) return
|
|
56
|
+
_devWarned.add(code)
|
|
57
|
+
// eslint-disable-next-line no-console
|
|
58
|
+
console.warn(`[duro-app/ui Table] ${message}`)
|
|
59
|
+
}
|
|
43
60
|
|
|
44
|
-
|
|
61
|
+
// --- Container — owns the @container query target ---
|
|
62
|
+
//
|
|
63
|
+
// @deprecated Root sets up its own container query and accepts `sortChip`
|
|
64
|
+
// / `pagination` as slot props. Container is kept exported as a passthrough
|
|
65
|
+
// so existing call sites continue to work; new code should use Root alone.
|
|
45
66
|
|
|
46
|
-
|
|
67
|
+
export function Container({children}: {children: ReactNode}) {
|
|
68
|
+
return <html.div style={styles.container}>{children}</html.div>
|
|
69
|
+
}
|
|
47
70
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
71
|
+
// --- Synchronous tree walk: widths + labels in document order ---
|
|
72
|
+
//
|
|
73
|
+
// Mirrors the pattern that was previously called extractTemplate(). Walks
|
|
74
|
+
// the JSX tree, finds HeaderCell elements, captures their `width` and
|
|
75
|
+
// `label` props (or extractText(children) fallback). Runs on every Root
|
|
76
|
+
// render — cheap (small N, no DOM) — but worth memoising on `children`
|
|
77
|
+
// reference if profiling flags it.
|
|
78
|
+
|
|
79
|
+
// Shallow string-children extraction. We deliberately do NOT recurse into
|
|
80
|
+
// child elements: an icon, tooltip trigger, or sort indicator nested inside
|
|
81
|
+
// a HeaderCell would otherwise pollute the stack-mode label with its own
|
|
82
|
+
// text content. JSX-only headers must set `label` explicitly.
|
|
83
|
+
function extractText(node: ReactNode): string {
|
|
84
|
+
let out = ''
|
|
85
|
+
Children.forEach(node, (child) => {
|
|
86
|
+
if (typeof child === 'string' || typeof child === 'number') {
|
|
87
|
+
out += String(child)
|
|
88
|
+
}
|
|
89
|
+
})
|
|
90
|
+
return out
|
|
52
91
|
}
|
|
53
92
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
93
|
+
// Unwrap memo(...) / forwardRef(...) wrappers so JSX like
|
|
94
|
+
// `<MemoizedHeaderCell ...>` still identifies as HeaderCell. Both wrappers
|
|
95
|
+
// expose the inner component via a `.type` (memo) or `.render` (forwardRef)
|
|
96
|
+
// property on the element-type descriptor. We walk both fields until we
|
|
97
|
+
// reach a leaf, which is the underlying function/class component.
|
|
98
|
+
function unwrapElementType(t: unknown): unknown {
|
|
99
|
+
let current = t
|
|
100
|
+
// Bounded loop — defensive cap against pathological infinite-nesting.
|
|
101
|
+
for (let i = 0; i < 8 && current && typeof current === 'object'; i++) {
|
|
102
|
+
const next =
|
|
103
|
+
(current as {type?: unknown; render?: unknown}).type ?? (current as {render?: unknown}).render
|
|
104
|
+
if (next == null) break
|
|
105
|
+
current = next
|
|
106
|
+
}
|
|
107
|
+
return current
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function extractColumnMeta(children: ReactNode): {template: string; labels: string[]} {
|
|
59
111
|
const widths: string[] = []
|
|
112
|
+
const labels: string[] = []
|
|
60
113
|
|
|
61
114
|
function walk(node: ReactNode) {
|
|
62
115
|
Children.forEach(node, (child) => {
|
|
63
116
|
if (!isValidElement(child)) return
|
|
64
117
|
const props = child.props as Record<string, any>
|
|
65
|
-
|
|
66
|
-
const displayName =
|
|
67
|
-
|
|
118
|
+
const unwrappedType = unwrapElementType(child.type)
|
|
119
|
+
const displayName =
|
|
120
|
+
(unwrappedType as {name?: string; displayName?: string} | null)?.displayName ||
|
|
121
|
+
(unwrappedType as {name?: string} | null)?.name ||
|
|
122
|
+
''
|
|
123
|
+
if (unwrappedType === HeaderCell || displayName === 'HeaderCell') {
|
|
68
124
|
widths.push(props.width || '1fr')
|
|
125
|
+
const explicit = typeof props.label === 'string' ? props.label : undefined
|
|
126
|
+
const fallback = extractText(props.children).trim()
|
|
127
|
+
const label = explicit ?? fallback
|
|
128
|
+
if (!explicit && fallback === '' && props.children != null) {
|
|
129
|
+
// Children are JSX with no string content — stack mode will render
|
|
130
|
+
// an unlabeled cell. Tell the developer once.
|
|
131
|
+
devWarnOnce(
|
|
132
|
+
'headerCell-missing-label',
|
|
133
|
+
'Table.HeaderCell with JSX children must set `label` for stack-mode rendering.',
|
|
134
|
+
)
|
|
135
|
+
}
|
|
136
|
+
labels.push(label)
|
|
69
137
|
} else if (props.children) {
|
|
70
138
|
walk(props.children)
|
|
71
139
|
}
|
|
@@ -73,33 +141,78 @@ function extractTemplate(children: ReactNode): string {
|
|
|
73
141
|
}
|
|
74
142
|
|
|
75
143
|
walk(children)
|
|
76
|
-
return
|
|
144
|
+
return {template: widths.join(' '), labels}
|
|
77
145
|
}
|
|
78
146
|
|
|
79
|
-
|
|
80
|
-
const inferredTemplateRef = useRef<string | null>(null)
|
|
147
|
+
// --- Root ---
|
|
81
148
|
|
|
82
|
-
|
|
83
|
-
|
|
149
|
+
interface RootProps {
|
|
150
|
+
children: ReactNode
|
|
151
|
+
variant?: TableVariant
|
|
152
|
+
size?: TableSize
|
|
153
|
+
/** Opt out of responsive container-query behavior. Default true. */
|
|
154
|
+
responsive?: boolean
|
|
155
|
+
/**
|
|
156
|
+
* Optional sort UI rendered above the grid. Visible only in stack mode
|
|
157
|
+
* (SortChip carries its own `display: none → inline-flex` rule). Typical
|
|
158
|
+
* value: `<Table.SortChip options={...} value={...} onChange={...} />`.
|
|
159
|
+
*/
|
|
160
|
+
sortChip?: ReactNode
|
|
161
|
+
/**
|
|
162
|
+
* Optional pagination UI rendered below the grid. Typical value:
|
|
163
|
+
* `<Table.Pagination table={tanstackTable} />`.
|
|
164
|
+
*/
|
|
165
|
+
pagination?: ReactNode
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export function Root({
|
|
169
|
+
children,
|
|
170
|
+
variant = 'default',
|
|
171
|
+
size = 'md',
|
|
172
|
+
responsive = true,
|
|
173
|
+
sortChip,
|
|
174
|
+
pagination,
|
|
175
|
+
}: RootProps) {
|
|
176
|
+
const inferredTemplateRef = useRef<string | null>(null)
|
|
177
|
+
const {template, labels} = extractColumnMeta(children)
|
|
84
178
|
if (template) {
|
|
85
179
|
inferredTemplateRef.current = template
|
|
86
180
|
}
|
|
87
181
|
|
|
182
|
+
const grid = (
|
|
183
|
+
<html.div
|
|
184
|
+
role="table"
|
|
185
|
+
style={[
|
|
186
|
+
styles.root,
|
|
187
|
+
template ? styles.gridColumns(template) : undefined,
|
|
188
|
+
responsive && styles.rootResponsive,
|
|
189
|
+
]}
|
|
190
|
+
>
|
|
191
|
+
{children}
|
|
192
|
+
</html.div>
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
// Slots render unconditionally — `responsive=false` still wants its sort/
|
|
196
|
+
// pagination chrome. Only the containerType:inline-size wrapper is
|
|
197
|
+
// conditional, since it only matters when @container queries fire.
|
|
198
|
+
const body = (
|
|
199
|
+
<>
|
|
200
|
+
{sortChip}
|
|
201
|
+
{grid}
|
|
202
|
+
{pagination}
|
|
203
|
+
</>
|
|
204
|
+
)
|
|
205
|
+
|
|
88
206
|
return (
|
|
89
|
-
<TableContext.Provider value={{variant, size, inferredTemplateRef}}>
|
|
90
|
-
<html.div
|
|
91
|
-
role="table"
|
|
92
|
-
style={[styles.root, template ? styles.gridColumns(template) : undefined]}
|
|
93
|
-
>
|
|
94
|
-
{children}
|
|
95
|
-
</html.div>
|
|
207
|
+
<TableContext.Provider value={{variant, size, responsive, labels, inferredTemplateRef}}>
|
|
208
|
+
{responsive ? <html.div style={styles.rootContainer}>{body}</html.div> : body}
|
|
96
209
|
</TableContext.Provider>
|
|
97
210
|
)
|
|
98
211
|
}
|
|
99
212
|
|
|
100
213
|
// --- Header ---
|
|
101
214
|
|
|
102
|
-
function Header({children}: {children: ReactNode}) {
|
|
215
|
+
export function Header({children}: {children: ReactNode}) {
|
|
103
216
|
return (
|
|
104
217
|
<HeaderContext.Provider value={true}>
|
|
105
218
|
<html.div role="rowgroup" style={styles.header}>
|
|
@@ -111,22 +224,24 @@ function Header({children}: {children: ReactNode}) {
|
|
|
111
224
|
|
|
112
225
|
// --- Body ---
|
|
113
226
|
|
|
114
|
-
function Body({children}: {children: ReactNode}) {
|
|
227
|
+
export function Body({children}: {children: ReactNode}) {
|
|
115
228
|
const {variant} = useTable()
|
|
116
|
-
const childArray = Children.toArray(children)
|
|
229
|
+
const childArray = Children.toArray(children) as ReactElement[]
|
|
117
230
|
|
|
118
231
|
return (
|
|
119
232
|
<HeaderContext.Provider value={false}>
|
|
120
233
|
<html.div role="rowgroup" style={styles.body}>
|
|
121
234
|
{childArray.map((child, index) => {
|
|
122
|
-
if (variant
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
235
|
+
if (variant !== 'striped') return child
|
|
236
|
+
// Key the provider by the child's React key (Children.toArray
|
|
237
|
+
// guarantees one) so reordered rows carry their providers along
|
|
238
|
+
// with them. Position is passed as the value because striping is
|
|
239
|
+
// a positional concern even when row identity is stable.
|
|
240
|
+
return (
|
|
241
|
+
<RowIndexContext.Provider key={child.key ?? index} value={index}>
|
|
242
|
+
{child}
|
|
243
|
+
</RowIndexContext.Provider>
|
|
244
|
+
)
|
|
130
245
|
})}
|
|
131
246
|
</html.div>
|
|
132
247
|
</HeaderContext.Provider>
|
|
@@ -136,30 +251,89 @@ function Body({children}: {children: ReactNode}) {
|
|
|
136
251
|
const RowIndexContext = createContext<number>(-1)
|
|
137
252
|
|
|
138
253
|
// --- Row ---
|
|
254
|
+
//
|
|
255
|
+
// Always provides CellIndexContext, regardless of variant. Previously this
|
|
256
|
+
// was only set up for `variant === 'bordered'`, which meant non-bordered
|
|
257
|
+
// tables had every cell reading {index: 0} from the default — fine until
|
|
258
|
+
// we needed to look up labels by column index.
|
|
259
|
+
//
|
|
260
|
+
// Interactive rows: pass `onClick` to make the row a navigation target.
|
|
261
|
+
// The role stays `row` (per ARIA grid pattern) — we don't wrap in an outer
|
|
262
|
+
// element with role=button, which would break the rowgroup → row hierarchy.
|
|
263
|
+
// A click that originates inside an interactive descendant (button, link,
|
|
264
|
+
// input, etc.) is treated as that descendant's click and does not fire
|
|
265
|
+
// onClick — prevents double-fire when a row contains action buttons.
|
|
266
|
+
|
|
267
|
+
interface RowProps {
|
|
268
|
+
children: ReactNode
|
|
269
|
+
/** When set, the row becomes focusable + clickable. */
|
|
270
|
+
onClick?: () => void
|
|
271
|
+
/** Per-row accessible name — required when onClick is set, recommended otherwise. */
|
|
272
|
+
'aria-label'?: string
|
|
273
|
+
}
|
|
139
274
|
|
|
140
|
-
|
|
275
|
+
// Heuristic for "clicking a descendant means the descendant, not the row".
|
|
276
|
+
// Matches the elements the WAI-ARIA grid pattern lists as "widgets" plus the
|
|
277
|
+
// usual native focus-stealers.
|
|
278
|
+
const INTERACTIVE_SELECTOR =
|
|
279
|
+
'button, a, input, select, textarea, [role="button"], [role="link"], [role="checkbox"], [role="menuitem"], [role="switch"], [role="tab"], [contenteditable="true"]'
|
|
280
|
+
|
|
281
|
+
export function Row({children, onClick, 'aria-label': ariaLabel}: RowProps) {
|
|
141
282
|
const {variant} = useTable()
|
|
142
283
|
const isHeader = useContext(HeaderContext)
|
|
143
284
|
const rowIndex = useContext(RowIndexContext)
|
|
144
285
|
const isEvenRow = rowIndex >= 0 && rowIndex % 2 === 1
|
|
145
|
-
const childArray = Children.toArray(children)
|
|
286
|
+
const childArray = Children.toArray(children) as ReactElement[]
|
|
287
|
+
const isClickable = onClick !== undefined && !isHeader
|
|
146
288
|
|
|
147
289
|
return (
|
|
148
290
|
<html.div
|
|
149
291
|
role="row"
|
|
292
|
+
tabIndex={isClickable ? 0 : undefined}
|
|
293
|
+
aria-label={isClickable ? ariaLabel : undefined}
|
|
294
|
+
onClick={
|
|
295
|
+
isClickable
|
|
296
|
+
? (e) => {
|
|
297
|
+
// react-strict-dom's typed click event omits `target`, but the
|
|
298
|
+
// underlying SyntheticEvent still carries it. Cast through so
|
|
299
|
+
// we can detect clicks that originate inside an interactive
|
|
300
|
+
// descendant (action button, link, input) and let them be
|
|
301
|
+
// attributed to that widget instead of the row.
|
|
302
|
+
const target = (e as unknown as {target?: EventTarget | null}).target
|
|
303
|
+
if (target instanceof Element && target.closest(INTERACTIVE_SELECTOR)) {
|
|
304
|
+
return
|
|
305
|
+
}
|
|
306
|
+
onClick()
|
|
307
|
+
}
|
|
308
|
+
: undefined
|
|
309
|
+
}
|
|
310
|
+
onKeyDown={
|
|
311
|
+
isClickable
|
|
312
|
+
? (e) => {
|
|
313
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
314
|
+
onClick()
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
: undefined
|
|
318
|
+
}
|
|
150
319
|
style={[
|
|
151
320
|
styles.row,
|
|
152
321
|
!isHeader && styles.bodyRow,
|
|
153
322
|
!isHeader && variant === 'striped' && isEvenRow && styles.stripedEven,
|
|
323
|
+
isClickable && styles.clickableRow,
|
|
154
324
|
]}
|
|
155
325
|
>
|
|
156
|
-
{
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
326
|
+
{childArray.map((child, index) => (
|
|
327
|
+
// Key by the child's React key (Children.toArray assigns one) so a
|
|
328
|
+
// reordered column carries its CellIndexContext provider along.
|
|
329
|
+
// The positional `index` lives in the provider's value, not its key.
|
|
330
|
+
<CellIndexContext.Provider
|
|
331
|
+
key={child.key ?? index}
|
|
332
|
+
value={{index, total: childArray.length}}
|
|
333
|
+
>
|
|
334
|
+
{child}
|
|
335
|
+
</CellIndexContext.Provider>
|
|
336
|
+
))}
|
|
163
337
|
</html.div>
|
|
164
338
|
)
|
|
165
339
|
}
|
|
@@ -168,16 +342,34 @@ const CellIndexContext = createContext<{index: number; total: number}>({index: 0
|
|
|
168
342
|
|
|
169
343
|
// --- HeaderCell ---
|
|
170
344
|
|
|
171
|
-
function HeaderCell({
|
|
345
|
+
export function HeaderCell({
|
|
172
346
|
children,
|
|
173
347
|
width: _width,
|
|
348
|
+
label: _label,
|
|
349
|
+
isActions,
|
|
174
350
|
'aria-label': ariaLabel,
|
|
175
351
|
}: {
|
|
176
352
|
children?: ReactNode
|
|
177
353
|
/** Column width: CSS value like '40px', '2fr', 'max-content'. Defaults to '1fr'. */
|
|
178
354
|
width?: string
|
|
355
|
+
/** Stack-mode label string. Optional when children is a plain string — the
|
|
356
|
+
* text content is used as the label automatically. Required when children
|
|
357
|
+
* contain JSX (icon + text, sort indicator, etc.). */
|
|
358
|
+
label?: string
|
|
359
|
+
/**
|
|
360
|
+
* @deprecated Has no effect on HeaderCell. Pass `isActions` on the
|
|
361
|
+
* matching `Table.Cell` instead — that's where the stack-mode footer
|
|
362
|
+
* layout actually applies.
|
|
363
|
+
*/
|
|
364
|
+
isActions?: boolean
|
|
179
365
|
'aria-label'?: string
|
|
180
366
|
}) {
|
|
367
|
+
if (isActions === true) {
|
|
368
|
+
devWarnOnce(
|
|
369
|
+
'headerCell-isActions',
|
|
370
|
+
'HeaderCell `isActions` prop has no effect and is deprecated. Pass `isActions` on the matching Table.Cell instead.',
|
|
371
|
+
)
|
|
372
|
+
}
|
|
181
373
|
const {size, variant} = useTable()
|
|
182
374
|
const {index, total} = useContext(CellIndexContext)
|
|
183
375
|
const isLast = variant === 'bordered' && index === total - 1
|
|
@@ -197,13 +389,19 @@ function HeaderCell({
|
|
|
197
389
|
</html.div>
|
|
198
390
|
)
|
|
199
391
|
}
|
|
392
|
+
HeaderCell.displayName = 'HeaderCell'
|
|
200
393
|
|
|
201
394
|
// --- Cell ---
|
|
395
|
+
//
|
|
396
|
+
// Renders the column-header label as a real <html.span>, hidden via
|
|
397
|
+
// container query in non-stack modes. The span is omitted entirely when
|
|
398
|
+
// isActions=true — actions footers don't show a label.
|
|
202
399
|
|
|
203
|
-
function Cell({children}: {children: ReactNode}) {
|
|
204
|
-
const {size, variant} = useTable()
|
|
400
|
+
export function Cell({children, isActions}: {children: ReactNode; isActions?: boolean}) {
|
|
401
|
+
const {size, variant, labels, responsive} = useTable()
|
|
205
402
|
const {index, total} = useContext(CellIndexContext)
|
|
206
403
|
const isLast = variant === 'bordered' && index === total - 1
|
|
404
|
+
const label = labels[index] ?? ''
|
|
207
405
|
|
|
208
406
|
return (
|
|
209
407
|
<html.div
|
|
@@ -213,8 +411,12 @@ function Cell({children}: {children: ReactNode}) {
|
|
|
213
411
|
size === 'sm' ? styles.cellSm : styles.cellMd,
|
|
214
412
|
variant === 'bordered' && styles.borderedCell,
|
|
215
413
|
isLast && styles.borderedCellLast,
|
|
414
|
+
isActions && styles.cellActions,
|
|
216
415
|
]}
|
|
217
416
|
>
|
|
417
|
+
{responsive && !isActions && label !== '' ? (
|
|
418
|
+
<html.span style={styles.cellLabel}>{label}</html.span>
|
|
419
|
+
) : null}
|
|
218
420
|
{children}
|
|
219
421
|
</html.div>
|
|
220
422
|
)
|
|
@@ -222,7 +424,11 @@ function Cell({children}: {children: ReactNode}) {
|
|
|
222
424
|
|
|
223
425
|
// --- Export ---
|
|
224
426
|
|
|
427
|
+
import {FromTanstack} from './FromTanstack'
|
|
428
|
+
|
|
225
429
|
export const Table = {
|
|
430
|
+
/** @deprecated Wrap behaviour is built into Table.Root. Drop this wrapper from new code. */
|
|
431
|
+
Container,
|
|
226
432
|
Root,
|
|
227
433
|
Header,
|
|
228
434
|
Body,
|
|
@@ -232,4 +438,7 @@ export const Table = {
|
|
|
232
438
|
Pagination,
|
|
233
439
|
SortIndicator,
|
|
234
440
|
ColumnFilter,
|
|
441
|
+
SortChip,
|
|
442
|
+
/** Renders a styled Table directly from a TanStack table instance. */
|
|
443
|
+
FromTanstack,
|
|
235
444
|
}
|