@homebound/beam 2.136.0 → 2.136.1

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.
@@ -140,8 +140,8 @@ function GridTable(props) {
140
140
  }
141
141
  else {
142
142
  // Otherwise, maybe one of the children match.
143
- const isCollapsed = collapsedIds.includes(row.id);
144
- if (!isCollapsed && !!((_c = row.children) === null || _c === void 0 ? void 0 : _c.length)) {
143
+ // Always filter children rows whether or not they are collapsed in order to determine proper "selected" state of the group row.
144
+ if (!!((_c = row.children) === null || _c === void 0 ? void 0 : _c.length)) {
145
145
  const matchedChildren = row.children.reduce(filterRows, []);
146
146
  // If some children did match, then add the parent row with its matched children.
147
147
  if (matchedChildren.length > 0) {
@@ -152,7 +152,7 @@ function GridTable(props) {
152
152
  return acc;
153
153
  }, [filter, collapsedIds, columns]);
154
154
  // Flatten + component-ize the sorted rows.
155
- let [headerRows, filteredRows, totalsRows] = (0, react_1.useMemo)(() => {
155
+ let [headerRows, visibleDataRows, totalsRows, filteredRowIds] = (0, react_1.useMemo)(() => {
156
156
  function makeRowComponent(row, level) {
157
157
  // We only pass sortState to header rows, b/c non-headers rows shouldn't have to re-render on sorting
158
158
  // changes, and so by not passing the sortProps, it means the data rows' React.memo will still cache them.
@@ -178,20 +178,25 @@ function GridTable(props) {
178
178
  // Split out the header rows from the data rows so that we can put an `infoMessage` in between them (if needed).
179
179
  const headerRows = [];
180
180
  const totalsRows = [];
181
- const filteredRows = [];
181
+ const visibleDataRows = [];
182
+ const filteredRowIds = [];
182
183
  // Misc state to track our nested card-ification, i.e. interleaved actual rows + chrome rows
183
- const nestedCards = !!style.nestedCards && new nestedCards_1.NestedCards(columns, filteredRows, style.nestedCards);
184
- function visit([row, children], level) {
185
- let isCard = nestedCards && nestedCards.maybeOpenCard(row);
186
- filteredRows.push([row, makeRowComponent(row, level)]);
187
- const isCollapsed = collapsedIds.includes(row.id);
188
- if (!isCollapsed && children.length) {
189
- nestedCards && nestedCards.addSpacer();
190
- visitRows(children, isCard, level + 1);
184
+ const nestedCards = !!style.nestedCards && new nestedCards_1.NestedCards(columns, visibleDataRows, style.nestedCards);
185
+ function visit([row, children], level, visible) {
186
+ let isCard = visible && nestedCards && nestedCards.maybeOpenCard(row);
187
+ visible && visibleDataRows.push([row, makeRowComponent(row, level)]);
188
+ // This row may be invisible (because it's parent is collapsed), but we still want
189
+ // to consider it matched if it or it's parent matched a filter.
190
+ filteredRowIds.push(row.id);
191
+ if (children.length) {
192
+ // Consider "isCollapsed" as true if the parent wasn't visible.
193
+ const isCollapsed = !visible || collapsedIds.includes(row.id);
194
+ !isCollapsed && nestedCards && nestedCards.addSpacer();
195
+ visitRows(children, isCard, level + 1, !isCollapsed);
191
196
  }
192
- !(0, nestedCards_1.isLeafRow)(row) && isCard && nestedCards && nestedCards.closeCard();
197
+ visible && !(0, nestedCards_1.isLeafRow)(row) && isCard && nestedCards && nestedCards.closeCard();
193
198
  }
194
- function visitRows(rows, addSpacer, level) {
199
+ function visitRows(rows, addSpacer, level, visible) {
195
200
  const length = rows.length;
196
201
  rows.forEach((row, i) => {
197
202
  if (row[0].kind === "header") {
@@ -202,15 +207,15 @@ function GridTable(props) {
202
207
  totalsRows.push([row[0], makeRowComponent(row[0], level)]);
203
208
  return;
204
209
  }
205
- visit(row, level);
206
- addSpacer && nestedCards && i !== length - 1 && nestedCards.addSpacer();
210
+ visit(row, level, visible);
211
+ visible && addSpacer && nestedCards && i !== length - 1 && nestedCards.addSpacer();
207
212
  });
208
213
  }
209
214
  // Call `visitRows` with our a pre-filtered set list
210
215
  // If nestedCards is set, we assume the top-level kind is a card, and so should add spacers between them
211
- visitRows(maybeSorted.reduce(filterRows, []), !!nestedCards, 0);
216
+ visitRows(maybeSorted.reduce(filterRows, []), !!nestedCards, 0, true);
212
217
  nestedCards && nestedCards.done();
213
- return [headerRows, filteredRows, totalsRows];
218
+ return [headerRows, visibleDataRows, totalsRows, filteredRowIds];
214
219
  }, [
215
220
  as,
216
221
  maybeSorted,
@@ -230,21 +235,21 @@ function GridTable(props) {
230
235
  hasTotalsRow,
231
236
  ]);
232
237
  let tooManyClientSideRows = false;
233
- if (filterMaxRows && filteredRows.length > filterMaxRows) {
238
+ if (filterMaxRows && visibleDataRows.length > filterMaxRows) {
234
239
  tooManyClientSideRows = true;
235
- filteredRows = filteredRows.slice(0, filterMaxRows);
240
+ visibleDataRows = visibleDataRows.slice(0, filterMaxRows);
236
241
  }
237
- rowState.setVisibleRows(filteredRows.map(([row]) => { var _a; return (_a = row === null || row === void 0 ? void 0 : row.id) !== null && _a !== void 0 ? _a : ""; }));
242
+ rowState.setMatchedRows(filteredRowIds);
238
243
  // Push back to the caller a way to ask us where a row is.
239
244
  const { rowLookup } = props;
240
245
  if (rowLookup) {
241
246
  // Refs are cheap to assign to, so we don't bother doing this in a useEffect
242
- rowLookup.current = (0, GridRowLookup_1.createRowLookup)(columns, filteredRows, virtuosoRef);
247
+ rowLookup.current = (0, GridRowLookup_1.createRowLookup)(columns, visibleDataRows, virtuosoRef);
243
248
  }
244
249
  (0, react_1.useEffect)(() => {
245
- setRowCount && (filteredRows === null || filteredRows === void 0 ? void 0 : filteredRows.length) !== undefined && setRowCount(filteredRows.length);
246
- }, [filteredRows === null || filteredRows === void 0 ? void 0 : filteredRows.length, setRowCount]);
247
- const noData = filteredRows.length === 0;
250
+ setRowCount && (visibleDataRows === null || visibleDataRows === void 0 ? void 0 : visibleDataRows.length) !== undefined && setRowCount(visibleDataRows.length);
251
+ }, [visibleDataRows === null || visibleDataRows === void 0 ? void 0 : visibleDataRows.length, setRowCount]);
252
+ const noData = visibleDataRows.length === 0;
248
253
  const firstRowMessage = (noData && fallbackMessage) || (tooManyClientSideRows && "Hiding some rows, use filter...") || infoMessage;
249
254
  const borderless = (_a = style === null || style === void 0 ? void 0 : style.presentationSettings) === null || _a === void 0 ? void 0 : _a.borderless;
250
255
  const typeScale = (_b = style === null || style === void 0 ? void 0 : style.presentationSettings) === null || _b === void 0 ? void 0 : _b.typeScale;
@@ -263,7 +268,7 @@ function GridTable(props) {
263
268
  // behave semantically the same as `as=div` did for its tests.
264
269
  const _as = as === "virtual" && runningInJest ? "div" : as;
265
270
  const rowStateContext = (0, react_1.useMemo)(() => ({ rowState }), [rowState]);
266
- return ((0, jsx_runtime_1.jsx)(RowState_1.RowStateContext.Provider, Object.assign({ value: rowStateContext }, { children: (0, jsx_runtime_1.jsxs)(PresentationContext_1.PresentationProvider, Object.assign({ fieldProps: fieldProps, wrap: (_c = style === null || style === void 0 ? void 0 : style.presentationSettings) === null || _c === void 0 ? void 0 : _c.wrap }, { children: [(0, jsx_runtime_1.jsx)("div", { ref: resizeRef, css: Css_1.Css.w100.$ }, void 0), renders[_as](style, id, columns, headerRows, totalsRows, filteredRows, firstRowMessage, stickyHeader, (_d = style.nestedCards) === null || _d === void 0 ? void 0 : _d.firstLastColumnWidth, xss, virtuosoRef)] }), void 0) }), void 0));
271
+ return ((0, jsx_runtime_1.jsx)(RowState_1.RowStateContext.Provider, Object.assign({ value: rowStateContext }, { children: (0, jsx_runtime_1.jsxs)(PresentationContext_1.PresentationProvider, Object.assign({ fieldProps: fieldProps, wrap: (_c = style === null || style === void 0 ? void 0 : style.presentationSettings) === null || _c === void 0 ? void 0 : _c.wrap }, { children: [(0, jsx_runtime_1.jsx)("div", { ref: resizeRef, css: Css_1.Css.w100.$ }, void 0), renders[_as](style, id, columns, headerRows, totalsRows, visibleDataRows, firstRowMessage, stickyHeader, (_d = style.nestedCards) === null || _d === void 0 ? void 0 : _d.firstLastColumnWidth, xss, virtuosoRef)] }), void 0) }), void 0));
267
272
  }
268
273
  exports.GridTable = GridTable;
269
274
  // Determine which HTML element to use to build the GridTable
@@ -273,7 +278,7 @@ const renders = {
273
278
  virtual: renderVirtual,
274
279
  };
275
280
  /** Renders table using divs with flexbox rows, which is the default render */
276
- function renderDiv(style, id, columns, headerRows, totalsRows, filteredRows, firstRowMessage, _stickyHeader, firstLastColumnWidth, xss, _virtuosoRef) {
281
+ function renderDiv(style, id, columns, headerRows, totalsRows, visibleDataRows, firstRowMessage, _stickyHeader, firstLastColumnWidth, xss, _virtuosoRef) {
277
282
  return ((0, jsx_runtime_1.jsxs)("div", Object.assign({ css: {
278
283
  // Use `fit-content` to ensure the width of the table takes up the full width of its content.
279
284
  // Otherwise, the table's width would be that of its container, which may not be as wide as the table itself.
@@ -290,10 +295,10 @@ function renderDiv(style, id, columns, headerRows, totalsRows, filteredRows, fir
290
295
  ...style.rootCss,
291
296
  ...(style.minWidthPx ? Css_1.Css.mwPx(style.minWidthPx).$ : {}),
292
297
  ...xss,
293
- }, "data-testid": id }, { children: [totalsRows.map(([, node]) => node), headerRows.map(([, node]) => node), firstRowMessage && ((0, jsx_runtime_1.jsx)("div", Object.assign({ css: { ...style.firstRowMessageCss }, "data-gridrow": true }, { children: firstRowMessage }), void 0)), filteredRows.map(([, node]) => node)] }), void 0));
298
+ }, "data-testid": id }, { children: [totalsRows.map(([, node]) => node), headerRows.map(([, node]) => node), firstRowMessage && ((0, jsx_runtime_1.jsx)("div", Object.assign({ css: { ...style.firstRowMessageCss }, "data-gridrow": true }, { children: firstRowMessage }), void 0)), visibleDataRows.map(([, node]) => node)] }), void 0));
294
299
  }
295
300
  /** Renders as a table, primarily/solely for good print support. */
296
- function renderTable(style, id, columns, headerRows, totalsRows, filteredRows, firstRowMessage, _stickyHeader, _firstLastColumnWidth, xss, _virtuosoRef) {
301
+ function renderTable(style, id, columns, headerRows, totalsRows, visibleDataRows, firstRowMessage, _stickyHeader, _firstLastColumnWidth, xss, _virtuosoRef) {
297
302
  return ((0, jsx_runtime_1.jsxs)("table", Object.assign({ css: {
298
303
  ...Css_1.Css.w100.add("borderCollapse", "collapse").$,
299
304
  ...Css_1.Css.addIn("& > tbody > tr ", style.betweenRowsCss || {})
@@ -302,7 +307,7 @@ function renderTable(style, id, columns, headerRows, totalsRows, filteredRows, f
302
307
  ...style.rootCss,
303
308
  ...(style.minWidthPx ? Css_1.Css.mwPx(style.minWidthPx).$ : {}),
304
309
  ...xss,
305
- }, "data-testid": id }, { children: [(0, jsx_runtime_1.jsx)("thead", { children: [...totalsRows, ...headerRows].map(([, node]) => node) }, void 0), (0, jsx_runtime_1.jsxs)("tbody", { children: [firstRowMessage && ((0, jsx_runtime_1.jsx)("tr", { children: (0, jsx_runtime_1.jsx)("td", Object.assign({ colSpan: columns.length, css: { ...style.firstRowMessageCss } }, { children: firstRowMessage }), void 0) }, void 0)), filteredRows.map(([, node]) => node)] }, void 0)] }), void 0));
310
+ }, "data-testid": id }, { children: [(0, jsx_runtime_1.jsx)("thead", { children: [...totalsRows, ...headerRows].map(([, node]) => node) }, void 0), (0, jsx_runtime_1.jsxs)("tbody", { children: [firstRowMessage && ((0, jsx_runtime_1.jsx)("tr", { children: (0, jsx_runtime_1.jsx)("td", Object.assign({ colSpan: columns.length, css: { ...style.firstRowMessageCss } }, { children: firstRowMessage }), void 0) }, void 0)), visibleDataRows.map(([, node]) => node)] }, void 0)] }), void 0));
306
311
  }
307
312
  /**
308
313
  * Uses react-virtuoso to render rows virtually.
@@ -324,7 +329,7 @@ function renderTable(style, id, columns, headerRows, totalsRows, filteredRows, f
324
329
  * [2]: https://github.com/tannerlinsley/react-virtual/issues/85
325
330
  * [3]: https://github.com/tannerlinsley/react-virtual/issues/108
326
331
  */
327
- function renderVirtual(style, id, columns, headerRows, totalsRows, filteredRows, firstRowMessage, stickyHeader, firstLastColumnWidth, xss, virtuosoRef) {
332
+ function renderVirtual(style, id, columns, headerRows, totalsRows, visibleDataRows, firstRowMessage, stickyHeader, firstLastColumnWidth, xss, virtuosoRef) {
328
333
  // eslint-disable-next-line react-hooks/rules-of-hooks
329
334
  const { footerStyle, listStyle } = (0, react_1.useMemo)(() => {
330
335
  var _a;
@@ -363,8 +368,8 @@ function renderVirtual(style, id, columns, headerRows, totalsRows, filteredRows,
363
368
  index--;
364
369
  }
365
370
  // Lastly render `filteredRow`
366
- return filteredRows[index][1];
367
- }, totalCount: (headerRows.length || 0) + (totalsRows.length || 0) + (firstRowMessage ? 1 : 0) + (filteredRows.length || 0) }, void 0));
371
+ return visibleDataRows[index][1];
372
+ }, totalCount: (headerRows.length || 0) + (totalsRows.length || 0) + (firstRowMessage ? 1 : 0) + (visibleDataRows.length || 0) }, void 0));
368
373
  }
