@lovett/ui 0.0.2 → 0.0.4
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/package.json +1 -1
- package/src/badge.tsx +28 -8
- package/src/data-grid/data-grid.tsx +1 -0
- package/src/data-grid/index.ts +1 -0
- package/src/data-grid/sortable-parts.tsx +26 -6
- package/src/data-grid/sticky.ts +4 -3
- package/src/data-grid/table-body.tsx +20 -2
- package/src/data-grid/table-elements.tsx +6 -0
- package/src/data-grid/table-header.tsx +12 -4
- package/src/data-grid/table-summary-footer.tsx +9 -4
- package/src/data-grid/table-view.tsx +10 -1
- package/src/data-grid/toolbar.tsx +44 -0
- package/src/data-grid/use-grid-columns.ts +23 -1
- package/src/index.ts +2 -0
package/package.json
CHANGED
package/src/badge.tsx
CHANGED
|
@@ -17,6 +17,8 @@
|
|
|
17
17
|
|
|
18
18
|
import type { ReactNode } from 'react'
|
|
19
19
|
|
|
20
|
+
import { cn } from './lib/utils'
|
|
21
|
+
|
|
20
22
|
export type BadgeTone =
|
|
21
23
|
| 'neutral'
|
|
22
24
|
| 'accent'
|
|
@@ -57,33 +59,51 @@ export interface BadgeProps {
|
|
|
57
59
|
children: ReactNode
|
|
58
60
|
/** Optional leading icon — sized 12-14px expected. */
|
|
59
61
|
icon?: ReactNode
|
|
60
|
-
/**
|
|
61
|
-
|
|
62
|
-
|
|
62
|
+
/** Leading status dot in the tone color (gray-ui chip style). Ignored
|
|
63
|
+
* when `icon` is provided. */
|
|
64
|
+
dot?: boolean
|
|
65
|
+
/** Size variant. `sm` = compact (10px), `md` = default (11px),
|
|
66
|
+
* `lg` = roomier category-chip (12px, taller). */
|
|
67
|
+
size?: 'sm' | 'md' | 'lg'
|
|
68
|
+
/** Extra classes merged onto the outer span (no longer replaces base). */
|
|
63
69
|
className?: string
|
|
64
70
|
}
|
|
65
71
|
|
|
72
|
+
const SIZE_CLASS: Record<NonNullable<BadgeProps['size']>, string> = {
|
|
73
|
+
sm: 'text-[10px] px-1.5 py-0.5',
|
|
74
|
+
md: 'text-[11px] px-2 py-0.5',
|
|
75
|
+
lg: 'text-xs px-2.5 py-1',
|
|
76
|
+
}
|
|
77
|
+
|
|
66
78
|
export function Badge({
|
|
67
79
|
tone,
|
|
68
80
|
children,
|
|
69
81
|
icon,
|
|
82
|
+
dot = false,
|
|
70
83
|
size = 'md',
|
|
71
84
|
className,
|
|
72
85
|
}: BadgeProps) {
|
|
73
86
|
const { bg, color } = TONE_STYLE[tone]
|
|
74
|
-
const sizeClass = size === 'sm' ? 'text-[10px] px-1.5 py-0.5' : 'text-[11px] px-2 py-0.5'
|
|
75
87
|
return (
|
|
76
88
|
<span
|
|
77
|
-
className={
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
89
|
+
className={cn(
|
|
90
|
+
'inline-flex w-fit items-center gap-1.5 font-medium whitespace-nowrap',
|
|
91
|
+
SIZE_CLASS[size],
|
|
92
|
+
className,
|
|
93
|
+
)}
|
|
81
94
|
style={{
|
|
82
95
|
background: bg,
|
|
83
96
|
color,
|
|
84
97
|
borderRadius: 'var(--radius-full)',
|
|
85
98
|
}}
|
|
86
99
|
>
|
|
100
|
+
{dot && !icon ? (
|
|
101
|
+
<span
|
|
102
|
+
aria-hidden
|
|
103
|
+
className="size-1.5 shrink-0 rounded-full"
|
|
104
|
+
style={{ background: 'currentColor' }}
|
|
105
|
+
/>
|
|
106
|
+
) : null}
|
|
87
107
|
{icon && <span className="flex-shrink-0">{icon}</span>}
|
|
88
108
|
{children}
|
|
89
109
|
</span>
|
|
@@ -415,6 +415,7 @@ export function DataGrid<Row extends DataGridRowBase, ColumnId extends string>({
|
|
|
415
415
|
stickySummaryFooter={stickySummaryFooter}
|
|
416
416
|
stickyHeader={stickyHeader}
|
|
417
417
|
fillWidth={fillWidth}
|
|
418
|
+
fillHeight={fillAvailableHeight}
|
|
418
419
|
scrollEdges={scrollEdges}
|
|
419
420
|
tableContainerClassName={tableContainerClassName}
|
|
420
421
|
isEmptyValue={isEmptyValue}
|
package/src/data-grid/index.ts
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
* local table-elements (inlined per DEV-1)
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
+
import { useRef } from 'react'
|
|
18
19
|
import type {
|
|
19
20
|
CSSProperties,
|
|
20
21
|
KeyboardEvent as ReactKeyboardEvent,
|
|
@@ -138,6 +139,10 @@ export function SortableHeaderCell<ColumnId extends string>({
|
|
|
138
139
|
}: SortableHeaderCellProps<ColumnId>) {
|
|
139
140
|
// ADR-027 — column sortability: explicit `sortable: false` opts out;
|
|
140
141
|
// missing `onSortChange` also disables (no parent handler).
|
|
142
|
+
// Suppress the sort click that the browser fires after a resize
|
|
143
|
+
// interaction (drag OR a stray click on the resize handle), so resizing
|
|
144
|
+
// never accidentally toggles the sort.
|
|
145
|
+
const justResizedRef = useRef(false)
|
|
141
146
|
const isSortable =
|
|
142
147
|
column.sortable !== false && typeof onSortChange === 'function'
|
|
143
148
|
const ariaSort: 'ascending' | 'descending' | 'none' = !isSortable
|
|
@@ -150,9 +155,28 @@ export function SortableHeaderCell<ColumnId extends string>({
|
|
|
150
155
|
|
|
151
156
|
function handleSortClick() {
|
|
152
157
|
if (!isSortable) return
|
|
158
|
+
if (justResizedRef.current) return
|
|
153
159
|
onSortChange!(column.id)
|
|
154
160
|
}
|
|
155
161
|
|
|
162
|
+
function handleResizePointerDown(event: ReactPointerEvent<HTMLButtonElement>) {
|
|
163
|
+
// Don't bubble the resize-pointer-down up to the th's onClick sort
|
|
164
|
+
// handler — resize is its own interaction.
|
|
165
|
+
event.stopPropagation()
|
|
166
|
+
onResize(event, column.id)
|
|
167
|
+
const onUp = () => {
|
|
168
|
+
window.removeEventListener('pointerup', onUp)
|
|
169
|
+
justResizedRef.current = true
|
|
170
|
+
// Clear after the click that fires on this same pointerup has been
|
|
171
|
+
// dispatched (a later macrotask), so that click is swallowed but
|
|
172
|
+
// genuine subsequent clicks still sort.
|
|
173
|
+
window.setTimeout(() => {
|
|
174
|
+
justResizedRef.current = false
|
|
175
|
+
}, 0)
|
|
176
|
+
}
|
|
177
|
+
window.addEventListener('pointerup', onUp)
|
|
178
|
+
}
|
|
179
|
+
|
|
156
180
|
function handleSortKey(event: ReactKeyboardEvent<HTMLDivElement>) {
|
|
157
181
|
if (!isSortable) return
|
|
158
182
|
if (event.key === 'Enter' || event.key === ' ') {
|
|
@@ -209,12 +233,8 @@ export function SortableHeaderCell<ColumnId extends string>({
|
|
|
209
233
|
aria-label={`Resize ${column.label} column`}
|
|
210
234
|
className="absolute top-0 right-0 flex h-full w-3 cursor-col-resize items-center justify-center transition-colors"
|
|
211
235
|
style={{ color: 'rgb(var(--text-muted))' }}
|
|
212
|
-
onPointerDown={
|
|
213
|
-
|
|
214
|
-
// sort handler — resize is its own interaction.
|
|
215
|
-
event.stopPropagation()
|
|
216
|
-
onResize(event, column.id)
|
|
217
|
-
}}
|
|
236
|
+
onPointerDown={handleResizePointerDown}
|
|
237
|
+
onClick={(event) => event.stopPropagation()}
|
|
218
238
|
/>
|
|
219
239
|
</TableHead>
|
|
220
240
|
)
|
package/src/data-grid/sticky.ts
CHANGED
|
@@ -98,10 +98,11 @@ export function splitAtRightPinned<ColumnId extends string>(
|
|
|
98
98
|
|
|
99
99
|
type Role = 'header' | 'body' | 'footer'
|
|
100
100
|
|
|
101
|
-
/** Opaque background. Header
|
|
102
|
-
* opaque base so
|
|
101
|
+
/** Opaque background. Header + footer composite their translucent tint
|
|
102
|
+
* over an opaque base so they read as a light-gray band but never let
|
|
103
|
+
* content through. Body pinned cells stay plain card-colored. */
|
|
103
104
|
function opaqueBg(role: Role): CSSProperties {
|
|
104
|
-
if (role === 'header') {
|
|
105
|
+
if (role === 'header' || role === 'footer') {
|
|
105
106
|
return {
|
|
106
107
|
backgroundColor: 'rgb(var(--bg-card))',
|
|
107
108
|
backgroundImage:
|
|
@@ -79,6 +79,7 @@ type DataGridTableBodyProps<
|
|
|
79
79
|
pinOffsets: Map<ColumnId, PinInfo>
|
|
80
80
|
scrollEdges: ScrollEdges
|
|
81
81
|
fillWidth: boolean
|
|
82
|
+
fillHeight: boolean
|
|
82
83
|
}
|
|
83
84
|
|
|
84
85
|
export function DataGridTableBody<
|
|
@@ -107,6 +108,7 @@ export function DataGridTableBody<
|
|
|
107
108
|
pinOffsets,
|
|
108
109
|
scrollEdges,
|
|
109
110
|
fillWidth,
|
|
111
|
+
fillHeight,
|
|
110
112
|
}: DataGridTableBodyProps<Row, ColumnId>) {
|
|
111
113
|
const { leading, rightPinned } = splitAtRightPinned(visibleColumns)
|
|
112
114
|
|
|
@@ -123,6 +125,7 @@ export function DataGridTableBody<
|
|
|
123
125
|
rowIndex: number,
|
|
124
126
|
column: DataGridColumn<ColumnId>,
|
|
125
127
|
colIndex: number,
|
|
128
|
+
noRightBorder = false,
|
|
126
129
|
) => {
|
|
127
130
|
const isEditing =
|
|
128
131
|
editingCell?.rowId === row.id && editingCell.columnId === column.id
|
|
@@ -151,7 +154,9 @@ export function DataGridTableBody<
|
|
|
151
154
|
style={{
|
|
152
155
|
width: columnWidths[column.id],
|
|
153
156
|
minWidth: columnWidths[column.id],
|
|
154
|
-
|
|
157
|
+
// The rightmost pinned cell drops its right border — the table
|
|
158
|
+
// container's own border already draws that edge (no double line).
|
|
159
|
+
borderRight: noRightBorder ? undefined : '1px solid rgb(var(--border))',
|
|
155
160
|
...sticky,
|
|
156
161
|
...(isDraggingThisColumn
|
|
157
162
|
? { background: 'rgb(var(--surface-overlay-soft))' }
|
|
@@ -276,10 +281,23 @@ export function DataGridTableBody<
|
|
|
276
281
|
<td aria-hidden style={{ width: 'auto', padding: 0 }} />
|
|
277
282
|
) : null}
|
|
278
283
|
{rightPinned.map((column, i) =>
|
|
279
|
-
renderDataCell(
|
|
284
|
+
renderDataCell(
|
|
285
|
+
row,
|
|
286
|
+
rowIndex,
|
|
287
|
+
column,
|
|
288
|
+
leading.length + i,
|
|
289
|
+
i === rightPinned.length - 1,
|
|
290
|
+
),
|
|
280
291
|
)}
|
|
281
292
|
</TableRow>
|
|
282
293
|
))}
|
|
294
|
+
{fillHeight ? (
|
|
295
|
+
// Filler row absorbs the leftover height (table is height:100%) so
|
|
296
|
+
// the summary footer stays pinned to the bottom even with few rows.
|
|
297
|
+
<tr aria-hidden style={{ height: '100%' }}>
|
|
298
|
+
<td style={{ padding: 0, border: 0 }} colSpan={visibleColumns.length + 2} />
|
|
299
|
+
</tr>
|
|
300
|
+
) : null}
|
|
283
301
|
</TableBody>
|
|
284
302
|
)
|
|
285
303
|
}
|
|
@@ -34,6 +34,12 @@ export const Table = forwardRef<
|
|
|
34
34
|
style={{
|
|
35
35
|
border: '1px solid rgb(var(--border))',
|
|
36
36
|
borderRadius: 'var(--radius-lg)',
|
|
37
|
+
// NOTE: intentionally NOT setting scrollbar-width / scrollbar-color.
|
|
38
|
+
// On macOS, any custom scrollbar property opts the element out of the
|
|
39
|
+
// platform's auto-hiding *overlay* scrollbars into *classic*
|
|
40
|
+
// always-visible ones — which left the vertical bar permanently
|
|
41
|
+
// covering the pinned action column. Native overlay bars are already
|
|
42
|
+
// thin + light AND auto-hide, so we leave them untouched.
|
|
37
43
|
}}
|
|
38
44
|
>
|
|
39
45
|
<table
|
|
@@ -89,7 +89,10 @@ export function DataGridTableHeader<ColumnId extends string>({
|
|
|
89
89
|
stickyFooter: false,
|
|
90
90
|
})
|
|
91
91
|
|
|
92
|
-
const renderHeadCell = (
|
|
92
|
+
const renderHeadCell = (
|
|
93
|
+
column: DataGridColumn<ColumnId>,
|
|
94
|
+
noRightBorder = false,
|
|
95
|
+
) => (
|
|
93
96
|
<SortableHeaderCell
|
|
94
97
|
key={column.id}
|
|
95
98
|
column={column}
|
|
@@ -97,7 +100,10 @@ export function DataGridTableHeader<ColumnId extends string>({
|
|
|
97
100
|
onResize={onResizeStart}
|
|
98
101
|
sortDir={sort?.columnId === column.id ? sort.dir : null}
|
|
99
102
|
onSortChange={onSortChange}
|
|
100
|
-
cellStyle={
|
|
103
|
+
cellStyle={{
|
|
104
|
+
...styleFor(column),
|
|
105
|
+
...(noRightBorder ? { borderRight: 'none' } : null),
|
|
106
|
+
}}
|
|
101
107
|
/>
|
|
102
108
|
)
|
|
103
109
|
|
|
@@ -132,11 +138,13 @@ export function DataGridTableHeader<ColumnId extends string>({
|
|
|
132
138
|
className="mx-auto"
|
|
133
139
|
/>
|
|
134
140
|
</TableHead>
|
|
135
|
-
{leading.map(renderHeadCell)}
|
|
141
|
+
{leading.map((column) => renderHeadCell(column))}
|
|
136
142
|
{fillWidth ? (
|
|
137
143
|
<th aria-hidden style={{ width: 'auto', padding: 0, ...spacerStyle }} />
|
|
138
144
|
) : null}
|
|
139
|
-
{rightPinned.map(
|
|
145
|
+
{rightPinned.map((column, i) =>
|
|
146
|
+
renderHeadCell(column, i === rightPinned.length - 1),
|
|
147
|
+
)}
|
|
140
148
|
</TableRow>
|
|
141
149
|
</TableHeader>
|
|
142
150
|
</>
|
|
@@ -74,7 +74,10 @@ export function DataGridSummaryFooter<
|
|
|
74
74
|
stickyFooter: stickySummaryFooter,
|
|
75
75
|
})
|
|
76
76
|
|
|
77
|
-
const renderSummaryCell = (
|
|
77
|
+
const renderSummaryCell = (
|
|
78
|
+
column: DataGridColumn<ColumnId>,
|
|
79
|
+
noRightBorder = false,
|
|
80
|
+
) => {
|
|
78
81
|
const summaryContent = renderSummary(column, visibleRows)
|
|
79
82
|
const isDraggingThisColumn = draggingColumnId === column.id
|
|
80
83
|
|
|
@@ -86,7 +89,7 @@ export function DataGridSummaryFooter<
|
|
|
86
89
|
width: columnWidths[column.id],
|
|
87
90
|
minWidth: columnWidths[column.id],
|
|
88
91
|
color: 'rgb(var(--text-muted))',
|
|
89
|
-
borderRight: '1px solid rgb(var(--border))',
|
|
92
|
+
borderRight: noRightBorder ? undefined : '1px solid rgb(var(--border))',
|
|
90
93
|
...footerStyle(pinOffsets.get(column.id) ?? null),
|
|
91
94
|
...(isDraggingThisColumn
|
|
92
95
|
? { background: 'rgb(var(--surface-overlay-soft))' }
|
|
@@ -110,14 +113,16 @@ export function DataGridSummaryFooter<
|
|
|
110
113
|
...footerStyle({ side: 'left', offset: 0 }),
|
|
111
114
|
}}
|
|
112
115
|
/>
|
|
113
|
-
{leading.map(renderSummaryCell)}
|
|
116
|
+
{leading.map((column) => renderSummaryCell(column))}
|
|
114
117
|
{fillWidth ? (
|
|
115
118
|
<td
|
|
116
119
|
aria-hidden
|
|
117
120
|
style={{ width: 'auto', padding: 0, ...footerStyle(null) }}
|
|
118
121
|
/>
|
|
119
122
|
) : null}
|
|
120
|
-
{rightPinned.map(
|
|
123
|
+
{rightPinned.map((column, i) =>
|
|
124
|
+
renderSummaryCell(column, i === rightPinned.length - 1),
|
|
125
|
+
)}
|
|
121
126
|
</TableRow>
|
|
122
127
|
</TableFooter>
|
|
123
128
|
)
|
|
@@ -76,6 +76,7 @@ type DataGridTableViewProps<
|
|
|
76
76
|
stickySummaryFooter: boolean
|
|
77
77
|
stickyHeader: boolean
|
|
78
78
|
fillWidth: boolean
|
|
79
|
+
fillHeight: boolean
|
|
79
80
|
scrollEdges: ScrollEdges
|
|
80
81
|
tableContainerClassName: string | undefined
|
|
81
82
|
isEmptyValue: (value: ReactNode) => boolean
|
|
@@ -120,6 +121,7 @@ export function DataGridTableView<
|
|
|
120
121
|
stickySummaryFooter,
|
|
121
122
|
stickyHeader,
|
|
122
123
|
fillWidth,
|
|
124
|
+
fillHeight,
|
|
123
125
|
scrollEdges,
|
|
124
126
|
tableContainerClassName,
|
|
125
127
|
isEmptyValue,
|
|
@@ -134,7 +136,13 @@ export function DataGridTableView<
|
|
|
134
136
|
ref={tableRef}
|
|
135
137
|
className="table-fixed"
|
|
136
138
|
containerClassName={tableContainerClassName}
|
|
137
|
-
style={{
|
|
139
|
+
style={{
|
|
140
|
+
width: `max(100%, ${gridMinWidth}px)`,
|
|
141
|
+
// When the grid fills its height, stretch the table to the full
|
|
142
|
+
// viewport so the spacer body row can push the summary footer to
|
|
143
|
+
// the bottom even with few rows.
|
|
144
|
+
...(fillHeight ? { height: '100%' } : null),
|
|
145
|
+
}}
|
|
138
146
|
>
|
|
139
147
|
<DataGridTableHeader
|
|
140
148
|
visibleColumns={visibleColumns}
|
|
@@ -174,6 +182,7 @@ export function DataGridTableView<
|
|
|
174
182
|
pinOffsets={pinOffsets}
|
|
175
183
|
scrollEdges={scrollEdges}
|
|
176
184
|
fillWidth={fillWidth}
|
|
185
|
+
fillHeight={fillHeight}
|
|
177
186
|
/>
|
|
178
187
|
|
|
179
188
|
<DataGridSummaryFooter
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DataGridToolbar — the standard layout band that sits directly above a
|
|
3
|
+
* DataGrid: a search field on the left and filter / column / view
|
|
4
|
+
* controls on the right (gray-ui "table toolbar" pattern). Collapses to
|
|
5
|
+
* a stacked column on narrow viewports.
|
|
6
|
+
*
|
|
7
|
+
* Purely a layout primitive — pass whatever search input + action
|
|
8
|
+
* buttons you like into the slots.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { ReactNode } from 'react'
|
|
12
|
+
|
|
13
|
+
import { cn } from '../lib/utils'
|
|
14
|
+
|
|
15
|
+
export interface DataGridToolbarProps {
|
|
16
|
+
/** Left slot — typically a <SearchBar>. Stretches up to a comfortable
|
|
17
|
+
* reading width, full-width when stacked. */
|
|
18
|
+
search?: ReactNode
|
|
19
|
+
/** Right slot — filter / columns / view-toggle controls. */
|
|
20
|
+
children?: ReactNode
|
|
21
|
+
className?: string
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function DataGridToolbar({
|
|
25
|
+
search,
|
|
26
|
+
children,
|
|
27
|
+
className,
|
|
28
|
+
}: DataGridToolbarProps) {
|
|
29
|
+
return (
|
|
30
|
+
<div
|
|
31
|
+
className={cn(
|
|
32
|
+
'flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between',
|
|
33
|
+
className,
|
|
34
|
+
)}
|
|
35
|
+
>
|
|
36
|
+
{search ? <div className="w-full sm:max-w-sm">{search}</div> : <span />}
|
|
37
|
+
{children ? (
|
|
38
|
+
<div className="flex flex-wrap items-center gap-2 sm:justify-end">
|
|
39
|
+
{children}
|
|
40
|
+
</div>
|
|
41
|
+
) : null}
|
|
42
|
+
</div>
|
|
43
|
+
)
|
|
44
|
+
}
|
|
@@ -101,7 +101,29 @@ export function useGridColumns<ColumnId extends string>({
|
|
|
101
101
|
setVisibleColumnIds((current) => {
|
|
102
102
|
const kept = current.filter((id) => allowedIds.has(id))
|
|
103
103
|
const missing = columnOrder.filter((id) => !kept.includes(id))
|
|
104
|
-
|
|
104
|
+
if (missing.length === 0) {
|
|
105
|
+
return kept.length === current.length ? current : kept
|
|
106
|
+
}
|
|
107
|
+
// Insert newly-visible columns at their natural position (per the
|
|
108
|
+
// `columns` prop order) instead of appending them at the very end.
|
|
109
|
+
// Appending broke pinned trailing columns (e.g. an actions column
|
|
110
|
+
// pinned right would stop being last once another column was toggled
|
|
111
|
+
// on). Existing columns keep their (possibly drag-reordered) order.
|
|
112
|
+
const orderIndex = (id: ColumnId) => columnOrder.indexOf(id)
|
|
113
|
+
const next = [...kept]
|
|
114
|
+
for (const id of missing) {
|
|
115
|
+
const target = orderIndex(id)
|
|
116
|
+
let insertAt = next.length
|
|
117
|
+
for (let i = 0; i < next.length; i += 1) {
|
|
118
|
+
const cur = next[i]
|
|
119
|
+
if (cur !== undefined && orderIndex(cur) > target) {
|
|
120
|
+
insertAt = i
|
|
121
|
+
break
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
next.splice(insertAt, 0, id)
|
|
125
|
+
}
|
|
126
|
+
return next
|
|
105
127
|
})
|
|
106
128
|
|
|
107
129
|
orderBeforeDragRef.current = columnOrder
|
package/src/index.ts
CHANGED
|
@@ -109,6 +109,7 @@ export {
|
|
|
109
109
|
} from './dropdown-menu'
|
|
110
110
|
export {
|
|
111
111
|
DataGrid,
|
|
112
|
+
DataGridToolbar,
|
|
112
113
|
DataGridColumnOptionsMenu,
|
|
113
114
|
DataGridDragOverlay,
|
|
114
115
|
DataGridDropIndicator,
|
|
@@ -117,6 +118,7 @@ export {
|
|
|
117
118
|
type DataGridProps,
|
|
118
119
|
type DataGridRowBase,
|
|
119
120
|
type DataGridSortState,
|
|
121
|
+
type DataGridToolbarProps,
|
|
120
122
|
type DataGridToolbarRenderProps,
|
|
121
123
|
type DataGridIcon,
|
|
122
124
|
type EditingCell,
|