@homebound/beam 2.117.4 → 2.118.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.
|
@@ -127,6 +127,9 @@ 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 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]);
|
|
130
133
|
const [sortState, setSortKey] = (0, useSortState_1.useSortState)(columns, sorting);
|
|
131
134
|
const maybeSorted = (0, react_1.useMemo)(() => {
|
|
132
135
|
if ((sorting === null || sorting === void 0 ? void 0 : sorting.on) === "client" && sortState) {
|
|
@@ -135,13 +138,34 @@ function GridTable(props) {
|
|
|
135
138
|
}
|
|
136
139
|
return rows;
|
|
137
140
|
}, [columns, rows, sorting, sortState]);
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
// Filter + flatten + component-ize the sorted rows.
|
|
142
|
-
let [headerRows, filteredRows] = (0, react_1.useMemo)(() => {
|
|
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]);
|
|
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.
|
|
@@ -168,38 +192,30 @@ 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
|
}, [
|
|
@@ -34,6 +34,8 @@ export declare class RowState {
|
|
|
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,13 @@ 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 });
|
|
40
47
|
}
|
|
41
48
|
get selectedIds() {
|
|
42
49
|
// Return only ids that are fully checked, i.e. not partial
|
|
@@ -62,7 +69,7 @@ class RowState {
|
|
|
62
69
|
// Just mash the header + all rows + children as selected
|
|
63
70
|
const map = new Map();
|
|
64
71
|
map.set("header", "checked");
|
|
65
|
-
(0, visitor_1.visit)(this.rows.current, (row) => map.set(row.id, "checked"));
|
|
72
|
+
(0, visitor_1.visit)(this.rows.current, (row) => this.visibleRows.has(row.id) && map.set(row.id, "checked"));
|
|
66
73
|
this.selectedRows.replace(map);
|
|
67
74
|
}
|
|
68
75
|
else {
|
|
@@ -80,19 +87,15 @@ class RowState {
|
|
|
80
87
|
}
|
|
81
88
|
// Everything here & down is deterministically on/off
|
|
82
89
|
const map = new Map();
|
|
83
|
-
(0, visitor_1.visit)([curr.row], (row) => map.set(row.id, selected ? "checked" : "unchecked"));
|
|
90
|
+
(0, visitor_1.visit)([curr.row], (row) => this.visibleRows.has(row.id) && map.set(row.id, selected ? "checked" : "unchecked"));
|
|
84
91
|
// Now walk up the parents and see if they are now-all-checked/now-all-unchecked/some-of-each
|
|
85
92
|
for (const parent of [...curr.parents].reverse()) {
|
|
86
93
|
if (parent.children) {
|
|
87
|
-
|
|
88
|
-
map.set(parent.id, deriveParentSelected(children));
|
|
94
|
+
map.set(parent.id, deriveParentSelected(this.getVisibleChildrenStates(parent.children, map)));
|
|
89
95
|
}
|
|
90
96
|
}
|
|
91
97
|
// 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));
|
|
98
|
+
map.set("header", deriveParentSelected(this.getVisibleChildrenStates(this.rows.current, map)));
|
|
96
99
|
this.selectedRows.merge(map);
|
|
97
100
|
}
|
|
98
101
|
}
|
|
@@ -145,6 +148,24 @@ class RowState {
|
|
|
145
148
|
localStorage.setItem(this.persistCollapse, JSON.stringify(collapsedIds));
|
|
146
149
|
}
|
|
147
150
|
}
|
|
151
|
+
getVisibleChildrenStates(children, map) {
|
|
152
|
+
return children
|
|
153
|
+
.filter((row) => row.id !== "header" && this.visibleRows.has(row.id))
|
|
154
|
+
.map((row) => map.get(row.id) || this.getSelected(row.id));
|
|
155
|
+
}
|
|
156
|
+
// Recursively traverse through rows to determine selected state of parent rows based on children
|
|
157
|
+
setNestedSelectedStates(row, map) {
|
|
158
|
+
if (this.visibleRows.has(row.id)) {
|
|
159
|
+
if (!row.children) {
|
|
160
|
+
return [this.getSelected(row.id)];
|
|
161
|
+
}
|
|
162
|
+
const childrenSelectedStates = row.children.flatMap((rc) => this.setNestedSelectedStates(rc, map));
|
|
163
|
+
const parentState = deriveParentSelected(childrenSelectedStates);
|
|
164
|
+
map.set(row.id, parentState);
|
|
165
|
+
return [parentState];
|
|
166
|
+
}
|
|
167
|
+
return [];
|
|
168
|
+
}
|
|
148
169
|
}
|
|
149
170
|
exports.RowState = RowState;
|
|
150
171
|
/** Provides a context for rows to access their table's `RowState`. */
|
|
@@ -177,5 +198,5 @@ function findRow(rows, id) {
|
|
|
177
198
|
function deriveParentSelected(children) {
|
|
178
199
|
const allChecked = children.every((child) => child === "checked");
|
|
179
200
|
const allUnchecked = children.every((child) => child === "unchecked");
|
|
180
|
-
return allChecked ? "checked" : allUnchecked ? "unchecked" : "partial";
|
|
201
|
+
return children.length === 0 ? "unchecked" : allChecked ? "checked" : allUnchecked ? "unchecked" : "partial";
|
|
181
202
|
}
|