369
374
  /**
370
375
  * A table might render two of these components to represent two virtual lists.
@@ -20,7 +20,7 @@ export declare class RowState {
20
20
  private readonly collapsedRows;
21
21
  private persistCollapse;
22
22
  private readonly selectedRows;
23
- private visibleRows;
23
+ private matchedRows;
24
24
  rows: GridDataRow<any>[];
25
25
  activeRowId: string | undefined;
26
26
  /**
@@ -29,14 +29,14 @@ export declare class RowState {
29
29
  constructor();
30
30
  loadCollapse(persistCollapse: string | undefined, rows: GridDataRow<any>[]): void;
31
31
  setRows(rows: GridDataRow<any>[]): void;
32
- setVisibleRows(rowIds: string[]): void;
32
+ setMatchedRows(rowIds: string[]): void;
33
33
  get selectedIds(): string[];
34
34
  getSelected(id: string): SelectedState;
35
35
  selectRow(id: string, selected: boolean): void;
36
36
  get collapsedIds(): string[];
37
37
  isCollapsed(id: string): boolean;
38
38
  toggleCollapsed(id: string): void;
39
- private getVisibleChildrenStates;
39
+ private getMatchedChildrenStates;
40
40
  private setNestedSelectedStates;
41
41
  }
42
42
  /** Provides a context for rows to access their table's `RowState`. */
