@cdx-ui/data-grid 0.3.11 → 0.3.13
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/README.md +3 -1
- package/coverage.svg +1 -1
- package/lib/commonjs/DataGrid.js +490 -81
- package/lib/commonjs/DataGrid.js.map +1 -1
- package/lib/commonjs/DataGridFilterPanel.js +547 -0
- package/lib/commonjs/DataGridFilterPanel.js.map +1 -0
- package/lib/commonjs/adapter/columnTypes.js +256 -0
- package/lib/commonjs/adapter/columnTypes.js.map +1 -0
- package/lib/commonjs/adapter/columns.js +140 -4
- package/lib/commonjs/adapter/columns.js.map +1 -1
- package/lib/commonjs/adapter/filterOperators.js +422 -0
- package/lib/commonjs/adapter/filterOperators.js.map +1 -0
- package/lib/commonjs/adapter/pinning.js +105 -0
- package/lib/commonjs/adapter/pinning.js.map +1 -0
- package/lib/commonjs/adapter/selectColumn.js +11 -0
- package/lib/commonjs/adapter/selectColumn.js.map +1 -1
- package/lib/commonjs/adapter/treeData.js +195 -0
- package/lib/commonjs/adapter/treeData.js.map +1 -0
- package/lib/commonjs/index.js +26 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/numberCells.js +280 -0
- package/lib/commonjs/numberCells.js.map +1 -0
- package/lib/commonjs/styles.js +107 -1
- package/lib/commonjs/styles.js.map +1 -1
- package/lib/commonjs/types.js +39 -1
- package/lib/commonjs/types.js.map +1 -1
- package/lib/commonjs/useDataGridTable.js +234 -18
- package/lib/commonjs/useDataGridTable.js.map +1 -1
- package/lib/module/DataGrid.js +497 -88
- package/lib/module/DataGrid.js.map +1 -1
- package/lib/module/DataGridFilterPanel.js +540 -0
- package/lib/module/DataGridFilterPanel.js.map +1 -0
- package/lib/module/adapter/columnTypes.js +240 -0
- package/lib/module/adapter/columnTypes.js.map +1 -0
- package/lib/module/adapter/columns.js +137 -4
- package/lib/module/adapter/columns.js.map +1 -1
- package/lib/module/adapter/filterOperators.js +406 -0
- package/lib/module/adapter/filterOperators.js.map +1 -0
- package/lib/module/adapter/pinning.js +94 -0
- package/lib/module/adapter/pinning.js.map +1 -0
- package/lib/module/adapter/selectColumn.js +11 -1
- package/lib/module/adapter/selectColumn.js.map +1 -1
- package/lib/module/adapter/treeData.js +187 -0
- package/lib/module/adapter/treeData.js.map +1 -0
- package/lib/module/index.js +2 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/numberCells.js +275 -0
- package/lib/module/numberCells.js.map +1 -0
- package/lib/module/styles.js +106 -0
- package/lib/module/styles.js.map +1 -1
- package/lib/module/types.js +38 -0
- package/lib/module/types.js.map +1 -1
- package/lib/module/useDataGridTable.js +238 -22
- package/lib/module/useDataGridTable.js.map +1 -1
- package/lib/typescript/DataGrid.d.ts.map +1 -1
- package/lib/typescript/DataGridFilterPanel.d.ts +52 -0
- package/lib/typescript/DataGridFilterPanel.d.ts.map +1 -0
- package/lib/typescript/adapter/columnTypes.d.ts +32 -0
- package/lib/typescript/adapter/columnTypes.d.ts.map +1 -0
- package/lib/typescript/adapter/columns.d.ts +14 -5
- package/lib/typescript/adapter/columns.d.ts.map +1 -1
- package/lib/typescript/adapter/filterOperators.d.ts +43 -0
- package/lib/typescript/adapter/filterOperators.d.ts.map +1 -0
- package/lib/typescript/adapter/pinning.d.ts +26 -0
- package/lib/typescript/adapter/pinning.d.ts.map +1 -0
- package/lib/typescript/adapter/selectColumn.d.ts +8 -0
- package/lib/typescript/adapter/selectColumn.d.ts.map +1 -1
- package/lib/typescript/adapter/treeData.d.ts +36 -0
- package/lib/typescript/adapter/treeData.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +4 -1
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/numberCells.d.ts +46 -0
- package/lib/typescript/numberCells.d.ts.map +1 -0
- package/lib/typescript/styles.d.ts +32 -0
- package/lib/typescript/styles.d.ts.map +1 -1
- package/lib/typescript/types.d.ts +154 -7
- package/lib/typescript/types.d.ts.map +1 -1
- package/lib/typescript/useDataGridTable.d.ts +40 -4
- package/lib/typescript/useDataGridTable.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/DataGrid.tsx +745 -95
- package/src/DataGridFilterPanel.tsx +648 -0
- package/src/adapter/columnTypes.ts +327 -0
- package/src/adapter/columns.test.ts +75 -1
- package/src/adapter/columns.ts +192 -3
- package/src/adapter/filterOperators.test.ts +292 -0
- package/src/adapter/filterOperators.ts +524 -0
- package/src/adapter/pinning.ts +134 -0
- package/src/adapter/selectColumn.ts +12 -1
- package/src/adapter/treeData.ts +228 -0
- package/src/index.ts +19 -0
- package/src/numberCells.tsx +379 -0
- package/src/styles.ts +131 -0
- package/src/types.ts +190 -7
- package/src/useDataGridTable.test.ts +69 -0
- package/src/useDataGridTable.ts +338 -17
package/src/useDataGridTable.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import { useMemo } from 'react';
|
|
1
|
+
import { useMemo, useState } from 'react';
|
|
2
2
|
import {
|
|
3
3
|
columnFilteringFeature,
|
|
4
|
+
columnPinningFeature,
|
|
5
|
+
columnVisibilityFeature,
|
|
4
6
|
createFilteredRowModel,
|
|
5
7
|
createPaginatedRowModel,
|
|
6
8
|
createSortedRowModel,
|
|
7
9
|
filterFn_includesString,
|
|
8
10
|
globalFilteringFeature,
|
|
11
|
+
rowExpandingFeature,
|
|
9
12
|
rowPaginationFeature,
|
|
10
13
|
rowSelectionFeature,
|
|
11
14
|
rowSortingFeature,
|
|
@@ -14,28 +17,79 @@ import {
|
|
|
14
17
|
tableFeatures,
|
|
15
18
|
useTable,
|
|
16
19
|
type ColumnFiltersState,
|
|
20
|
+
type ColumnPinningState,
|
|
17
21
|
type PaginationState,
|
|
18
22
|
type RowSelectionState,
|
|
19
23
|
type SortingState,
|
|
20
24
|
} from '@tanstack/react-table';
|
|
21
|
-
import { createSelectColumn } from './adapter/selectColumn';
|
|
25
|
+
import { createDetailPanelToggleColumn, createSelectColumn } from './adapter/selectColumn';
|
|
26
|
+
import {
|
|
27
|
+
applyTreeSelection,
|
|
28
|
+
buildTreeIndex,
|
|
29
|
+
computeTreeSelection,
|
|
30
|
+
keepMatchesWithAncestors,
|
|
31
|
+
selectionScope,
|
|
32
|
+
type GridTreeRowLike,
|
|
33
|
+
type GridTreeSelectionStatus,
|
|
34
|
+
} from './adapter/treeData';
|
|
22
35
|
import { applyUpdater, gridColDefToColumnDef } from './adapter/columns';
|
|
36
|
+
import {
|
|
37
|
+
filterFn_displayText,
|
|
38
|
+
metaUsesDisplayFilter,
|
|
39
|
+
normalizeFilterQuery,
|
|
40
|
+
sortFn_boolean,
|
|
41
|
+
sortFn_datetime,
|
|
42
|
+
sortFn_number,
|
|
43
|
+
sortFn_selectLabel,
|
|
44
|
+
untypedCellIncludesQuery,
|
|
45
|
+
} from './adapter/columnTypes';
|
|
46
|
+
import {
|
|
47
|
+
filterOperatorNeedsValue,
|
|
48
|
+
isActiveFilterItem,
|
|
49
|
+
isBlankFilterValue,
|
|
50
|
+
isFilterValueGroup,
|
|
51
|
+
isOperatorFilterValue,
|
|
52
|
+
rowMatchesFilterItem,
|
|
53
|
+
} from './adapter/filterOperators';
|
|
23
54
|
import type {
|
|
24
55
|
GridColDef,
|
|
56
|
+
GridColumnVisibilityModel,
|
|
25
57
|
GridFeatureMode,
|
|
58
|
+
GridFilterItem,
|
|
26
59
|
GridFilterModel,
|
|
60
|
+
GridLogicOperator,
|
|
27
61
|
GridPaginationModel,
|
|
28
62
|
GridRowId,
|
|
29
63
|
GridRowSelectionModel,
|
|
64
|
+
GridRowSelectionPropagation,
|
|
30
65
|
GridRowsProp,
|
|
31
66
|
GridSortModel,
|
|
67
|
+
GridTreeNodeParams,
|
|
32
68
|
GridValidRowModel,
|
|
33
69
|
} from './types';
|
|
34
|
-
import { SELECT_COLUMN_ID } from './types';
|
|
70
|
+
import { DETAIL_PANEL_TOGGLE_ID, SELECT_COLUMN_ID } from './types';
|
|
71
|
+
|
|
72
|
+
function gridGlobalFilterFn(
|
|
73
|
+
row: Parameters<typeof filterFn_displayText>[0],
|
|
74
|
+
columnId: string,
|
|
75
|
+
filterValue: unknown,
|
|
76
|
+
): boolean {
|
|
77
|
+
if (columnId === SELECT_COLUMN_ID || columnId === DETAIL_PANEL_TOGGLE_ID) {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
const meta = row.getAllCells().find((cell) => cell.column.id === columnId)?.column.columnDef.meta;
|
|
81
|
+
if (metaUsesDisplayFilter(meta)) {
|
|
82
|
+
return filterFn_displayText(row, columnId, filterValue);
|
|
83
|
+
}
|
|
84
|
+
return untypedCellIncludesQuery(row.getValue(columnId), normalizeFilterQuery(filterValue));
|
|
85
|
+
}
|
|
35
86
|
|
|
36
87
|
const features = tableFeatures({
|
|
37
88
|
columnFilteringFeature,
|
|
89
|
+
columnPinningFeature,
|
|
90
|
+
columnVisibilityFeature,
|
|
38
91
|
globalFilteringFeature,
|
|
92
|
+
rowExpandingFeature,
|
|
39
93
|
rowSortingFeature,
|
|
40
94
|
rowPaginationFeature,
|
|
41
95
|
rowSelectionFeature,
|
|
@@ -43,7 +97,14 @@ const features = tableFeatures({
|
|
|
43
97
|
sortedRowModel: createSortedRowModel(),
|
|
44
98
|
paginatedRowModel: createPaginatedRowModel(),
|
|
45
99
|
filterFns: { includesString: filterFn_includesString },
|
|
46
|
-
sortFns: {
|
|
100
|
+
sortFns: {
|
|
101
|
+
alphanumeric: sortFn_alphanumeric,
|
|
102
|
+
text: sortFn_text,
|
|
103
|
+
number: sortFn_number,
|
|
104
|
+
datetime: sortFn_datetime,
|
|
105
|
+
boolean: sortFn_boolean,
|
|
106
|
+
selectLabel: sortFn_selectLabel,
|
|
107
|
+
},
|
|
47
108
|
});
|
|
48
109
|
|
|
49
110
|
export function sortModelToSortingState(model: GridSortModel): SortingState {
|
|
@@ -81,16 +142,55 @@ function columnFilterValueToString(value: unknown): string {
|
|
|
81
142
|
return '';
|
|
82
143
|
}
|
|
83
144
|
|
|
145
|
+
/**
|
|
146
|
+
* Items without an `operator` keep today's text filter. Items with one carry the operator and
|
|
147
|
+
* typed operand into the column filter. An item whose operator needs a value but has none is
|
|
148
|
+
* dropped, so `isEmpty` / `isNotEmpty` survive a blank `value` and nothing else does.
|
|
149
|
+
*/
|
|
84
150
|
export function filterModelToColumnFilters(model: GridFilterModel): ColumnFiltersState {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
151
|
+
const valuesByField = new Map<string, unknown[]>();
|
|
152
|
+
for (const item of model) {
|
|
153
|
+
let value: unknown;
|
|
154
|
+
if (item.operator !== undefined) {
|
|
155
|
+
if (filterOperatorNeedsValue(item.operator) && isBlankFilterValue(item.value)) {
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
value = { operator: item.operator, value: item.value };
|
|
159
|
+
} else {
|
|
160
|
+
const text = columnFilterValueToString(item.value);
|
|
161
|
+
if (text.trim().length === 0) {
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
value = text;
|
|
165
|
+
}
|
|
166
|
+
const values = valuesByField.get(item.field);
|
|
167
|
+
if (values) {
|
|
168
|
+
values.push(value);
|
|
169
|
+
} else {
|
|
170
|
+
valuesByField.set(item.field, [value]);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return [...valuesByField].map(([id, values]) => ({
|
|
174
|
+
id,
|
|
175
|
+
value: values.length === 1 ? values[0] : { items: values },
|
|
176
|
+
}));
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function columnFilterValueToItem(field: string, value: unknown): GridFilterItem {
|
|
180
|
+
if (isOperatorFilterValue(value)) {
|
|
181
|
+
return { field, operator: value.operator, value: value.value };
|
|
182
|
+
}
|
|
183
|
+
return { field, value: columnFilterValueToString(value) };
|
|
88
184
|
}
|
|
89
185
|
|
|
90
186
|
export function columnFiltersToFilterModel(state: ColumnFiltersState): GridFilterModel {
|
|
91
187
|
return state
|
|
92
188
|
.filter((item) => item.id !== SELECT_COLUMN_ID)
|
|
93
|
-
.
|
|
189
|
+
.flatMap((item) =>
|
|
190
|
+
isFilterValueGroup(item.value)
|
|
191
|
+
? item.value.items.map((value) => columnFilterValueToItem(item.id, value))
|
|
192
|
+
: [columnFilterValueToItem(item.id, item.value)],
|
|
193
|
+
);
|
|
94
194
|
}
|
|
95
195
|
|
|
96
196
|
function selectionIdKey(id: GridRowId): string {
|
|
@@ -185,12 +285,36 @@ interface UseDataGridTableParams<R extends GridValidRowModel> {
|
|
|
185
285
|
onPaginationModelChange: (model: GridPaginationModel) => void;
|
|
186
286
|
filterModel: GridFilterModel;
|
|
187
287
|
onFilterModelChange: (model: GridFilterModel) => void;
|
|
288
|
+
filterLogicOperator: GridLogicOperator;
|
|
188
289
|
quickFilter: string;
|
|
189
290
|
onQuickFilterChange: (value: string) => void;
|
|
190
291
|
rowSelectionModel: GridRowSelectionModel;
|
|
191
292
|
onRowSelectionModelChange: (model: GridRowSelectionModel) => void;
|
|
293
|
+
columnPinning: ColumnPinningState;
|
|
294
|
+
columnVisibility?: GridColumnVisibilityModel;
|
|
295
|
+
detailPanel?: boolean;
|
|
296
|
+
treeData?: boolean;
|
|
297
|
+
getTreeDataPath?: (row: R) => readonly string[];
|
|
298
|
+
defaultGroupingExpansionDepth?: number;
|
|
299
|
+
isGroupExpandedByDefault?: (node: GridTreeNodeParams<R>) => boolean;
|
|
300
|
+
rowSelectionPropagation?: GridRowSelectionPropagation;
|
|
192
301
|
}
|
|
193
302
|
|
|
303
|
+
export interface DataGridTreeState {
|
|
304
|
+
isRowExpanded: (key: string) => boolean;
|
|
305
|
+
toggleRowExpanded: (key: string) => void;
|
|
306
|
+
selectionStatus: (key: string) => GridTreeSelectionStatus;
|
|
307
|
+
toggleRowSelected: (row: GridTreeRowLike) => void;
|
|
308
|
+
toggleAllRowsSelected: () => void;
|
|
309
|
+
headerSelection: { checked: boolean; indeterminate: boolean };
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
const EMPTY_EXPANSION: Readonly<Record<string, boolean>> = {};
|
|
313
|
+
const EMPTY_FILTER_EXPANSION: Readonly<Partial<Record<string, boolean>>> = {};
|
|
314
|
+
const EMPTY_VISIBILITY: GridColumnVisibilityModel = {};
|
|
315
|
+
|
|
316
|
+
let warnedMissingTreeDataPath = false;
|
|
317
|
+
|
|
194
318
|
export function useDataGridTable<R extends GridValidRowModel>({
|
|
195
319
|
rows,
|
|
196
320
|
columns,
|
|
@@ -207,13 +331,68 @@ export function useDataGridTable<R extends GridValidRowModel>({
|
|
|
207
331
|
onPaginationModelChange,
|
|
208
332
|
filterModel,
|
|
209
333
|
onFilterModelChange,
|
|
334
|
+
filterLogicOperator,
|
|
210
335
|
quickFilter,
|
|
211
336
|
onQuickFilterChange,
|
|
212
337
|
rowSelectionModel,
|
|
213
338
|
onRowSelectionModelChange,
|
|
339
|
+
columnPinning,
|
|
340
|
+
columnVisibility = EMPTY_VISIBILITY,
|
|
341
|
+
detailPanel = false,
|
|
342
|
+
treeData: treeDataProp = false,
|
|
343
|
+
getTreeDataPath,
|
|
344
|
+
defaultGroupingExpansionDepth = 0,
|
|
345
|
+
isGroupExpandedByDefault,
|
|
346
|
+
rowSelectionPropagation,
|
|
214
347
|
}: UseDataGridTableParams<R>) {
|
|
215
|
-
const
|
|
348
|
+
const treeData = treeDataProp && getTreeDataPath !== undefined;
|
|
349
|
+
if (__DEV__ && treeDataProp && getTreeDataPath === undefined && !warnedMissingTreeDataPath) {
|
|
350
|
+
warnedMissingTreeDataPath = true;
|
|
351
|
+
console.warn('[DataGrid] `treeData` needs `getTreeDataPath`. Rendering flat rows.');
|
|
352
|
+
}
|
|
353
|
+
const propagateDescendants = rowSelectionPropagation?.descendants ?? true;
|
|
354
|
+
const propagateParents = rowSelectionPropagation?.parents ?? true;
|
|
355
|
+
|
|
356
|
+
const orFilterItems = useMemo(() => {
|
|
357
|
+
if (filterLogicOperator !== 'or' || filterMode === 'server') {
|
|
358
|
+
return undefined;
|
|
359
|
+
}
|
|
360
|
+
const active = filterModel.filter(isActiveFilterItem);
|
|
361
|
+
return active.length > 1 ? active : undefined;
|
|
362
|
+
}, [filterLogicOperator, filterMode, filterModel]);
|
|
363
|
+
|
|
364
|
+
const keyOf = useMemo(() => (row: R) => selectionIdKey(resolveRowId(row, getRowId)), [getRowId]);
|
|
365
|
+
|
|
366
|
+
const fullTree = useMemo(
|
|
367
|
+
() => (treeData ? buildTreeIndex(rows, getTreeDataPath, keyOf) : undefined),
|
|
368
|
+
[getTreeDataPath, keyOf, rows, treeData],
|
|
369
|
+
);
|
|
370
|
+
|
|
371
|
+
const data = useMemo(() => {
|
|
372
|
+
if (!orFilterItems) {
|
|
373
|
+
return [...rows];
|
|
374
|
+
}
|
|
375
|
+
const filterableColumns = new Map(
|
|
376
|
+
columns.filter((col) => col.filterable !== false).map((col) => [col.field, col]),
|
|
377
|
+
);
|
|
378
|
+
const matches = (row: R) =>
|
|
379
|
+
orFilterItems.some((item) => {
|
|
380
|
+
const col = filterableColumns.get(item.field);
|
|
381
|
+
return col !== undefined && rowMatchesFilterItem(col, row, item);
|
|
382
|
+
});
|
|
383
|
+
return fullTree
|
|
384
|
+
? keepMatchesWithAncestors(rows, fullTree, keyOf, matches)
|
|
385
|
+
: rows.filter(matches);
|
|
386
|
+
}, [columns, fullTree, keyOf, orFilterItems, rows]);
|
|
216
387
|
const allIds = useMemo(() => data.map((row) => resolveRowId(row, getRowId)), [data, getRowId]);
|
|
388
|
+
const allRowIds = useMemo(() => rows.map((row) => resolveRowId(row, getRowId)), [rows, getRowId]);
|
|
389
|
+
|
|
390
|
+
const tree = useMemo(() => {
|
|
391
|
+
if (!fullTree || !getTreeDataPath) {
|
|
392
|
+
return undefined;
|
|
393
|
+
}
|
|
394
|
+
return data.length === rows.length ? fullTree : buildTreeIndex(data, getTreeDataPath, keyOf);
|
|
395
|
+
}, [data, fullTree, getTreeDataPath, keyOf, rows.length]);
|
|
217
396
|
|
|
218
397
|
const columnDefs = useMemo(() => {
|
|
219
398
|
const mapped = columns.map((col) => {
|
|
@@ -223,17 +402,93 @@ export function useDataGridTable<R extends GridValidRowModel>({
|
|
|
223
402
|
}
|
|
224
403
|
return def;
|
|
225
404
|
});
|
|
226
|
-
return
|
|
227
|
-
|
|
405
|
+
return [
|
|
406
|
+
...(checkboxSelection && !treeData ? [createSelectColumn()] : []),
|
|
407
|
+
...(detailPanel ? [createDetailPanelToggleColumn()] : []),
|
|
408
|
+
...mapped,
|
|
409
|
+
];
|
|
410
|
+
}, [checkboxSelection, columns, detailPanel, disableColumnSorting, treeData]);
|
|
228
411
|
|
|
229
412
|
const sortingState = useMemo(() => sortModelToSortingState(sortModel), [sortModel]);
|
|
230
413
|
const paginationState = useMemo(() => paginationModelToState(paginationModel), [paginationModel]);
|
|
231
|
-
const columnFilterState = useMemo(
|
|
414
|
+
const columnFilterState = useMemo(
|
|
415
|
+
() => (orFilterItems ? [] : filterModelToColumnFilters(filterModel)),
|
|
416
|
+
[filterModel, orFilterItems],
|
|
417
|
+
);
|
|
232
418
|
const rowSelectionState = useMemo(
|
|
233
|
-
() => selectionModelToRowSelection(rowSelectionModel, allIds),
|
|
234
|
-
[rowSelectionModel, allIds],
|
|
419
|
+
() => selectionModelToRowSelection(rowSelectionModel, treeData ? allRowIds : allIds),
|
|
420
|
+
[rowSelectionModel, treeData, allRowIds, allIds],
|
|
235
421
|
);
|
|
236
422
|
|
|
423
|
+
const filterSignature =
|
|
424
|
+
treeData &&
|
|
425
|
+
filterMode === 'client' &&
|
|
426
|
+
(quickFilter.trim().length > 0 || filterModel.some(isActiveFilterItem))
|
|
427
|
+
? JSON.stringify([quickFilter, filterModel, filterLogicOperator])
|
|
428
|
+
: '';
|
|
429
|
+
const [userExpanded, setUserExpanded] = useState<Partial<Record<string, boolean>>>({});
|
|
430
|
+
const [filterExpansion, setFilterExpansion] = useState<{
|
|
431
|
+
signature: string;
|
|
432
|
+
expanded: Partial<Record<string, boolean>>;
|
|
433
|
+
}>({ signature: '', expanded: {} });
|
|
434
|
+
const filterExpanded =
|
|
435
|
+
filterSignature !== '' && filterExpansion.signature === filterSignature
|
|
436
|
+
? filterExpansion.expanded
|
|
437
|
+
: EMPTY_FILTER_EXPANSION;
|
|
438
|
+
|
|
439
|
+
const expandedState = useMemo(() => {
|
|
440
|
+
if (!tree) {
|
|
441
|
+
return EMPTY_EXPANSION;
|
|
442
|
+
}
|
|
443
|
+
const isExpanded = (key: string): boolean => {
|
|
444
|
+
if (filterSignature !== '') {
|
|
445
|
+
return filterExpanded[key] ?? true;
|
|
446
|
+
}
|
|
447
|
+
const own = userExpanded[key];
|
|
448
|
+
if (own !== undefined) {
|
|
449
|
+
return own;
|
|
450
|
+
}
|
|
451
|
+
const row = tree.rowOf.get(key);
|
|
452
|
+
const depth = fullTree?.depthOf.get(key) ?? tree.depthOf.get(key) ?? 0;
|
|
453
|
+
if (row !== undefined && isGroupExpandedByDefault) {
|
|
454
|
+
return isGroupExpandedByDefault({ id: resolveRowId(row, getRowId), row, depth });
|
|
455
|
+
}
|
|
456
|
+
return defaultGroupingExpansionDepth === -1 || depth < defaultGroupingExpansionDepth;
|
|
457
|
+
};
|
|
458
|
+
const state: Record<string, boolean> = {};
|
|
459
|
+
for (const key of tree.childKeysOf.keys()) {
|
|
460
|
+
if (isExpanded(key)) {
|
|
461
|
+
state[key] = true;
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
return state;
|
|
465
|
+
}, [
|
|
466
|
+
tree,
|
|
467
|
+
fullTree,
|
|
468
|
+
filterSignature,
|
|
469
|
+
filterExpanded,
|
|
470
|
+
userExpanded,
|
|
471
|
+
isGroupExpandedByDefault,
|
|
472
|
+
defaultGroupingExpansionDepth,
|
|
473
|
+
getRowId,
|
|
474
|
+
]);
|
|
475
|
+
const isRowExpanded = (key: string) => key in expandedState;
|
|
476
|
+
|
|
477
|
+
const toggleRowExpanded = (key: string) => {
|
|
478
|
+
const next = !isRowExpanded(key);
|
|
479
|
+
if (filterSignature !== '') {
|
|
480
|
+
setFilterExpansion((previous) => ({
|
|
481
|
+
signature: filterSignature,
|
|
482
|
+
expanded: {
|
|
483
|
+
...(previous.signature === filterSignature ? previous.expanded : {}),
|
|
484
|
+
[key]: next,
|
|
485
|
+
},
|
|
486
|
+
}));
|
|
487
|
+
return;
|
|
488
|
+
}
|
|
489
|
+
setUserExpanded((previous) => ({ ...previous, [key]: next }));
|
|
490
|
+
};
|
|
491
|
+
|
|
237
492
|
const resetPaginationPage = () => {
|
|
238
493
|
if (paginationModel.page !== 0) {
|
|
239
494
|
onPaginationModelChange({ ...paginationModel, page: 0 });
|
|
@@ -257,10 +512,14 @@ export function useDataGridTable<R extends GridValidRowModel>({
|
|
|
257
512
|
const table = useTable({
|
|
258
513
|
features,
|
|
259
514
|
columns: columnDefs,
|
|
260
|
-
data,
|
|
261
|
-
getRowId: (row) =>
|
|
515
|
+
data: tree ? tree.roots : data,
|
|
516
|
+
getRowId: (row) => keyOf(row),
|
|
517
|
+
getSubRows: tree ? (row) => tree.childrenOf.get(row) : undefined,
|
|
518
|
+
filterFromLeafRows: treeData,
|
|
519
|
+
paginateExpandedRows: false,
|
|
262
520
|
enableMultiSort: false,
|
|
263
521
|
enableMultiRowSelection: true,
|
|
522
|
+
globalFilterFn: gridGlobalFilterFn,
|
|
264
523
|
manualPagination: paginationMode === 'server',
|
|
265
524
|
manualSorting: sortingMode === 'server',
|
|
266
525
|
manualFiltering: filterMode === 'server',
|
|
@@ -272,6 +531,9 @@ export function useDataGridTable<R extends GridValidRowModel>({
|
|
|
272
531
|
columnFilters: columnFilterState,
|
|
273
532
|
globalFilter: quickFilter,
|
|
274
533
|
rowSelection: rowSelectionState,
|
|
534
|
+
columnPinning,
|
|
535
|
+
columnVisibility,
|
|
536
|
+
expanded: expandedState,
|
|
275
537
|
},
|
|
276
538
|
onSortingChange: (updater) => {
|
|
277
539
|
const next = applyUpdater(updater, sortingState);
|
|
@@ -297,5 +559,64 @@ export function useDataGridTable<R extends GridValidRowModel>({
|
|
|
297
559
|
},
|
|
298
560
|
});
|
|
299
561
|
|
|
300
|
-
|
|
562
|
+
const setFilterModel = (model: GridFilterModel) => {
|
|
563
|
+
onFilterModelChange(model);
|
|
564
|
+
resetPaginationPage();
|
|
565
|
+
};
|
|
566
|
+
|
|
567
|
+
const treeSelection = useMemo(() => {
|
|
568
|
+
if (!fullTree) {
|
|
569
|
+
return undefined;
|
|
570
|
+
}
|
|
571
|
+
const selectedKeys = new Set(Object.keys(rowSelectionState));
|
|
572
|
+
return {
|
|
573
|
+
selectedKeys,
|
|
574
|
+
statuses: computeTreeSelection(fullTree, selectedKeys, propagateParents),
|
|
575
|
+
};
|
|
576
|
+
}, [fullTree, propagateParents, rowSelectionState]);
|
|
577
|
+
|
|
578
|
+
let treeState: DataGridTreeState | undefined;
|
|
579
|
+
if (fullTree && treeSelection) {
|
|
580
|
+
const { selectedKeys, statuses } = treeSelection;
|
|
581
|
+
const selectionStatus = (key: string) => statuses.get(key) ?? 'none';
|
|
582
|
+
const commit = (scope: { targets: string[]; units: string[] }) => {
|
|
583
|
+
const value = !scope.units.every((key) => selectionStatus(key) === 'all');
|
|
584
|
+
const next = applyTreeSelection(
|
|
585
|
+
fullTree,
|
|
586
|
+
selectedKeys,
|
|
587
|
+
scope.targets,
|
|
588
|
+
value,
|
|
589
|
+
propagateParents,
|
|
590
|
+
);
|
|
591
|
+
onRowSelectionModelChange(
|
|
592
|
+
rowSelectionToModel(
|
|
593
|
+
Object.fromEntries([...next].map((key) => [key, true])),
|
|
594
|
+
rowSelectionModel,
|
|
595
|
+
allRowIds,
|
|
596
|
+
),
|
|
597
|
+
);
|
|
598
|
+
};
|
|
599
|
+
const filtered = table.getFilteredRowModel();
|
|
600
|
+
const headerScope = propagateDescendants
|
|
601
|
+
? selectionScope(filtered.rows, fullTree, true)
|
|
602
|
+
: selectionScope(filtered.flatRows, fullTree, false);
|
|
603
|
+
const selectedUnits = headerScope.units.filter((key) => selectionStatus(key) !== 'none');
|
|
604
|
+
const allUnitsSelected =
|
|
605
|
+
headerScope.units.length > 0 &&
|
|
606
|
+
headerScope.units.every((key) => selectionStatus(key) === 'all');
|
|
607
|
+
|
|
608
|
+
treeState = {
|
|
609
|
+
isRowExpanded,
|
|
610
|
+
toggleRowExpanded,
|
|
611
|
+
selectionStatus,
|
|
612
|
+
toggleRowSelected: (row) => commit(selectionScope([row], fullTree, propagateDescendants)),
|
|
613
|
+
toggleAllRowsSelected: () => commit(headerScope),
|
|
614
|
+
headerSelection: {
|
|
615
|
+
checked: allUnitsSelected,
|
|
616
|
+
indeterminate: !allUnitsSelected && selectedUnits.length > 0,
|
|
617
|
+
},
|
|
618
|
+
};
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
return { table, setQuickFilter, setColumnFilter, setFilterModel, tree: treeState };
|
|
301
622
|
}
|