@rebasepro/ui 0.14.0 → 0.14.1-canary.g7e666eb
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/VirtualTable/VirtualTableHeader.d.ts +6 -1
- package/dist/components/VirtualTable/VirtualTableHeaderRow.d.ts +1 -1
- package/dist/components/VirtualTable/VirtualTableProps.d.ts +7 -4
- package/dist/components/VirtualTable/types.d.ts +6 -3
- package/dist/index.es.js +68 -28
- package/dist/index.es.js.map +1 -1
- package/dist/views/CollectionView/CollectionViewTypes.d.ts +4 -2
- package/package.json +2 -2
- package/src/components/VirtualTable/VirtualTable.tsx +47 -17
- package/src/components/VirtualTable/VirtualTableHeader.tsx +45 -4
- package/src/components/VirtualTable/VirtualTableHeaderRow.tsx +10 -10
- package/src/components/VirtualTable/VirtualTableProps.tsx +8 -4
- package/src/components/VirtualTable/types.tsx +3 -3
- package/src/views/CollectionView/CollectionViewTypes.ts +4 -2
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
+
import type { VirtualTableSortKey } from "../../components/VirtualTable/VirtualTableProps";
|
|
2
3
|
/** Supported view modes */
|
|
3
4
|
export type CollectionViewMode = "table" | "cards" | "kanban" | "list";
|
|
4
5
|
/** Supported collection sizes */
|
|
@@ -57,8 +58,9 @@ export interface CollectionDataController<T = Record<string, unknown>> {
|
|
|
57
58
|
error?: Error;
|
|
58
59
|
filterValues?: Record<string, [string, unknown]>;
|
|
59
60
|
setFilterValues?: (values: Record<string, [string, unknown]> | undefined) => void;
|
|
60
|
-
|
|
61
|
-
|
|
61
|
+
/** The sort keys in order of significance; the second breaks ties on the first. */
|
|
62
|
+
sortBy?: VirtualTableSortKey[];
|
|
63
|
+
setSortBy?: (sort?: VirtualTableSortKey[]) => void;
|
|
62
64
|
searchString?: string;
|
|
63
65
|
setSearchString?: (search?: string) => void;
|
|
64
66
|
clearFilter?: () => void;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rebasepro/ui",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.14.
|
|
4
|
+
"version": "0.14.1-canary.g7e666eb",
|
|
5
5
|
"description": "Rebase design system — React components and design tokens built on Radix UI, Tailwind CSS and lucide-react",
|
|
6
6
|
"funding": {
|
|
7
7
|
"url": "https://github.com/sponsors/rebaseco"
|
|
@@ -116,7 +116,7 @@
|
|
|
116
116
|
"build": "rm -rf dist || true && vite build && cp dist/src/index.css dist/src/theme.css dist/ && tsc --emitDeclarationOnly -p tsconfig.prod.json && node ../../scripts/assert-build-output.mjs",
|
|
117
117
|
"test:lint": "eslint \"src/**\" --quiet",
|
|
118
118
|
"test": "jest --passWithNoTests",
|
|
119
|
-
"clean": "rm -rf dist && find ./src -name '*.js' -type f | xargs rm -f",
|
|
119
|
+
"clean": "rm -rf dist && find ./src \\( -name '*.js' -o -name '*.d.ts' \\) -type f | xargs rm -f",
|
|
120
120
|
"generateIcons": "bun --esm src/scripts/generateIcons.ts"
|
|
121
121
|
}
|
|
122
122
|
}
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
VirtualTableColumn,
|
|
14
14
|
VirtualTableFilterValues,
|
|
15
15
|
VirtualTableProps,
|
|
16
|
+
VirtualTableSortKey,
|
|
16
17
|
VirtualTableWhereFilterOp
|
|
17
18
|
} from "./VirtualTableProps";
|
|
18
19
|
|
|
@@ -142,8 +143,18 @@ const VirtualTableInner = React.memo<VirtualTableProps<Record<string, unknown>>>
|
|
|
142
143
|
extraData
|
|
143
144
|
}: VirtualTableProps<T>) {
|
|
144
145
|
|
|
145
|
-
|
|
146
|
-
|
|
146
|
+
// Where each sorted column sits in the order, so a header can show both
|
|
147
|
+
// which way it runs and how much it counts: `roles ↑1, created_at ↓2`
|
|
148
|
+
// reads as "by role, newest first within each role". Without the rank a
|
|
149
|
+
// multi-key sort shows two arrows and no way to tell which one wins.
|
|
150
|
+
const sortIndex = useMemo(() => {
|
|
151
|
+
const index = new Map<string, { direction: "asc" | "desc"; position: number }>();
|
|
152
|
+
(sortBy ?? []).forEach(([key, direction], position) => {
|
|
153
|
+
if (!index.has(key)) index.set(key, { direction,
|
|
154
|
+
position });
|
|
155
|
+
});
|
|
156
|
+
return index;
|
|
157
|
+
}, [sortBy]);
|
|
147
158
|
|
|
148
159
|
const [columns, setColumns] = useState(columnsProp);
|
|
149
160
|
|
|
@@ -243,16 +254,37 @@ const VirtualTableInner = React.memo<VirtualTableProps<Record<string, unknown>>>
|
|
|
243
254
|
}
|
|
244
255
|
}, []);
|
|
245
256
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
257
|
+
/**
|
|
258
|
+
* Click a header to sort by that column: ascending, descending, then
|
|
259
|
+
* off. Shift-click to keep the sort you already have and add this
|
|
260
|
+
* column under it — the same idiom spreadsheets use, and the only way
|
|
261
|
+
* to build "by role, newest first" out of two clicks.
|
|
262
|
+
*
|
|
263
|
+
* Shift cycles the column it lands on through the same three states, so
|
|
264
|
+
* a key added by mistake is removed by shift-clicking it twice more,
|
|
265
|
+
* without disturbing the keys around it.
|
|
266
|
+
*/
|
|
267
|
+
const onColumnSort = useCallback((key: string, additive = false) => {
|
|
268
|
+
|
|
269
|
+
const current = sortIndex.get(key);
|
|
270
|
+
const next: "asc" | "desc" | undefined = current === undefined
|
|
271
|
+
? "asc"
|
|
272
|
+
: current.direction === "asc" ? "desc" : undefined;
|
|
273
|
+
|
|
274
|
+
const existing = sortBy ?? [];
|
|
275
|
+
let newSortBy: VirtualTableSortKey[] | undefined;
|
|
276
|
+
if (!additive) {
|
|
277
|
+
newSortBy = next ? [[key, next]] : undefined;
|
|
278
|
+
} else if (next === undefined) {
|
|
279
|
+
newSortBy = existing.filter(([existingKey]) => existingKey !== key);
|
|
280
|
+
} else if (current === undefined) {
|
|
281
|
+
newSortBy = [...existing, [key, next]];
|
|
282
|
+
} else {
|
|
283
|
+
newSortBy = existing.map((entry) => entry[0] === key ? [key, next] as VirtualTableSortKey : entry);
|
|
284
|
+
}
|
|
285
|
+
if (newSortBy?.length === 0) newSortBy = undefined;
|
|
252
286
|
|
|
253
287
|
const filter = filterRef.current;
|
|
254
|
-
|
|
255
|
-
const newSortBy: [string, "asc" | "desc"] | undefined = newSort && newSortProperty ? [newSortProperty, newSort] : undefined;
|
|
256
288
|
if (filter) {
|
|
257
289
|
if (checkFilterCombination && !checkFilterCombination(filter, newSortBy)) {
|
|
258
290
|
if (onFilterUpdate)
|
|
@@ -269,7 +301,7 @@ const VirtualTableInner = React.memo<VirtualTableProps<Record<string, unknown>>>
|
|
|
269
301
|
}
|
|
270
302
|
|
|
271
303
|
scrollToTop();
|
|
272
|
-
}, [checkFilterCombination,
|
|
304
|
+
}, [checkFilterCombination, onFilterUpdate, onResetPagination, onSortByUpdate, scrollToTop, sortBy, sortIndex]);
|
|
273
305
|
|
|
274
306
|
const maxScroll = Math.max((data?.length ?? 0) * rowHeight - bounds.height, 0);
|
|
275
307
|
|
|
@@ -311,14 +343,13 @@ const VirtualTableInner = React.memo<VirtualTableProps<Record<string, unknown>>>
|
|
|
311
343
|
} else {
|
|
312
344
|
newFilterValue[column.key] = filterForProperty;
|
|
313
345
|
}
|
|
314
|
-
const
|
|
315
|
-
const isNewFilterCombinationValid = !checkFilterCombination || checkFilterCombination(newFilterValue, newSortBy);
|
|
346
|
+
const isNewFilterCombinationValid = !checkFilterCombination || checkFilterCombination(newFilterValue, sortBy);
|
|
316
347
|
if (!isNewFilterCombinationValid) {
|
|
317
348
|
newFilterValue = filterForProperty ? { [column.key]: filterForProperty } as VirtualTableFilterValues<Extract<keyof T, string>> : {};
|
|
318
349
|
}
|
|
319
350
|
|
|
320
351
|
if (onFilterUpdate) onFilterUpdate(newFilterValue);
|
|
321
|
-
}, [checkFilterCombination,
|
|
352
|
+
}, [checkFilterCombination, onFilterUpdate, sortBy]);
|
|
322
353
|
|
|
323
354
|
const empty = !loading && (data?.length ?? 0) === 0;
|
|
324
355
|
const customView = (error && (data?.length ?? 0) === 0)
|
|
@@ -349,7 +380,6 @@ const VirtualTableInner = React.memo<VirtualTableProps<Record<string, unknown>>>
|
|
|
349
380
|
headerHeight: headerHeight,
|
|
350
381
|
cellRenderer,
|
|
351
382
|
columns,
|
|
352
|
-
currentSort,
|
|
353
383
|
onRowClick,
|
|
354
384
|
customView,
|
|
355
385
|
onColumnResize: onColumnResizeInternal,
|
|
@@ -357,7 +387,7 @@ const VirtualTableInner = React.memo<VirtualTableProps<Record<string, unknown>>>
|
|
|
357
387
|
filter: filterRef.current,
|
|
358
388
|
onColumnSort,
|
|
359
389
|
onFilterUpdate: onFilterUpdateInternal,
|
|
360
|
-
|
|
390
|
+
sortIndex,
|
|
361
391
|
hoverRow: hoverRow ?? false,
|
|
362
392
|
createFilterField,
|
|
363
393
|
rowClassName,
|
|
@@ -369,7 +399,7 @@ const VirtualTableInner = React.memo<VirtualTableProps<Record<string, unknown>>>
|
|
|
369
399
|
} : undefined,
|
|
370
400
|
draggingColumnId,
|
|
371
401
|
extraData
|
|
372
|
-
}), [data, rowHeight, cellRenderer, columns,
|
|
402
|
+
}), [data, rowHeight, cellRenderer, columns, onRowClick, customView, onColumnResizeInternal, onColumnResizeEndInternal, filterInput, onColumnSort, onFilterUpdateInternal, sortIndex, hoverRow, createFilterField, rowClassName, endAdornment, AddColumnComponent, onColumnsOrderChange, draggingColumnId, extraData]);
|
|
373
403
|
|
|
374
404
|
// Get sortable column keys (excluding frozen columns)
|
|
375
405
|
const sortableColumnKeys = columns
|
|
@@ -36,9 +36,14 @@ type VirtualTableHeaderProps<M extends Record<string, unknown>> = {
|
|
|
36
36
|
columnIndex: number;
|
|
37
37
|
isResizingIndex: number;
|
|
38
38
|
column: VirtualTableColumn<unknown>;
|
|
39
|
-
onColumnSort: (key: Extract<keyof M, string
|
|
39
|
+
onColumnSort: (key: Extract<keyof M, string>, additive?: boolean) => void;
|
|
40
40
|
filter?: [VirtualTableWhereFilterOp, unknown];
|
|
41
41
|
sort: VirtualTableSort;
|
|
42
|
+
/**
|
|
43
|
+
* This column's zero-based rank in a multi-key sort, or `undefined` when
|
|
44
|
+
* only one column is sorted and a rank would say nothing.
|
|
45
|
+
*/
|
|
46
|
+
sortPosition?: number;
|
|
42
47
|
onFilterUpdate: (column: VirtualTableColumn, filterForProperty?: [VirtualTableWhereFilterOp, unknown]) => void;
|
|
43
48
|
onClickResizeColumn?: (columnIndex: number, column: VirtualTableColumn) => void;
|
|
44
49
|
createFilterField?: (props: FilterFormFieldProps<unknown>) => React.ReactNode;
|
|
@@ -47,12 +52,27 @@ type VirtualTableHeaderProps<M extends Record<string, unknown>> = {
|
|
|
47
52
|
isDraggable?: boolean;
|
|
48
53
|
};
|
|
49
54
|
|
|
55
|
+
/**
|
|
56
|
+
* What the next click on this column's sort control will do, spelled out for
|
|
57
|
+
* the tooltip and for screen readers. An unlabelled arrow that means three
|
|
58
|
+
* different things depending on the state it is in is a control you have to
|
|
59
|
+
* click to learn.
|
|
60
|
+
*/
|
|
61
|
+
function sortActionTitle(sort: VirtualTableSort, sortPosition?: number): string {
|
|
62
|
+
const rank = sortPosition !== undefined ? ` (sort key ${sortPosition + 1})` : "";
|
|
63
|
+
const addKey = " — shift-click to add it under the current sort instead";
|
|
64
|
+
if (sort === "asc") return `Sorted ascending${rank}. Click to sort descending.${addKey}`;
|
|
65
|
+
if (sort === "desc") return `Sorted descending${rank}. Click to remove this sort.${addKey}`;
|
|
66
|
+
return `Click to sort ascending.${addKey}`;
|
|
67
|
+
}
|
|
68
|
+
|
|
50
69
|
export const VirtualTableHeader = React.memo<VirtualTableHeaderProps<Record<string, unknown>>>(
|
|
51
70
|
function VirtualTableHeader<M extends Record<string, unknown>>({
|
|
52
71
|
resizeHandleRef,
|
|
53
72
|
columnIndex,
|
|
54
73
|
isResizingIndex,
|
|
55
74
|
sort,
|
|
75
|
+
sortPosition,
|
|
56
76
|
onColumnSort,
|
|
57
77
|
onFilterUpdate,
|
|
58
78
|
filter,
|
|
@@ -141,14 +161,23 @@ export const VirtualTableHeader = React.memo<VirtualTableHeaderProps<Record<stri
|
|
|
141
161
|
<AdditionalHeaderWidget onHover={onHover || openFilter}/>}
|
|
142
162
|
|
|
143
163
|
{column.sortable && (sort || hovered || openFilter) &&
|
|
144
|
-
<div className="flex-shrink-0">
|
|
164
|
+
<div className="flex-shrink-0 flex items-center">
|
|
145
165
|
<Badge color="secondary"
|
|
146
166
|
invisible={!sort}>
|
|
147
167
|
<IconButton
|
|
148
168
|
size={"small"}
|
|
149
169
|
className={onHover || openFilter ? "bg-white dark:bg-surface-900" : undefined}
|
|
150
|
-
|
|
151
|
-
|
|
170
|
+
// Shift keeps the sort already in place
|
|
171
|
+
// and adds this column beneath it, which
|
|
172
|
+
// is how a two-key order is built from
|
|
173
|
+
// header clicks. Plain click still
|
|
174
|
+
// replaces the whole sort, so the common
|
|
175
|
+
// case takes no modifier and nothing a
|
|
176
|
+
// user knew before stops working.
|
|
177
|
+
title={sortActionTitle(sort, sortPosition)}
|
|
178
|
+
aria-label={sortActionTitle(sort, sortPosition)}
|
|
179
|
+
onClick={(event: React.MouseEvent) => {
|
|
180
|
+
onColumnSort(column.key as Extract<keyof M, string>, event.shiftKey);
|
|
152
181
|
}}
|
|
153
182
|
>
|
|
154
183
|
{!sort &&
|
|
@@ -159,6 +188,18 @@ export const VirtualTableHeader = React.memo<VirtualTableHeaderProps<Record<stri
|
|
|
159
188
|
<ArrowUpIcon size={14} className="flex-shrink-0 rotate-180" />}
|
|
160
189
|
</IconButton>
|
|
161
190
|
</Badge>
|
|
191
|
+
{/* The rank, shown only once there is more than
|
|
192
|
+
one key: two arrows with no numbers beside
|
|
193
|
+
them say a table is sorted by both columns
|
|
194
|
+
and nothing about which one decides. */}
|
|
195
|
+
{sort && sortPosition !== undefined && (
|
|
196
|
+
<span
|
|
197
|
+
className="flex-shrink-0 -ml-0.5 mr-0.5 text-[10px] font-bold leading-none tabular-nums text-text-secondary dark:text-text-secondary-dark"
|
|
198
|
+
aria-hidden={true}
|
|
199
|
+
>
|
|
200
|
+
{sortPosition + 1}
|
|
201
|
+
</span>
|
|
202
|
+
)}
|
|
162
203
|
</div>
|
|
163
204
|
}
|
|
164
205
|
</>
|
|
@@ -16,8 +16,8 @@ const SortableColumnHeader = ({
|
|
|
16
16
|
isResizing,
|
|
17
17
|
onFilterUpdate,
|
|
18
18
|
filter,
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
sortIndex,
|
|
20
|
+
sortCount,
|
|
21
21
|
onColumnSort,
|
|
22
22
|
onClickResizeColumn,
|
|
23
23
|
createFilterField,
|
|
@@ -30,9 +30,9 @@ const SortableColumnHeader = ({
|
|
|
30
30
|
isResizing: number;
|
|
31
31
|
onFilterUpdate: (column: VirtualTableColumn, filterForProperty?: [VirtualTableWhereFilterOp, unknown]) => void;
|
|
32
32
|
filter: [VirtualTableWhereFilterOp, unknown] | undefined;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
onColumnSort: (key: string) => void;
|
|
33
|
+
sortIndex: Map<string, { direction: "asc" | "desc"; position: number }>;
|
|
34
|
+
sortCount: number;
|
|
35
|
+
onColumnSort: (key: string, additive?: boolean) => void;
|
|
36
36
|
onClickResizeColumn: (index: number) => void;
|
|
37
37
|
createFilterField: ((props: import("./VirtualTableHeader").FilterFormFieldProps<unknown>) => React.ReactNode) | undefined;
|
|
38
38
|
isDragging: boolean;
|
|
@@ -96,7 +96,8 @@ const SortableColumnHeader = ({
|
|
|
96
96
|
isResizingIndex={isResizing}
|
|
97
97
|
onFilterUpdate={onFilterUpdate}
|
|
98
98
|
filter={filter}
|
|
99
|
-
sort={
|
|
99
|
+
sort={sortIndex.get(column.key)?.direction}
|
|
100
|
+
sortPosition={sortCount > 1 ? sortIndex.get(column.key)?.position : undefined}
|
|
100
101
|
onColumnSort={onColumnSort}
|
|
101
102
|
onClickResizeColumn={onClickResizeColumn}
|
|
102
103
|
column={column}
|
|
@@ -110,10 +111,9 @@ const SortableColumnHeader = ({
|
|
|
110
111
|
|
|
111
112
|
export const VirtualTableHeaderRow = ({
|
|
112
113
|
columns,
|
|
113
|
-
|
|
114
|
+
sortIndex,
|
|
114
115
|
onColumnSort,
|
|
115
116
|
onFilterUpdate,
|
|
116
|
-
sortByProperty,
|
|
117
117
|
filter,
|
|
118
118
|
onColumnResize,
|
|
119
119
|
onColumnResizeEnd,
|
|
@@ -230,8 +230,8 @@ export const VirtualTableHeaderRow = ({
|
|
|
230
230
|
isResizing={isResizing}
|
|
231
231
|
onFilterUpdate={onFilterUpdate}
|
|
232
232
|
filter={filterForThisProperty}
|
|
233
|
-
|
|
234
|
-
|
|
233
|
+
sortIndex={sortIndex}
|
|
234
|
+
sortCount={sortIndex.size}
|
|
235
235
|
onColumnSort={onColumnSort}
|
|
236
236
|
onClickResizeColumn={onClickResizeColumn}
|
|
237
237
|
createFilterField={createFilterField}
|
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
import React from "react";
|
|
4
4
|
import type { FilterFormFieldProps } from "./VirtualTableHeader";
|
|
5
5
|
|
|
6
|
+
/** One sort key: the column, and which way it runs. */
|
|
7
|
+
export type VirtualTableSortKey = [string, "asc" | "desc"];
|
|
8
|
+
|
|
6
9
|
export type OnRowClickParams<T extends Record<string, unknown>> = {
|
|
7
10
|
rowData: T;
|
|
8
11
|
rowIndex: number;
|
|
@@ -39,7 +42,7 @@ export interface VirtualTableProps<T extends Record<string, unknown>> {
|
|
|
39
42
|
* @param sortBy
|
|
40
43
|
*/
|
|
41
44
|
checkFilterCombination?: (filterValues: VirtualTableFilterValues<Extract<keyof T, string>>,
|
|
42
|
-
sortBy?: [
|
|
45
|
+
sortBy?: VirtualTableSortKey[]) => boolean;
|
|
43
46
|
|
|
44
47
|
/**
|
|
45
48
|
* A callback function when scrolling the table to near the end
|
|
@@ -96,15 +99,16 @@ export interface VirtualTableProps<T extends Record<string, unknown>> {
|
|
|
96
99
|
}) => void;
|
|
97
100
|
|
|
98
101
|
/**
|
|
99
|
-
*
|
|
102
|
+
* Sort applied to this collection: the keys in order of significance, the
|
|
103
|
+
* second breaking ties on the first.
|
|
100
104
|
*/
|
|
101
|
-
sortBy?: [
|
|
105
|
+
sortBy?: VirtualTableSortKey[];
|
|
102
106
|
|
|
103
107
|
/**
|
|
104
108
|
* Callback used when sorting is updated
|
|
105
109
|
* @param sortBy
|
|
106
110
|
*/
|
|
107
|
-
onSortByUpdate?: (sortBy?: [
|
|
111
|
+
onSortByUpdate?: (sortBy?: VirtualTableSortKey[]) => void;
|
|
108
112
|
|
|
109
113
|
/**
|
|
110
114
|
* If there is an error loading data you can pass it here, so it gets
|
|
@@ -27,14 +27,14 @@ export type VirtualTableContextProps<T> = {
|
|
|
27
27
|
headerHeight?: number,
|
|
28
28
|
columns: VirtualTableColumn[];
|
|
29
29
|
cellRenderer: React.ComponentType<CellRendererParams<T>>;
|
|
30
|
-
|
|
30
|
+
/** Each sorted column's direction and its rank in the sort, keyed by column. */
|
|
31
|
+
sortIndex: Map<string, { direction: "asc" | "desc"; position: number }>;
|
|
31
32
|
filter?: VirtualTableFilterValues<string>;
|
|
32
33
|
onRowClick?: (props: OnRowClickParams<Record<string, unknown>>) => void;
|
|
33
|
-
onColumnSort: (key: string) => void;
|
|
34
|
+
onColumnSort: (key: string, additive?: boolean) => void;
|
|
34
35
|
onColumnResize: (params: OnVirtualTableColumnResizeParams) => void;
|
|
35
36
|
onColumnResizeEnd: (params: OnVirtualTableColumnResizeParams) => void;
|
|
36
37
|
onFilterUpdate: (column: VirtualTableColumn, filterForProperty?: [VirtualTableWhereFilterOp, unknown]) => void;
|
|
37
|
-
sortByProperty?: string;
|
|
38
38
|
customView?: React.ReactNode,
|
|
39
39
|
hoverRow: boolean;
|
|
40
40
|
createFilterField?: (props: FilterFormFieldProps<unknown>) => React.ReactNode;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
+
import type { VirtualTableSortKey } from "../../components/VirtualTable/VirtualTableProps";
|
|
2
3
|
|
|
3
4
|
/** Supported view modes */
|
|
4
5
|
export type CollectionViewMode = "table" | "cards" | "kanban" | "list";
|
|
@@ -80,8 +81,9 @@ export interface CollectionDataController<T = Record<string, unknown>> {
|
|
|
80
81
|
filterValues?: Record<string, [string, unknown]>;
|
|
81
82
|
setFilterValues?: (values: Record<string, [string, unknown]> | undefined) => void;
|
|
82
83
|
|
|
83
|
-
|
|
84
|
-
|
|
84
|
+
/** The sort keys in order of significance; the second breaks ties on the first. */
|
|
85
|
+
sortBy?: VirtualTableSortKey[];
|
|
86
|
+
setSortBy?: (sort?: VirtualTableSortKey[]) => void;
|
|
85
87
|
|
|
86
88
|
searchString?: string;
|
|
87
89
|
setSearchString?: (search?: string) => void;
|