@@ -30,8 +30,8 @@ class RowState {
30
30
  // A set of just row ids, i.e. not row.kind+row.id
31
31
  this.collapsedRows = new mobx_1.ObservableSet();
32
32
  this.selectedRows = new mobx_1.ObservableMap();
33
- // Set of just row ids. Keeps track of which rows are visible. Used to filter out non-visible rows from `selectedIds`
34
- this.visibleRows = new mobx_1.ObservableSet();
33
+ // Set of just row ids. Keeps track of which rows match the filter. Used to filter rows from `selectedIds`
34
+ this.matchedRows = new mobx_1.ObservableSet();
35
35
  // The current list of rows, basically a useRef.current. Not reactive.
36
36
  this.rows = [];
37
37
  // Keeps track of the 'active' row, formatted `${row.kind}_${row.id}`
@@ -42,11 +42,11 @@ class RowState {
42
42
  // We only shallow observe rows so that:
43
43
  // a) we don't deeply/needlessly proxy-ize a large Apollo fragment cache, but
44
44
  // b) if rows changes, we re-run computeds like getSelectedRows that may need to see the
45
- // updated _contents_ of a given row, even if our other selected/visible row states don't change.
45
+ // updated _contents_ of a given row, even if our other selected/matched row states don't change.
46
46
  // (as any b/c rows is private, so the mapped type doesn't see it)
47
47
  { rows: mobx_1.observable.shallow });
48
- // Whenever our `visibleRows` change (i.e. via filtering) then we need to re-derive header and parent rows' selected state.
49
- (0, mobx_1.reaction)(() => [...this.visibleRows.values()].sort(), () => {
48
+ // Whenever our `matchedRows` change (i.e. via filtering) then we need to re-derive header and parent rows' selected state.
49
+ (0, mobx_1.reaction)(() => [...this.matchedRows.values()].sort(), () => {
50
50
  const map = new Map();
51
51
  map.set("header", deriveParentSelected(this.rows.flatMap((row) => this.setNestedSelectedStates(row, map))));
52
52
  // Merge the changes back into the selected rows state
@@ -95,20 +95,20 @@ class RowState {
95
95
  // Finally replace our existing list of rows
96
96
  this.rows = rows;
97
97
  }
98
- setVisibleRows(rowIds) {
98
+ setMatchedRows(rowIds) {
99
99
  // ObservableSet doesn't seem to do a `diff` inside `replace` before firing
100
100
  // observers/reactions that watch it, which can lead to render loops with the
101
101
  // application page is observing `GridTableApi.getSelectedRows`, and merely
102
102
  // the act of rendering GridTable (w/o row changes) causes it's `useComputed`
103
103
  // to be triggered.
104
- if (!mobx_1.comparer.shallow(rowIds, [...this.visibleRows.values()])) {
105
- this.visibleRows.replace(rowIds);
104
+ if (!mobx_1.comparer.shallow(rowIds, [...this.matchedRows.values()])) {
105
+ this.matchedRows.replace(rowIds);
106
106
  }
107
107
  }
108
108
  get selectedIds() {
109
109
  // Return only ids that are fully checked, i.e. not partial
110
110
  const ids = [...this.selectedRows.entries()]
111
- .filter(([id, v]) => this.visibleRows.has(id) && v === "checked")
111
+ .filter(([id, v]) => this.matchedRows.has(id) && v === "checked")
112
112
  .map(([k]) => k);
113
113
  // Hide our header marker
114
114
  const headerIndex = ids.indexOf("header");
@@ -129,7 +129,7 @@ class RowState {
129
129
  // Just mash the header + all rows + children as selected
130
130
  const map = new Map();
131
131
  map.set("header", "checked");
132
- (0, visitor_1.visit)(this.rows, (row) => this.visibleRows.has(row.id) && row.kind !== "totals" && map.set(row.id, "checked"));
132
+ (0, visitor_1.visit)(this.rows, (row) => this.matchedRows.has(row.id) && row.kind !== "totals" && map.set(row.id, "checked"));
133
133
  this.selectedRows.replace(map);
134
134
  }
135
135
  else {
@@ -147,15 +147,15 @@ class RowState {
147
147
  }
148
148
  // Everything here & down is deterministically on/off
149
149
  const map = new Map();
150
- (0, visitor_1.visit)([curr.row], (row) => this.visibleRows.has(row.id) && map.set(row.id, selected ? "checked" : "unchecked"));
150
+ (0, visitor_1.visit)([curr.row], (row) => this.matchedRows.has(row.id) && map.set(row.id, selected ? "checked" : "unchecked"));
151
151
  // Now walk up the parents and see if they are now-all-checked/now-all-unchecked/some-of-each
152
152
  for (const parent of [...curr.parents].reverse()) {
153
153
  if (parent.children) {
154
- map.set(parent.id, deriveParentSelected(this.getVisibleChildrenStates(parent.children, map)));
154
+ map.set(parent.id, deriveParentSelected(this.getMatchedChildrenStates(parent.children, map)));
155
155
  }
156
156
  }
157
157
  // And do the header + top-level "children" as a final one-off
158
- map.set("header", deriveParentSelected(this.getVisibleChildrenStates(this.rows, map)));
158
+ map.set("header", deriveParentSelected(this.getMatchedChildrenStates(this.rows, map)));
159
159
  this.selectedRows.merge(map);
160
160
  }
161
161
  }
@@ -218,14 +218,14 @@ class RowState {
218
218
  sessionStorage.setItem(this.persistCollapse, JSON.stringify(collapsedIds));
219
219
  }
220
220
  }
221
- getVisibleChildrenStates(children, map) {
221
+ getMatchedChildrenStates(children, map) {
222
222
  return children
223
- .filter((row) => row.id !== "header" && this.visibleRows.has(row.id))
223
+ .filter((row) => row.id !== "header" && this.matchedRows.has(row.id))
224
224
  .map((row) => map.get(row.id) || this.getSelected(row.id));
225
225
  }
226
226
  // Recursively traverse through rows to determine selected state of parent rows based on children
227
227
  setNestedSelectedStates(row, map) {
228
- if (this.visibleRows.has(row.id)) {
228
+ if (this.matchedRows.has(row.id)) {
229
229
  if (!row.children) {
230
230
  return [this.getSelected(row.id)];
231
231
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@homebound/beam",
3
- "version": "2.136.0",
3
+ "version": "2.136.1",
4
4
  "author": "Homebound",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",