@homebound/beam 2.117.4 → 2.118.2
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/GridTable.d.ts +1 -0
- package/dist/components/Table/GridTable.js +52 -36
- package/dist/components/Table/RowState.d.ts +4 -2
- package/dist/components/Table/RowState.js +40 -9
- package/dist/components/Table/sortRows.d.ts +3 -3
- package/dist/components/Table/sortRows.js +2 -5
- package/dist/components/Table/useSortState.d.ts +2 -1
- package/dist/components/Table/useSortState.js +11 -5
- package/package.json +1 -1
|
@@ -149,6 +149,7 @@ export interface GridTableProps<R extends Kinded, S, X> {
|
|
|
149
149
|
/** Whether the header row should be sticky. */
|
|
150
150
|
stickyHeader?: boolean;
|
|
151
151
|
stickyOffset?: string;
|
|
152
|
+
/** Configures sorting via a hash, does not need to be stable. */
|
|
152
153
|
sorting?: GridSortConfig<S>;
|
|
153
154
|
/** Shown in the first row slot, if there are no rows to show, i.e. 'No rows found'. */
|
|
154
155
|
fallbackMessage?: string;
|
|
@@ -85,7 +85,7 @@ exports.setGridTableDefaults = setGridTableDefaults;
|
|
|
85
85
|
*/
|
|
86
86
|
function GridTable(props) {
|
|
87
87
|
var _a, _b, _c, _d;
|
|
88
|
-
const { id = "gridTable", as = "div", columns, rows, style = defaults.style, rowStyles, stickyHeader = defaults.stickyHeader, stickyOffset = "0", xss,
|
|
88
|
+
const { id = "gridTable", as = "div", columns, rows, style = defaults.style, rowStyles, stickyHeader = defaults.stickyHeader, stickyOffset = "0", xss, filter, filterMaxRows, fallbackMessage = "No rows found.", infoMessage, setRowCount, observeRows, persistCollapse, api: callerApi, resizeTarget, activeRowId, } = props;
|
|
89
89
|
// Create a ref that always contains the latest rows, for our effectively-singleton RowState to use
|
|
90
90
|
const rowsRef = (0, react_1.useRef)(rows);
|
|
91
91
|
rowsRef.current = rows;
|
|
@@ -127,25 +127,49 @@ function GridTable(props) {
|
|
|
127
127
|
// (or us) is resetting component state more than necessary, so we track render counts from
|
|
128
128
|
// here instead.
|
|
129
129
|
const { getCount } = (0, useRenderCount_1.useRenderCount)();
|
|
130
|
-
const
|
|
130
|
+
const columnSizes = (0, columnSizes_1.useSetupColumnSizes)(style, columns, tableRef, resizeTarget);
|
|
131
|
+
// Make a single copy of our current collapsed state, so we'll have a single observer.
|
|
132
|
+
const collapsedIds = (0, hooks_1.useComputed)(() => rowState.collapsedIds, [rowState]);
|
|
133
|
+
const [sortState, setSortKey, sortOn] = (0, useSortState_1.useSortState)(columns, props.sorting);
|
|
131
134
|
const maybeSorted = (0, react_1.useMemo)(() => {
|
|
132
|
-
if (
|
|
135
|
+
if (sortOn === "client" && sortState) {
|
|
133
136
|
// If using client-side sort, the sortState use S = number
|
|
134
137
|
return (0, sortRows_1.sortRows)(columns, rows, sortState);
|
|
135
138
|
}
|
|
136
139
|
return rows;
|
|
137
|
-
}, [columns, rows,
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
// Filter + flatten + component-ize the sorted rows.
|
|
142
|
-
let [headerRows, filteredRows] = (0, react_1.useMemo)(() => {
|
|
140
|
+
}, [columns, rows, sortOn, sortState]);
|
|
141
|
+
// Filter rows - ensures parent rows remain in the list if any children match the filter.
|
|
142
|
+
const filterRows = (0, react_1.useCallback)((acc, row) => {
|
|
143
|
+
var _a, _b, _c;
|
|
143
144
|
// Break up "foo bar" into `[foo, bar]` and a row must match both `foo` and `bar`
|
|
144
145
|
const filters = (filter && filter.split(/ +/)) || [];
|
|
146
|
+
const matches = row.kind === "header" ||
|
|
147
|
+
filters.length === 0 ||
|
|
148
|
+
!!row.pin ||
|
|
149
|
+
filters.every((f) => columns.map((c) => applyRowFn(c, row, api)).some((maybeContent) => matchesFilter(maybeContent, f)));
|
|
150
|
+
// If the row matches, add it in
|
|
151
|
+
if (matches) {
|
|
152
|
+
return acc.concat([[row, (_b = (_a = row.children) === null || _a === void 0 ? void 0 : _a.reduce(filterRows, [])) !== null && _b !== void 0 ? _b : []]]);
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
// Otherwise, maybe one of the children match.
|
|
156
|
+
const isCollapsed = collapsedIds.includes(row.id);
|
|
157
|
+
if (!isCollapsed && !!((_c = row.children) === null || _c === void 0 ? void 0 : _c.length)) {
|
|
158
|
+
const matchedChildren = row.children.reduce(filterRows, []);
|
|
159
|
+
// If some children did match, then add the parent row with its matched children.
|
|
160
|
+
if (matchedChildren.length > 0) {
|
|
161
|
+
return acc.concat([[row, matchedChildren]]);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return acc;
|
|
166
|
+
}, [filter, collapsedIds, columns]);
|
|
167
|
+
// Flatten + component-ize the sorted rows.
|
|
168
|
+
let [headerRows, filteredRows] = (0, react_1.useMemo)(() => {
|
|
145
169
|
function makeRowComponent(row, level) {
|
|
146
170
|
// We only pass sortState to header rows, b/c non-headers rows shouldn't have to re-render on sorting
|
|
147
171
|
// changes, and so by not passing the sortProps, it means the data rows' React.memo will still cache them.
|
|
148
|
-
const sortProps = row.kind === "header" ? {
|
|
172
|
+
const sortProps = row.kind === "header" ? { sortOn, sortState, setSortKey } : { sortOn };
|
|
149
173
|
const RowComponent = observeRows ? ObservedGridRow : MemoizedGridRow;
|
|
150
174
|
return ((0, jsx_runtime_1.jsx)(RowComponent, Object.assign({}, {
|
|
151
175
|
as,
|
|
@@ -168,48 +192,40 @@ function GridTable(props) {
|
|
|
168
192
|
const filteredRows = [];
|
|
169
193
|
// Misc state to track our nested card-ification, i.e. interleaved actual rows + chrome rows
|
|
170
194
|
const nestedCards = !!style.nestedCards && new nestedCards_1.NestedCards(columns, filteredRows, style.nestedCards);
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
const matches = filters.length === 0 ||
|
|
175
|
-
row.pin ||
|
|
176
|
-
filters.every((filter) => columns.map((c) => applyRowFn(c, row, api)).some((maybeContent) => matchesFilter(maybeContent, filter)));
|
|
177
|
-
let isCard = false;
|
|
178
|
-
// Even if we don't pass the filter, one of our children might, so we continue on after this check
|
|
179
|
-
if (matches) {
|
|
180
|
-
isCard = nestedCards && nestedCards.maybeOpenCard(row);
|
|
181
|
-
filteredRows.push([row, makeRowComponent(row, level)]);
|
|
182
|
-
}
|
|
195
|
+
function visit([row, children], level) {
|
|
196
|
+
let isCard = nestedCards && nestedCards.maybeOpenCard(row);
|
|
197
|
+
filteredRows.push([row, makeRowComponent(row, level)]);
|
|
183
198
|
const isCollapsed = collapsedIds.includes(row.id);
|
|
184
|
-
if (!isCollapsed &&
|
|
185
|
-
nestedCards &&
|
|
186
|
-
visitRows(
|
|
199
|
+
if (!isCollapsed && children.length) {
|
|
200
|
+
nestedCards && nestedCards.addSpacer();
|
|
201
|
+
visitRows(children, isCard, level + 1);
|
|
187
202
|
}
|
|
188
203
|
!(0, nestedCards_1.isLeafRow)(row) && isCard && nestedCards && nestedCards.closeCard();
|
|
189
204
|
}
|
|
190
205
|
function visitRows(rows, addSpacer, level) {
|
|
191
206
|
const length = rows.length;
|
|
192
207
|
rows.forEach((row, i) => {
|
|
193
|
-
if (row.kind === "header") {
|
|
194
|
-
headerRows.push([row, makeRowComponent(row, level)]);
|
|
208
|
+
if (row[0].kind === "header") {
|
|
209
|
+
headerRows.push([row[0], makeRowComponent(row[0], level)]);
|
|
195
210
|
return;
|
|
196
211
|
}
|
|
197
212
|
visit(row, level);
|
|
198
213
|
addSpacer && nestedCards && i !== length - 1 && nestedCards.addSpacer();
|
|
199
214
|
});
|
|
200
215
|
}
|
|
216
|
+
// Call `visitRows` with our a pre-filtered set list
|
|
201
217
|
// If nestedCards is set, we assume the top-level kind is a card, and so should add spacers between them
|
|
202
|
-
visitRows(maybeSorted, !!nestedCards, 0);
|
|
218
|
+
visitRows(maybeSorted.reduce(filterRows, []), !!nestedCards, 0);
|
|
203
219
|
nestedCards && nestedCards.done();
|
|
204
220
|
return [headerRows, filteredRows];
|
|
205
221
|
}, [
|
|
206
222
|
as,
|
|
207
223
|
maybeSorted,
|
|
208
224
|
columns,
|
|
209
|
-
|
|
225
|
+
filterRows,
|
|
210
226
|
style,
|
|
211
227
|
rowStyles,
|
|
212
|
-
|
|
228
|
+
sortOn,
|
|
213
229
|
setSortKey,
|
|
214
230
|
sortState,
|
|
215
231
|
stickyHeader,
|
|
@@ -224,7 +240,7 @@ function GridTable(props) {
|
|
|
224
240
|
tooManyClientSideRows = true;
|
|
225
241
|
filteredRows = filteredRows.slice(0, filterMaxRows);
|
|
226
242
|
}
|
|
227
|
-
rowState.
|
|
243
|
+
rowState.setVisibleRows(filteredRows.map(([row]) => { var _a; return (_a = row === null || row === void 0 ? void 0 : row.id) !== null && _a !== void 0 ? _a : ""; }));
|
|
228
244
|
// Push back to the caller a way to ask us where a row is.
|
|
229
245
|
const { rowLookup } = props;
|
|
230
246
|
if (rowLookup) {
|
|
@@ -468,7 +484,7 @@ function getFirstOrLastCellCss(style, columnIndex, columns) {
|
|
|
468
484
|
// We extract GridRow to its own mini-component primarily so we can React.memo'ize it.
|
|
469
485
|
function GridRow(props) {
|
|
470
486
|
var _a;
|
|
471
|
-
const { as, columns, row, style, rowStyles, stickyHeader, stickyOffset,
|
|
487
|
+
const { as, columns, row, style, rowStyles, stickyHeader, stickyOffset, sortOn, sortState, setSortKey, openCards, columnSizes, level, getCount, api, ...others } = props;
|
|
472
488
|
const { rowState } = (0, react_1.useContext)(RowState_1.RowStateContext);
|
|
473
489
|
const isActive = (0, hooks_1.useComputed)(() => rowState.activeRowId === `${row.kind}_${row.id}`, [row, rowState]);
|
|
474
490
|
// We treat the "header" kind as special for "good defaults" styling
|
|
@@ -511,12 +527,12 @@ function GridRow(props) {
|
|
|
511
527
|
}
|
|
512
528
|
const maybeContent = applyRowFn(column, row, api);
|
|
513
529
|
currentColspan = isGridCellContent(maybeContent) ? (_a = maybeContent.colspan) !== null && _a !== void 0 ? _a : 1 : 1;
|
|
514
|
-
const canSortColumn = (
|
|
515
|
-
(
|
|
530
|
+
const canSortColumn = (sortOn === "client" && column.clientSideSort !== false) ||
|
|
531
|
+
(sortOn === "server" && !!column.serverSideSortKey);
|
|
516
532
|
const alignment = getAlignment(column, maybeContent);
|
|
517
533
|
const justificationCss = getJustification(column, maybeContent, as, alignment);
|
|
518
|
-
const content = toContent(maybeContent, isHeader, canSortColumn,
|
|
519
|
-
(0, sortRows_1.ensureClientSideSortValueIsSortable)(
|
|
534
|
+
const content = toContent(maybeContent, isHeader, canSortColumn, sortOn === "client", style, as, alignment);
|
|
535
|
+
(0, sortRows_1.ensureClientSideSortValueIsSortable)(sortOn, isHeader, column, columnIndex, maybeContent);
|
|
520
536
|
const maybeNestedCardColumnIndex = columnIndex + (style.nestedCards ? 1 : 0);
|
|
521
537
|
const maybeSticky = (_b = ((isGridCellContent(maybeContent) && maybeContent.sticky) || column.sticky)) !== null && _b !== void 0 ? _b : undefined;
|
|
522
538
|
const maybeStickyColumnStyles = maybeSticky && columnSizes
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { ObservableSet } from "mobx";
|
|
2
1
|
import React, { MutableRefObject } from "react";
|
|
3
2
|
import { GridDataRow } from "./GridTable";
|
|
4
3
|
export declare type SelectedState = "checked" | "unchecked" | "partial";
|
|
@@ -22,18 +21,21 @@ export declare class RowState {
|
|
|
22
21
|
private persistCollapse;
|
|
23
22
|
private readonly collapsedRows;
|
|
24
23
|
private readonly selectedRows;
|
|
25
|
-
visibleRows
|
|
24
|
+
private visibleRows;
|
|
26
25
|
activeRowId: string | undefined;
|
|
27
26
|
/**
|
|
28
27
|
* Creates the `RowState` for a given `GridTable`.
|
|
29
28
|
*/
|
|
30
29
|
constructor(rows: MutableRefObject<GridDataRow<any>[]>, persistCollapse: string | undefined, activeRowId: string | undefined);
|
|
30
|
+
setVisibleRows(rowIds: string[]): void;
|
|
31
31
|
get selectedIds(): string[];
|
|
32
32
|
getSelected(id: string): SelectedState;
|
|
33
33
|
selectRow(id: string, selected: boolean): void;
|
|
34
34
|
get collapsedIds(): string[];
|
|
35
35
|
isCollapsed(id: string): boolean;
|
|
36
36
|
toggleCollapsed(id: string): void;
|
|
37
|
+
private getVisibleChildrenStates;
|
|
38
|
+
private setNestedSelectedStates;
|
|
37
39
|
}
|
|
38
40
|
/** Provides a context for rows to access their table's `RowState`. */
|
|
39
41
|
export declare const RowStateContext: React.Context<{
|
|
@@ -37,6 +37,23 @@ class RowState {
|
|
|
37
37
|
// Make ourselves an observable so that mobx will do caching of .collapseIds so
|
|
38
38
|
// that it'll be a stable identity for GridTable to useMemo against.
|
|
39
39
|
(0, mobx_1.makeAutoObservable)(this, { rows: false }); // as any b/c rows is private, so the mapped type doesn't see it
|
|
40
|
+
// Whenever our `visibleRows` change (i.e. via filtering) then we need to re-derive header and parent rows' selected state.
|
|
41
|
+
(0, mobx_1.reaction)(() => [...this.visibleRows.values()].sort(), () => {
|
|
42
|
+
const map = new Map();
|
|
43
|
+
map.set("header", deriveParentSelected(this.rows.current.flatMap((row) => this.setNestedSelectedStates(row, map))));
|
|
44
|
+
// Merge the changes back into the selected rows state
|
|
45
|
+
this.selectedRows.merge(map);
|
|
46
|
+
}, { equals: mobx_1.comparer.shallow });
|
|
47
|
+
}
|
|
48
|
+
setVisibleRows(rowIds) {
|
|
49
|
+
// ObservableSet doesn't seem to do a `diff` inside `replace` before firing
|
|
50
|
+
// observers/reactions that watch it, which can lead to render loops with the
|
|
51
|
+
// application page is observing `GridTableApi.getSelectedRows`, and merely
|
|
52
|
+
// the act of rendering GridTable (w/o row changes) causes it's `useComputed`
|
|
53
|
+
// to be triggered.
|
|
54
|
+
if (!mobx_1.comparer.shallow(rowIds, [...this.visibleRows.values()])) {
|
|
55
|
+
this.visibleRows.replace(rowIds);
|
|
56
|
+
}
|
|
40
57
|
}
|
|
41
58
|
get selectedIds() {
|
|
42
59
|
// Return only ids that are fully checked, i.e. not partial
|
|
@@ -62,7 +79,7 @@ class RowState {
|
|
|
62
79
|
// Just mash the header + all rows + children as selected
|
|
63
80
|
const map = new Map();
|
|
64
81
|
map.set("header", "checked");
|
|
65
|
-
(0, visitor_1.visit)(this.rows.current, (row) => map.set(row.id, "checked"));
|
|
82
|
+
(0, visitor_1.visit)(this.rows.current, (row) => this.visibleRows.has(row.id) && map.set(row.id, "checked"));
|
|
66
83
|
this.selectedRows.replace(map);
|
|
67
84
|
}
|
|
68
85
|
else {
|
|
@@ -80,19 +97,15 @@ class RowState {
|
|
|
80
97
|
}
|
|
81
98
|
// Everything here & down is deterministically on/off
|
|
82
99
|
const map = new Map();
|
|
83
|
-
(0, visitor_1.visit)([curr.row], (row) => map.set(row.id, selected ? "checked" : "unchecked"));
|
|
100
|
+
(0, visitor_1.visit)([curr.row], (row) => this.visibleRows.has(row.id) && map.set(row.id, selected ? "checked" : "unchecked"));
|
|
84
101
|
// Now walk up the parents and see if they are now-all-checked/now-all-unchecked/some-of-each
|
|
85
102
|
for (const parent of [...curr.parents].reverse()) {
|
|
86
103
|
if (parent.children) {
|
|
87
|
-
|
|
88
|
-
map.set(parent.id, deriveParentSelected(children));
|
|
104
|
+
map.set(parent.id, deriveParentSelected(this.getVisibleChildrenStates(parent.children, map)));
|
|
89
105
|
}
|
|
90
106
|
}
|
|
91
107
|
// And do the header + top-level "children" as a final one-off
|
|
92
|
-
|
|
93
|
-
.filter((row) => row.id !== "header")
|
|
94
|
-
.map((row) => map.get(row.id) || this.getSelected(row.id));
|
|
95
|
-
map.set("header", deriveParentSelected(children));
|
|
108
|
+
map.set("header", deriveParentSelected(this.getVisibleChildrenStates(this.rows.current, map)));
|
|
96
109
|
this.selectedRows.merge(map);
|
|
97
110
|
}
|
|
98
111
|
}
|
|
@@ -145,6 +158,24 @@ class RowState {
|
|
|
145
158
|
localStorage.setItem(this.persistCollapse, JSON.stringify(collapsedIds));
|
|
146
159
|
}
|
|
147
160
|
}
|
|
161
|
+
getVisibleChildrenStates(children, map) {
|
|
162
|
+
return children
|
|
163
|
+
.filter((row) => row.id !== "header" && this.visibleRows.has(row.id))
|
|
164
|
+
.map((row) => map.get(row.id) || this.getSelected(row.id));
|
|
165
|
+
}
|
|
166
|
+
// Recursively traverse through rows to determine selected state of parent rows based on children
|
|
167
|
+
setNestedSelectedStates(row, map) {
|
|
168
|
+
if (this.visibleRows.has(row.id)) {
|
|
169
|
+
if (!row.children) {
|
|
170
|
+
return [this.getSelected(row.id)];
|
|
171
|
+
}
|
|
172
|
+
const childrenSelectedStates = row.children.flatMap((rc) => this.setNestedSelectedStates(rc, map));
|
|
173
|
+
const parentState = deriveParentSelected(childrenSelectedStates);
|
|
174
|
+
map.set(row.id, parentState);
|
|
175
|
+
return [parentState];
|
|
176
|
+
}
|
|
177
|
+
return [];
|
|
178
|
+
}
|
|
148
179
|
}
|
|
149
180
|
exports.RowState = RowState;
|
|
150
181
|
/** Provides a context for rows to access their table's `RowState`. */
|
|
@@ -177,5 +208,5 @@ function findRow(rows, id) {
|
|
|
177
208
|
function deriveParentSelected(children) {
|
|
178
209
|
const allChecked = children.every((child) => child === "checked");
|
|
179
210
|
const allUnchecked = children.every((child) => child === "unchecked");
|
|
180
|
-
return allChecked ? "checked" : allUnchecked ? "unchecked" : "partial";
|
|
211
|
+
return children.length === 0 ? "unchecked" : allChecked ? "checked" : allUnchecked ? "unchecked" : "partial";
|
|
181
212
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ReactNode } from "react";
|
|
2
|
-
import { GridCellContent, GridColumn, GridDataRow,
|
|
3
|
-
import { SortState } from "./useSortState";
|
|
2
|
+
import { GridCellContent, GridColumn, GridDataRow, Kinded } from "./GridTable";
|
|
3
|
+
import { SortOn, SortState } from "./useSortState";
|
|
4
4
|
export declare function sortRows<R extends Kinded>(columns: GridColumn<R>[], rows: GridDataRow<R>[], sortState: SortState<number>): GridDataRow<R>[];
|
|
5
|
-
export declare function ensureClientSideSortValueIsSortable(
|
|
5
|
+
export declare function ensureClientSideSortValueIsSortable(sortOn: SortOn, isHeader: boolean, column: GridColumn<any>, idx: number, maybeContent: ReactNode | GridCellContent): void;
|
|
@@ -64,11 +64,8 @@ function sortValue(value) {
|
|
|
64
64
|
}
|
|
65
65
|
return maybeFn;
|
|
66
66
|
}
|
|
67
|
-
function ensureClientSideSortValueIsSortable(
|
|
68
|
-
if (process.env.NODE_ENV !== "production" &&
|
|
69
|
-
!isHeader &&
|
|
70
|
-
(sorting === null || sorting === void 0 ? void 0 : sorting.on) === "client" &&
|
|
71
|
-
column.clientSideSort !== false) {
|
|
67
|
+
function ensureClientSideSortValueIsSortable(sortOn, isHeader, column, idx, maybeContent) {
|
|
68
|
+
if (process.env.NODE_ENV !== "production" && !isHeader && sortOn === "client" && column.clientSideSort !== false) {
|
|
72
69
|
const value = sortValue(maybeContent);
|
|
73
70
|
if (!canClientSideSort(value)) {
|
|
74
71
|
throw new Error(`Column ${idx} passed an unsortable value, use GridCellContent or clientSideSort=false`);
|
|
@@ -8,6 +8,7 @@ import { Direction, GridColumn, GridSortConfig, Kinded } from "./GridTable";
|
|
|
8
8
|
* b) it's index in the `columns` array, if client-side sorting
|
|
9
9
|
*/
|
|
10
10
|
export declare type SortState<S> = readonly [S, Direction];
|
|
11
|
+
export declare type SortOn = "client" | "server" | undefined;
|
|
11
12
|
/** Small custom hook that wraps the "setSortColumn inverts the current sort" logic. */
|
|
12
|
-
export declare function useSortState<R extends Kinded, S>(columns: GridColumn<R, S>[], sorting?: GridSortConfig<S>): [SortState<S> | undefined, (value: S) => void];
|
|
13
|
+
export declare function useSortState<R extends Kinded, S>(columns: GridColumn<R, S>[], sorting?: GridSortConfig<S>): [SortState<S> | undefined, (value: S) => void, SortOn];
|
|
13
14
|
export declare function deriveSortState<S>(currentSortState: SortState<S> | undefined, clickedKey: S, initialSortState: SortState<S> | undefined): SortState<S> | undefined;
|
|
@@ -28,20 +28,26 @@ function useSortState(columns, sorting) {
|
|
|
28
28
|
else {
|
|
29
29
|
return sorting === null || sorting === void 0 ? void 0 : sorting.value;
|
|
30
30
|
}
|
|
31
|
-
},
|
|
31
|
+
},
|
|
32
|
+
// We want to allow the user to not memoize `GridTableProps.sorting` b/c for the
|
|
33
|
+
// initialSortState calc, it's just a bunch of surely hard-coded primitives like
|
|
34
|
+
// sort on client/server, which column is initial.
|
|
35
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
36
|
+
[columns]);
|
|
32
37
|
const [sortState, setSortState] = (0, react_1.useState)(initialSortState);
|
|
33
38
|
// Make a custom setSortKey that is useState-like but contains the ASC->DESC->RESET logic.
|
|
39
|
+
const onSort = (sorting === null || sorting === void 0 ? void 0 : sorting.on) === "server" ? sorting.onSort : undefined;
|
|
34
40
|
const setSortKey = (0, react_1.useCallback)((clickedKey) => {
|
|
35
41
|
const newState = deriveSortState(sortState, clickedKey, initialSortState);
|
|
36
42
|
setSortState(newState);
|
|
37
|
-
if (
|
|
43
|
+
if (onSort) {
|
|
38
44
|
const [newKey, newDirection] = newState !== null && newState !== void 0 ? newState : [undefined, undefined];
|
|
39
|
-
|
|
45
|
+
onSort(newKey, newDirection);
|
|
40
46
|
}
|
|
41
47
|
},
|
|
42
48
|
// Note that sorting.onSort is not listed here, so we bind to whatever the 1st sorting.onSort was
|
|
43
|
-
[sortState,
|
|
44
|
-
return [sortState, setSortKey];
|
|
49
|
+
[initialSortState, sortState, onSort]);
|
|
50
|
+
return [sortState, setSortKey, sorting === null || sorting === void 0 ? void 0 : sorting.on];
|
|
45
51
|
}
|
|
46
52
|
exports.useSortState = useSortState;
|
|
47
53
|
// Exported for testing purposes
|