@homebound/beam 2.208.1 → 2.209.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.
Files changed (29) hide show
  1. package/dist/components/Table/GridTable.js +47 -20
  2. package/dist/components/Table/GridTableApi.d.ts +4 -0
  3. package/dist/components/Table/GridTableApi.js +6 -0
  4. package/dist/components/Table/TableStyles.d.ts +4 -0
  5. package/dist/components/Table/TableStyles.js +11 -7
  6. package/dist/components/Table/components/EditColumnsButton.d.ts +3 -4
  7. package/dist/components/Table/components/EditColumnsButton.js +10 -9
  8. package/dist/components/Table/components/ExpandableHeader.d.ts +9 -0
  9. package/dist/components/Table/components/ExpandableHeader.js +25 -0
  10. package/dist/components/Table/components/Row.d.ts +1 -0
  11. package/dist/components/Table/components/Row.js +54 -18
  12. package/dist/components/Table/components/cell.d.ts +5 -2
  13. package/dist/components/Table/components/cell.js +6 -3
  14. package/dist/components/Table/index.d.ts +0 -1
  15. package/dist/components/Table/index.js +0 -1
  16. package/dist/components/Table/types.d.ts +9 -0
  17. package/dist/components/Table/types.js +2 -0
  18. package/dist/components/Table/utils/TableState.d.ts +10 -0
  19. package/dist/components/Table/utils/TableState.js +55 -7
  20. package/dist/components/Table/utils/columns.js +29 -5
  21. package/dist/components/Table/utils/simpleHelpers.d.ts +5 -0
  22. package/dist/components/Table/utils/simpleHelpers.js +2 -1
  23. package/dist/components/Table/utils/sortRows.d.ts +2 -2
  24. package/dist/components/Table/utils/sortRows.js +5 -3
  25. package/dist/components/Table/utils/utils.d.ts +12 -2
  26. package/dist/components/Table/utils/utils.js +21 -4
  27. package/package.json +1 -1
  28. package/dist/components/Table/hooks/useColumns.d.ts +0 -3
  29. package/dist/components/Table/hooks/useColumns.js +0 -33
@@ -80,7 +80,7 @@ exports.setGridTableDefaults = setGridTableDefaults;
80
80
  function GridTable(props) {
81
81
  var _a, _b, _c;
82
82
  const { id = "gridTable", as = "div", columns: _columns, rows, style: maybeStyle = defaults.style, rowStyles, stickyHeader = defaults.stickyHeader, stickyOffset = 0, xss, filter, filterMaxRows, fallbackMessage = "No rows found.", infoMessage, setRowCount, persistCollapse, resizeTarget, activeRowId, activeCellId, } = props;
83
- const columns = (0, react_1.useMemo)(() => (0, columns_1.assignDefaultColumnIds)(_columns), [_columns]);
83
+ const columnsWithIds = (0, react_1.useMemo)(() => (0, columns_1.assignDefaultColumnIds)(_columns), [_columns]);
84
84
  // We only use this in as=virtual mode, but keep this here for rowLookup to use
85
85
  const virtuosoRef = (0, react_1.useRef)(null);
86
86
  // Use this ref to watch for changes in the GridTable's container and resize columns accordingly.
@@ -95,6 +95,11 @@ function GridTable(props) {
95
95
  }, [props.api]);
96
96
  const style = (0, TableStyles_1.resolveStyles)(maybeStyle);
97
97
  const { tableState } = api;
98
+ tableState.setRows(rows);
99
+ tableState.setColumns(columnsWithIds);
100
+ const columns = (0, hooks_1.useComputed)(() => tableState.columns
101
+ .filter((c) => tableState.visibleColumnIds.includes(c.id))
102
+ .flatMap((c) => c.expandColumns && tableState.expandedColumnIds.includes(c.id) ? [c, ...c.expandColumns] : [c]), [tableState]);
98
103
  // Initialize the sort state. This will only happen on the first render.
99
104
  // Once the `TableState.sort` is defined, it will not re-initialize.
100
105
  tableState.initSortState(props.sorting, columns);
@@ -102,7 +107,6 @@ function GridTable(props) {
102
107
  const { sortConfig } = tableState;
103
108
  return [sortConfig === null || sortConfig === void 0 ? void 0 : sortConfig.on, (sortConfig === null || sortConfig === void 0 ? void 0 : sortConfig.on) === "client" ? !!sortConfig.caseSensitive : false];
104
109
  }, [tableState]);
105
- tableState.setRows(rows);
106
110
  (0, react_1.useEffect)(() => {
107
111
  tableState.activeRowId = activeRowId;
108
112
  }, [tableState, activeRowId]);
@@ -125,10 +129,21 @@ function GridTable(props) {
125
129
  }
126
130
  return rows;
127
131
  }, [columns, rows, sortOn, sortState, caseSensitive]);
128
- const hasTotalsRow = rows.some((row) => row.id === "totals");
129
132
  // Flatten + component-ize the sorted rows.
130
- let [headerRows, visibleDataRows, totalsRows, filteredRowIds] = (0, react_1.useMemo)(() => {
133
+ let [headerRows, visibleDataRows, totalsRows, expandableHeaderRows, filteredRowIds] = (0, react_1.useMemo)(() => {
131
134
  function makeRowComponent(row, level) {
135
+ // We may have multiple rows that need to be sticky, if that is the case, then we need properly define the stickyOffset for each row.
136
+ // *TOTALS* will always be on top, so that can remain 0.
137
+ // *EXPANDABLE_HEADER Header* may need to include the height of the totals row in the offset
138
+ // *HEADER* may need to include both TOTALS and EXPANDABLE_HEADER in its offset.
139
+ // TODO: Create a single "table header" container that can hold multiple rows and use a single `position: sticky`. And we can get rid of this nonsense.
140
+ const maybeTotalsRowHeight = hasTotalsRow ? TableStyles_1.totalsRowHeight : 0;
141
+ const maybeExpandableRowsHeight = hasExpandableHeader ? TableStyles_1.expandableHeaderRowHeight : 0;
142
+ const rowStickyOffset = row.kind === utils_1.HEADER
143
+ ? maybeTotalsRowHeight + maybeExpandableRowsHeight
144
+ : row.kind === utils_1.EXPANDABLE_HEADER
145
+ ? maybeTotalsRowHeight
146
+ : 0;
132
147
  return ((0, jsx_runtime_1.jsx)(Row_1.Row, Object.assign({}, {
133
148
  as,
134
149
  columns,
@@ -136,8 +151,7 @@ function GridTable(props) {
136
151
  style,
137
152
  rowStyles,
138
153
  stickyHeader,
139
- // If we have a totals row then add the height of the totals row (52px) to the `stickyOffset` for the "header" kind
140
- stickyOffset: hasTotalsRow && row.kind === "header" ? 52 + stickyOffset : stickyOffset,
154
+ stickyOffset: rowStickyOffset + stickyOffset,
141
155
  columnSizes,
142
156
  level,
143
157
  getCount,
@@ -145,13 +159,17 @@ function GridTable(props) {
145
159
  cellHighlight: "cellHighlight" in maybeStyle && maybeStyle.cellHighlight === true,
146
160
  omitRowHover: "rowHover" in maybeStyle && maybeStyle.rowHover === false,
147
161
  sortOn,
162
+ hasExpandableHeader,
148
163
  }), `${row.kind}-${row.id}`));
149
164
  }
150
165
  // Split out the header rows from the data rows so that we can put an `infoMessage` in between them (if needed).
151
166
  const headerRows = [];
167
+ const expandableHeaderRows = [];
152
168
  const totalsRows = [];
153
169
  const visibleDataRows = [];
154
170
  const filteredRowIds = [];
171
+ const hasTotalsRow = rows.some((row) => row.id === utils_1.TOTALS);
172
+ const hasExpandableHeader = rows.some((row) => row.id === utils_1.EXPANDABLE_HEADER);
155
173
  function visit([row, children], level, visible) {
156
174
  visible && visibleDataRows.push([row, makeRowComponent(row, level)]);
157
175
  // This row may be invisible (because it's parent is collapsed), but we still want
@@ -173,13 +191,17 @@ function GridTable(props) {
173
191
  totalsRows.push([row[0], makeRowComponent(row[0], level)]);
174
192
  return;
175
193
  }
194
+ if (row[0].kind === "expandableHeader") {
195
+ expandableHeaderRows.push([row[0], makeRowComponent(row[0], level)]);
196
+ return;
197
+ }
176
198
  visit(row, level, visible);
177
199
  });
178
200
  }
179
201
  // Call `visitRows` with our a pre-filtered set list
180
202
  const filteredRows = filterRows(api, columns, maybeSorted, filter);
181
203
  visitRows(filteredRows, 0, true);
182
- return [headerRows, visibleDataRows, totalsRows, filteredRowIds];
204
+ return [headerRows, visibleDataRows, totalsRows, expandableHeaderRows, filteredRowIds];
183
205
  }, [
184
206
  as,
185
207
  api,
@@ -194,7 +216,6 @@ function GridTable(props) {
194
216
  columnSizes,
195
217
  collapsedIds,
196
218
  getCount,
197
- hasTotalsRow,
198
219
  ]);
199
220
  let tooManyClientSideRows = false;
200
221
  if (filterMaxRows && visibleDataRows.length > filterMaxRows) {
@@ -230,7 +251,7 @@ function GridTable(props) {
230
251
  // behave semantically the same as `as=div` did for its tests.
231
252
  const _as = as === "virtual" && runningInJest ? "div" : as;
232
253
  const rowStateContext = (0, react_1.useMemo)(() => ({ tableState: tableState }), [tableState]);
233
- return ((0, jsx_runtime_1.jsx)(TableState_1.TableStateContext.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.if(as === "virtual").w("calc(100% - 20px)").$ }, void 0), renders[_as](style, id, columns, headerRows, totalsRows, visibleDataRows, firstRowMessage, stickyHeader, xss, virtuosoRef)] }), void 0) }), void 0));
254
+ return ((0, jsx_runtime_1.jsx)(TableState_1.TableStateContext.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.if(as === "virtual").w("calc(100% - 20px)").$ }, void 0), renders[_as](style, id, columns, headerRows, totalsRows, expandableHeaderRows, visibleDataRows, firstRowMessage, stickyHeader, xss, virtuosoRef)] }), void 0) }), void 0));
234
255
  }
235
256
  exports.GridTable = GridTable;
236
257
  // Determine which HTML element to use to build the GridTable
@@ -240,7 +261,7 @@ const renders = {
240
261
  virtual: renderVirtual,
241
262
  };
242
263
  /** Renders table using divs with flexbox rows, which is the default render */
243
- function renderDiv(style, id, columns, headerRows, totalsRows, visibleDataRows, firstRowMessage, _stickyHeader, xss, _virtuosoRef) {
264
+ function renderDiv(style, id, columns, headerRows, totalsRows, expandableHeaderRows, visibleDataRows, firstRowMessage, _stickyHeader, xss, _virtuosoRef) {
244
265
  return ((0, jsx_runtime_1.jsxs)("div", Object.assign({ css: {
245
266
  // Use `fit-content` to ensure the width of the table takes up the full width of its content.
246
267
  // Otherwise, the table's width would be that of its container, which may not be as wide as the table itself.
@@ -261,10 +282,10 @@ function renderDiv(style, id, columns, headerRows, totalsRows, visibleDataRows,
261
282
  ...style.rootCss,
262
283
  ...(style.minWidthPx ? Css_1.Css.mwPx(style.minWidthPx).$ : {}),
263
284
  ...xss,
264
- }, "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));
285
+ }, "data-testid": id }, { children: [totalsRows.map(([, node]) => node), expandableHeaderRows.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));
265
286
  }
266
287
  /** Renders as a table, primarily/solely for good print support. */
267
- function renderTable(style, id, columns, headerRows, totalsRows, visibleDataRows, firstRowMessage, _stickyHeader, xss, _virtuosoRef) {
288
+ function renderTable(style, id, columns, headerRows, totalsRows, expandableHeaderRows, visibleDataRows, firstRowMessage, _stickyHeader, xss, _virtuosoRef) {
268
289
  return ((0, jsx_runtime_1.jsxs)("table", Object.assign({ css: {
269
290
  ...Css_1.Css.w100.add("borderCollapse", "separate").add("borderSpacing", "0").$,
270
291
  ...Css_1.Css.addIn("& > tbody > tr > * ", style.betweenRowsCss || {})
@@ -275,7 +296,7 @@ function renderTable(style, id, columns, headerRows, totalsRows, visibleDataRows
275
296
  ...style.rootCss,
276
297
  ...(style.minWidthPx ? Css_1.Css.mwPx(style.minWidthPx).$ : {}),
277
298
  ...xss,
278
- }, "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));
299
+ }, "data-testid": id }, { children: [(0, jsx_runtime_1.jsx)("thead", { children: [...totalsRows, ...expandableHeaderRows, ...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));
279
300
  }
280
301
  /**
281
302
  * Uses react-virtuoso to render rows virtually.
@@ -297,7 +318,7 @@ function renderTable(style, id, columns, headerRows, totalsRows, visibleDataRows
297
318
  * [2]: https://github.com/tannerlinsley/react-virtual/issues/85
298
319
  * [3]: https://github.com/tannerlinsley/react-virtual/issues/108
299
320
  */
300
- function renderVirtual(style, id, columns, headerRows, totalsRows, visibleDataRows, firstRowMessage, stickyHeader, xss, virtuosoRef) {
321
+ function renderVirtual(style, id, columns, headerRows, totalsRows, expandableHeaderRows, visibleDataRows, firstRowMessage, stickyHeader, xss, virtuosoRef) {
301
322
  // eslint-disable-next-line react-hooks/rules-of-hooks
302
323
  const { footerStyle, listStyle } = (0, react_1.useMemo)(() => {
303
324
  var _a;
@@ -306,13 +327,14 @@ function renderVirtual(style, id, columns, headerRows, totalsRows, visibleDataRo
306
327
  }, [style]);
307
328
  return ((0, jsx_runtime_1.jsx)(react_virtuoso_1.Virtuoso, { overscan: 5, ref: virtuosoRef, components: {
308
329
  // Applying a zIndex: 2 to ensure it stays on top of sticky columns
309
- TopItemList: react_1.default.forwardRef((props, ref) => ((0, jsx_runtime_1.jsx)("div", Object.assign({}, props, { ref: ref, style: { ...props.style, ...{ zIndex: 2 } } }), void 0))),
330
+ TopItemList: react_1.default.forwardRef((props, ref) => ((0, jsx_runtime_1.jsx)("div", Object.assign({}, props, { ref: ref, style: { ...props.style, ...{ zIndex: utils_1.zIndices.stickyHeader } } }), void 0))),
310
331
  List: VirtualRoot(listStyle, columns, id, xss),
311
332
  Footer: () => (0, jsx_runtime_1.jsx)("div", { css: footerStyle }, void 0),
312
333
  },
313
334
  // Pin/sticky both the header row(s) + firstRowMessage to the top
314
- topItemCount: (stickyHeader ? headerRows.length + totalsRows.length : 0) + (firstRowMessage ? 1 : 0), itemContent: (index) => {
315
- // Since we have three arrays of rows: `headerRows`, `totalsRows`, and `filteredRow` we
335
+ topItemCount: (stickyHeader ? headerRows.length + totalsRows.length + expandableHeaderRows.length : 0) +
336
+ (firstRowMessage ? 1 : 0), itemContent: (index) => {
337
+ // Since we have 4 arrays of rows: `headerRows`, `totalsRows`, `expandableHeaderRows`, and `filteredRow` we
316
338
  // must determine which one to render.
317
339
  // Determine if we need to render a totals row
318
340
  if (index < totalsRows.length) {
@@ -320,6 +342,12 @@ function renderVirtual(style, id, columns, headerRows, totalsRows, visibleDataRo
320
342
  }
321
343
  // Reset index
322
344
  index -= totalsRows.length;
345
+ // Determine if we need to render an expandableHeaderRows row
346
+ if (index < expandableHeaderRows.length) {
347
+ return expandableHeaderRows[index][1];
348
+ }
349
+ // Reset index
350
+ index -= expandableHeaderRows.length;
323
351
  // Determine if we need to render a header row
324
352
  if (index < headerRows.length) {
325
353
  return headerRows[index][1];
@@ -392,10 +420,9 @@ function filterRows(api, columns, rows, filter) {
392
420
  var _a, _b, _c, _d;
393
421
  // Break up "foo bar" into `[foo, bar]` and a row must match both `foo` and `bar`
394
422
  const filters = (filter && filter.split(/ +/)) || [];
395
- const matches = row.kind === "header" ||
396
- row.kind === "totals" ||
423
+ const matches = utils_1.reservedRowKinds.includes(row.kind) ||
397
424
  filters.length === 0 ||
398
- filters.every((f) => columns.map((c) => (0, utils_1.applyRowFn)(c, row, api, 0)).some((maybeContent) => (0, utils_1.matchesFilter)(maybeContent, f)));
425
+ filters.every((f) => columns.map((c) => (0, utils_1.applyRowFn)(c, row, api, 0, false)).some((maybeContent) => (0, utils_1.matchesFilter)(maybeContent, f)));
399
426
  if (matches) {
400
427
  return acc.concat([[row, (_b = (_a = row.children) === null || _a === void 0 ? void 0 : _a.reduce(acceptAll, [])) !== null && _b !== void 0 ? _b : []]]);
401
428
  }
@@ -39,6 +39,8 @@ export declare type GridTableApi<R extends Kinded> = {
39
39
  selectRow: (id: string, selected?: boolean) => void;
40
40
  /** Toggle collapse state of a row by id */
41
41
  toggleCollapsedRow: (id: string) => void;
42
+ setVisibleColumns: (ids: string[]) => void;
43
+ getVisibleColumnIds: () => string[];
42
44
  };
43
45
  export declare class GridTableApiImpl<R extends Kinded> implements GridTableApi<R> {
44
46
  readonly tableState: TableState;
@@ -53,4 +55,6 @@ export declare class GridTableApiImpl<R extends Kinded> implements GridTableApi<
53
55
  setActiveCellId(id: string | undefined): void;
54
56
  selectRow(id: string, selected?: boolean): void;
55
57
  toggleCollapsedRow(id: string): void;
58
+ setVisibleColumns(ids: string[]): void;
59
+ getVisibleColumnIds(): string[];
56
60
  }
@@ -68,5 +68,11 @@ class GridTableApiImpl {
68
68
  toggleCollapsedRow(id) {
69
69
  this.tableState.toggleCollapsed(id);
70
70
  }
71
+ setVisibleColumns(ids) {
72
+ this.tableState.setVisibleColumns(ids);
73
+ }
74
+ getVisibleColumnIds() {
75
+ return this.tableState.visibleColumnIds;
76
+ }
71
77
  }
72
78
  exports.GridTableApiImpl = GridTableApiImpl;
@@ -28,6 +28,8 @@ export interface GridStyle {
28
28
  headerCellCss?: Properties;
29
29
  /** Applied to 'kind: "totals"' cells */
30
30
  totalsCellCss?: Properties;
31
+ /** Applied to 'kind: "expandableHeader"' cells */
32
+ expandableHeaderCss?: Properties;
31
33
  /** Applied to the first cell of all rows, i.e. for table-wide padding or left-side borders. */
32
34
  firstCellCss?: Properties;
33
35
  /** Applied to the last cell of all rows, i.e. for table-wide padding or right-side borders. */
@@ -64,6 +66,8 @@ export interface GridStyleDef {
64
66
  rowHover?: boolean;
65
67
  }
66
68
  export declare const getTableStyles: (props?: GridStyleDef) => GridStyle;
69
+ export declare const totalsRowHeight = 52;
70
+ export declare const expandableHeaderRowHeight = 40;
67
71
  /** Defines row-specific styling for each given row `kind` in `R` */
68
72
  export declare type RowStyles<R extends Kinded> = {
69
73
  [P in R["kind"]]?: RowStyle<DiscriminateUnion<R, "kind", P>>;
@@ -1,13 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.resolveStyles = exports.tableRowStyles = exports.cardStyle = exports.condensedStyle = exports.defaultStyle = exports.getTableStyles = void 0;
3
+ exports.resolveStyles = exports.tableRowStyles = exports.cardStyle = exports.condensedStyle = exports.defaultStyle = exports.expandableHeaderRowHeight = exports.totalsRowHeight = exports.getTableStyles = void 0;
4
4
  const Css_1 = require("../../Css");
5
5
  const utils_1 = require("../../utils");
6
6
  // Returns a "blessed" style of GridTable
7
7
  function memoizedTableStyles() {
8
8
  const cache = {};
9
9
  return (props = {}) => {
10
- const { inlineEditing = false, grouped = false, rowHeight = "flexible", cellHighlight = false, allWhite = false, bordered = false, rowHover = true, } = props;
10
+ const { inlineEditing = false, grouped = false, rowHeight = "flexible", cellHighlight = false, allWhite = false, bordered = false, } = props;
11
11
  const key = (0, utils_1.safeKeys)(props)
12
12
  .sort()
13
13
  .map((k) => `${k}_${props[k]}`)
@@ -30,9 +30,13 @@ function memoizedTableStyles() {
30
30
  headerCellCss: {
31
31
  ...Css_1.Css.gray700.xsMd.bgGray200.aic.nowrap.pxPx(12).hPx(40).$,
32
32
  ...(allWhite && Css_1.Css.bgWhite.$),
33
- ...(bordered && Css_1.Css.bt.bGray200.$),
34
33
  },
35
- totalsCellCss: Css_1.Css.bgWhite.gray700.smMd.hPx(52).pPx(12).boxShadow("none").$,
34
+ totalsCellCss: Css_1.Css.bgWhite.gray700.smMd.hPx(exports.totalsRowHeight).pPx(12).boxShadow("none").$,
35
+ expandableHeaderCss: Css_1.Css.bgWhite.gray900.xsMd.wsNormal
36
+ .hPx(exports.expandableHeaderRowHeight)
37
+ .pxPx(12)
38
+ .py0.boxShadow(`inset 0 -1px 0 ${Css_1.Palette.Gray200}`)
39
+ .addIn("&:not(:last-of-type)", Css_1.Css.boxShadow(`inset -1px -1px 0 ${Css_1.Palette.Gray200}`).$).$,
36
40
  cellCss: {
37
41
  ...Css_1.Css.gray900.xs.bgWhite.aic.pxPx(12).boxShadow(`inset 0 -1px 0 ${Css_1.Palette.Gray200}`).$,
38
42
  ...(rowHeight === "flexible" ? Css_1.Css.pyPx(12).$ : Css_1.Css.nowrap.hPx(inlineEditing ? 48 : 36).$),
@@ -40,9 +44,7 @@ function memoizedTableStyles() {
40
44
  ...(bordered && { "&:first-of-type": Css_1.Css.bl.bGray200.$, "&:last-of-type": Css_1.Css.br.bGray200.$ }),
41
45
  },
42
46
  firstRowCss: {
43
- // Only apply border-radius to the corners of the table when `allWhite` is true for now.
44
- ...(allWhite &&
45
- Css_1.Css.addIn("& > *:first-of-type", Css_1.Css.borderRadius("8px 0 0 0 ").$).addIn("& > *:last-of-type", Css_1.Css.borderRadius("0 8px 0 0").$).$),
47
+ ...Css_1.Css.addIn("& > *:first-of-type", Css_1.Css.borderRadius("8px 0 0 0 ").$).addIn("& > *:last-of-type", Css_1.Css.borderRadius("0 8px 0 0").$).$,
46
48
  ...(bordered && Css_1.Css.addIn("& > *", Css_1.Css.bt.bGray200.$).$),
47
49
  },
48
50
  ...(allWhite && {
@@ -57,6 +59,8 @@ function memoizedTableStyles() {
57
59
  };
58
60
  }
59
61
  exports.getTableStyles = memoizedTableStyles();
62
+ exports.totalsRowHeight = 52;
63
+ exports.expandableHeaderRowHeight = 40;
60
64
  /** Our original table look & feel/style. */
61
65
  exports.defaultStyle = {
62
66
  rootCss: Css_1.Css.gray700.$,
@@ -1,11 +1,10 @@
1
- import { Dispatch, SetStateAction } from "react";
2
1
  import { OverlayTriggerProps } from "../../internal/OverlayTrigger";
2
+ import { GridTableApi } from "../GridTableApi";
3
3
  import { GridColumn, Kinded } from "../types";
4
4
  interface EditColumnsButtonProps<R extends Kinded> extends Pick<OverlayTriggerProps, "trigger" | "placement" | "disabled" | "tooltip"> {
5
- allColumns: GridColumn<R>[];
6
- selectedColumns: GridColumn<R>[];
7
- setSelectedColumns: Dispatch<SetStateAction<GridColumn<R>[]>>;
5
+ columns: GridColumn<R>[];
8
6
  title?: string;
7
+ api: GridTableApi<R>;
9
8
  defaultOpen?: boolean;
10
9
  }
11
10
  export declare function EditColumnsButton<R extends Kinded>(props: EditColumnsButtonProps<R>): import("@emotion/react/jsx-runtime").JSX.Element;
@@ -8,31 +8,32 @@ const react_stately_1 = require("react-stately");
8
8
  const Button_1 = require("../../Button");
9
9
  const OverlayTrigger_1 = require("../../internal/OverlayTrigger");
10
10
  const Css_1 = require("../../../Css");
11
+ const hooks_1 = require("../../../hooks");
11
12
  const inputs_1 = require("../../../inputs");
12
13
  const utils_1 = require("../../../utils");
13
14
  function EditColumnsButton(props) {
14
- const { defaultOpen, disabled, allColumns, setSelectedColumns, trigger, title, selectedColumns } = props;
15
+ const { defaultOpen, disabled, columns, trigger, title, api } = props;
15
16
  const state = (0, react_stately_1.useMenuTriggerState)({ isOpen: defaultOpen });
16
17
  const buttonRef = (0, react_1.useRef)(null);
17
18
  const { menuTriggerProps } = (0, react_aria_1.useMenuTrigger)({ isDisabled: !!disabled }, state, buttonRef);
18
19
  const tid = (0, utils_1.useTestIds)(props, (0, OverlayTrigger_1.isTextButton)(trigger) ? trigger.label : (0, OverlayTrigger_1.isIconButton)(trigger) ? trigger.icon : trigger.name);
19
20
  const { options } = (0, react_1.useMemo)(() => {
20
- return allColumns.reduce((acc, column) => {
21
+ return columns.reduce((acc, column) => {
21
22
  // Only include options that can be hidden and have the `name` property defined.
22
23
  if (!column.canHide)
23
24
  return acc;
24
- if (!column.id || column.id.length === 0) {
25
- console.warn("Column is missing 'name' property required by the Edit Columns button", column);
25
+ if (!column.name || column.name.length === 0 || !column.id || column.id.length === 0) {
26
+ console.warn("Column is missing 'name' and/or 'id' property required by the Edit Columns button", column);
26
27
  return acc;
27
28
  }
28
29
  // Add current column as an option
29
- return { ...acc, options: acc.options.concat({ label: column.id, value: column.id }) };
30
+ return { ...acc, options: acc.options.concat({ label: column.name, value: column.id }) };
30
31
  }, { options: [] });
31
- }, [allColumns]);
32
- const selectedValues = selectedColumns.map((column) => column.id);
32
+ }, [columns]);
33
+ const selectedValues = (0, hooks_1.useComputed)(() => api.getVisibleColumnIds(), [api]);
33
34
  const setSelectedValues = (0, react_1.useCallback)((values) => {
34
- setSelectedColumns(allColumns.filter((column) => (column.canHide ? values.includes(column.id) : true)));
35
- }, [allColumns, setSelectedColumns]);
35
+ api.setVisibleColumns(columns.filter((column) => (column.canHide ? values.includes(column.id) : true)).map((c) => c.id));
36
+ }, [columns, api]);
36
37
  return ((0, jsx_runtime_1.jsx)(OverlayTrigger_1.OverlayTrigger, Object.assign({}, props, { menuTriggerProps: menuTriggerProps, state: state, buttonRef: buttonRef }, tid, { children: (0, jsx_runtime_1.jsxs)("div", Object.assign({ css: {
37
38
  ...Css_1.Css.bgWhite.py5.px3.maxwPx(380).bshBasic.$,
38
39
  "&:hover": Css_1.Css.bshHover.$,
@@ -0,0 +1,9 @@
1
+ import { GridColumnWithId, Kinded, RenderAs } from "../types";
2
+ interface ExpandableHeaderProps<R extends Kinded> {
3
+ title: string;
4
+ column: GridColumnWithId<R>;
5
+ minStickyLeftOffset: number;
6
+ as: RenderAs;
7
+ }
8
+ export declare function ExpandableHeader<R extends Kinded>(props: ExpandableHeaderProps<R>): import("@emotion/react/jsx-runtime").JSX.Element;
9
+ export {};
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ExpandableHeader = void 0;
4
+ const jsx_runtime_1 = require("@emotion/react/jsx-runtime");
5
+ const react_1 = require("react");
6
+ const Icon_1 = require("../../Icon");
7
+ const TableState_1 = require("../utils/TableState");
8
+ const utils_1 = require("../utils/utils");
9
+ const Css_1 = require("../../../Css");
10
+ const hooks_1 = require("../../../hooks");
11
+ function ExpandableHeader(props) {
12
+ const { title, column, minStickyLeftOffset, as } = props;
13
+ const { tableState } = (0, react_1.useContext)(TableState_1.TableStateContext);
14
+ const expandedColumnIds = (0, hooks_1.useComputed)(() => tableState.expandedColumnIds, [tableState]);
15
+ const isExpanded = expandedColumnIds.includes(column.id);
16
+ // Do not apply sticky styles when rendering as table. Currently the table does not properly respect column widths, causing the sticky offsets to be incorrect
17
+ const applyStickyStyles = isExpanded && as !== "table";
18
+ const { hoverProps, isHovered } = (0, hooks_1.useHover)({});
19
+ return ((0, jsx_runtime_1.jsxs)("button", Object.assign({}, hoverProps, { css: Css_1.Css.df.xsMd.aic.jcsb.gap2.px1.hPx(32).mxPx(-8).w("calc(100% + 16px)").br4.lightBlue700.if(isHovered).bgGray100.$, onClick: () => tableState.toggleExpandedColumn(column.id), "data-testid": "expandableColumn" }, { children: [(0, jsx_runtime_1.jsx)("span", Object.assign({ css: Css_1.Css.tl.lineClamp2
20
+ .if(applyStickyStyles)
21
+ .sticky.leftPx(minStickyLeftOffset + 12)
22
+ .pr2.mr2.bgWhite.z(utils_1.zIndices.expandableHeaderTitle)
23
+ .if(isHovered).bgGray100.$ }, { children: title }), void 0), (0, jsx_runtime_1.jsx)("span", Object.assign({ css: Css_1.Css.if(applyStickyStyles).sticky.rightPx(12).z(utils_1.zIndices.expandableHeaderIcon).$ }, { children: (0, jsx_runtime_1.jsx)(Icon_1.Icon, { icon: isExpanded ? "chevronLeft" : "chevronRight", inc: 2 }, void 0) }), void 0)] }), void 0));
24
+ }
25
+ exports.ExpandableHeader = ExpandableHeader;
@@ -18,6 +18,7 @@ interface RowProps<R extends Kinded> {
18
18
  api: GridTableApi<R>;
19
19
  cellHighlight: boolean;
20
20
  omitRowHover: boolean;
21
+ hasExpandableHeader: boolean;
21
22
  }
22
23
  declare function RowImpl<R extends Kinded, S>(props: RowProps<R>): ReactElement;
23
24
  /**
@@ -33,17 +33,18 @@ const shallowEqual_1 = require("../../../utils/shallowEqual");
33
33
  // We extract Row to its own mini-component primarily so we can React.memo'ize it.
34
34
  function RowImpl(props) {
35
35
  var _a;
36
- const { as, columns, row, style, rowStyles, stickyHeader, stickyOffset, sortOn, columnSizes, level, getCount, api, cellHighlight, omitRowHover, ...others } = props;
36
+ const { as, columns, row, style, rowStyles, stickyHeader, stickyOffset, sortOn, columnSizes, level, getCount, api, cellHighlight, omitRowHover, hasExpandableHeader, ...others } = props;
37
37
  const { tableState } = (0, react_1.useContext)(TableState_1.TableStateContext);
38
38
  const rowId = `${row.kind}_${row.id}`;
39
39
  const isActive = (0, hooks_1.useComputed)(() => tableState.activeRowId === rowId, [rowId, tableState]);
40
40
  // We treat the "header" and "totals" kind as special for "good defaults" styling
41
- const isHeader = row.kind === "header";
42
- const isTotals = row.kind === "totals";
41
+ const isHeader = row.kind === utils_1.HEADER;
42
+ const isTotals = row.kind === utils_1.TOTALS;
43
+ const isExpandableHeader = row.kind === utils_1.EXPANDABLE_HEADER;
43
44
  const rowStyle = rowStyles === null || rowStyles === void 0 ? void 0 : rowStyles[row.kind];
44
45
  const RowTag = as === "table" ? "tr" : "div";
45
46
  const revealOnRowHoverClass = "revealOnRowHover";
46
- const showRowHoverColor = row.kind !== "totals" && row.kind !== "header" && !omitRowHover;
47
+ const showRowHoverColor = !utils_1.reservedRowKinds.includes(row.kind) && !omitRowHover;
47
48
  const rowStyleCellCss = (0, utils_1.maybeApplyFunction)(row, rowStyle === null || rowStyle === void 0 ? void 0 : rowStyle.cellCss);
48
49
  const rowCss = {
49
50
  // Optionally include the row hover styles, by default they should be turned on.
@@ -57,16 +58,23 @@ function RowImpl(props) {
57
58
  ...(((rowStyle === null || rowStyle === void 0 ? void 0 : rowStyle.rowLink) || (rowStyle === null || rowStyle === void 0 ? void 0 : rowStyle.onClick)) && { "&:hover": Css_1.Css.cursorPointer.$ }),
58
59
  ...(0, utils_1.maybeApplyFunction)(row, rowStyle === null || rowStyle === void 0 ? void 0 : rowStyle.rowCss),
59
60
  // Maybe add the sticky header styles
60
- ...((isHeader || isTotals) && stickyHeader ? Css_1.Css.sticky.topPx(stickyOffset).z2.$ : undefined),
61
+ ...(utils_1.reservedRowKinds.includes(row.kind) && stickyHeader
62
+ ? Css_1.Css.sticky.topPx(stickyOffset).z(utils_1.zIndices.stickyHeader).$
63
+ : undefined),
61
64
  ...{
62
65
  [` > .${revealOnRowHoverClass} > *`]: Css_1.Css.invisible.$,
63
66
  [`:hover > .${revealOnRowHoverClass} > *`]: Css_1.Css.visible.$,
64
67
  },
65
68
  };
66
69
  let currentColspan = 1;
70
+ // Keep a running count of how many expanded columns are being shown.
71
+ let currentExpandedColumnCount = 0;
67
72
  let firstContentColumnStylesApplied = false;
73
+ let minStickyLeftOffset = 0;
68
74
  return ((0, jsx_runtime_1.jsx)(RowTag, Object.assign({ css: rowCss }, others, { "data-gridrow": true }, getCount(row.id), { children: columns.map((column, columnIndex) => {
69
- var _a, _b, _c, _d, _e;
75
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
76
+ // Need to keep track of the expanded columns so we can add borders as expected for the header rows
77
+ const isExpanded = tableState.expandedColumnIds.includes(column.id);
70
78
  const { wrapAction = true, isAction = false } = column;
71
79
  const applyFirstContentColumnStyles = !isHeader && !isAction && !firstContentColumnStylesApplied;
72
80
  firstContentColumnStylesApplied || (firstContentColumnStylesApplied = applyFirstContentColumnStyles);
@@ -76,24 +84,40 @@ function RowImpl(props) {
76
84
  throw new Error("Beam Table column min-width definition only supports px or percentage values");
77
85
  }
78
86
  }
87
+ // When using the variation of the table with an EXPANDABLE_HEADER, then our HEADER row required special border styling
88
+ if (hasExpandableHeader && (isHeader || isTotals)) {
89
+ // When the value of `currentExpandedColumnCount` is 0, then we have started over.
90
+ // If the current column `isExpanded`, then store the number of expandable columns.
91
+ if (currentExpandedColumnCount === 0 && isExpanded) {
92
+ currentExpandedColumnCount = (_b = (_a = column.expandColumns) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
93
+ }
94
+ else if (currentExpandedColumnCount > 0) {
95
+ // If value is great than 0, then decrement. Once the value equals 0, then the special styling will be applied below.
96
+ currentExpandedColumnCount -= 1;
97
+ }
98
+ }
79
99
  // Decrement colspan count and skip if greater than 1.
80
100
  if (currentColspan > 1) {
81
101
  currentColspan -= 1;
82
102
  return null;
83
103
  }
84
- const maybeContent = (0, utils_1.applyRowFn)(column, row, api, level);
85
- currentColspan = (0, utils_1.isGridCellContent)(maybeContent) ? (_a = maybeContent.colspan) !== null && _a !== void 0 ? _a : 1 : 1;
104
+ const maybeContent = (0, utils_1.applyRowFn)(column, row, api, level, isExpanded);
105
+ const numExpandedColumns = isExpandableHeader && isExpanded ? (_d = (_c = column.expandColumns) === null || _c === void 0 ? void 0 : _c.length) !== null && _d !== void 0 ? _d : 0 : 0;
106
+ currentColspan = (0, utils_1.isGridCellContent)(maybeContent)
107
+ ? (_e = maybeContent.colspan) !== null && _e !== void 0 ? _e : numExpandedColumns + 1
108
+ : numExpandedColumns + 1;
86
109
  const revealOnRowHover = (0, utils_1.isGridCellContent)(maybeContent) ? maybeContent.revealOnRowHover : false;
87
110
  const canSortColumn = (sortOn === "client" && column.clientSideSort !== false) ||
88
111
  (sortOn === "server" && !!column.serverSideSortKey);
89
112
  const alignment = (0, utils_1.getAlignment)(column, maybeContent);
90
113
  const justificationCss = (0, utils_1.getJustification)(column, maybeContent, as, alignment);
91
- const content = (0, utils_1.toContent)(maybeContent, isHeader, canSortColumn, sortOn === "client", style, as, alignment, column);
92
- (0, sortRows_1.ensureClientSideSortValueIsSortable)(sortOn, isHeader, column, columnIndex, maybeContent);
93
- const maybeSticky = (_b = (((0, utils_1.isGridCellContent)(maybeContent) && maybeContent.sticky) || column.sticky)) !== null && _b !== void 0 ? _b : undefined;
114
+ const isExpandable = column.expandColumns !== undefined && column.expandColumns.length > 0;
115
+ const content = (0, utils_1.toContent)(maybeContent, isHeader, canSortColumn, sortOn === "client", style, as, alignment, column, isExpandableHeader, isExpandable, minStickyLeftOffset);
116
+ (0, sortRows_1.ensureClientSideSortValueIsSortable)(sortOn, isHeader || isTotals || isExpandableHeader, column, columnIndex, maybeContent);
117
+ const maybeSticky = (_f = (((0, utils_1.isGridCellContent)(maybeContent) && maybeContent.sticky) || column.sticky)) !== null && _f !== void 0 ? _f : undefined;
94
118
  const maybeStickyColumnStyles = maybeSticky && columnSizes
95
119
  ? {
96
- ...Css_1.Css.sticky.z1.bgWhite.$,
120
+ ...Css_1.Css.sticky.z(utils_1.zIndices.stickyColumns).bgWhite.$,
97
121
  ...(maybeSticky === "left"
98
122
  ? Css_1.Css.left(columnIndex === 0 ? 0 : `calc(${columnSizes.slice(0, columnIndex).join(" + ")})`).$
99
123
  : {}),
@@ -104,6 +128,8 @@ function RowImpl(props) {
104
128
  : {}),
105
129
  }
106
130
  : {};
131
+ // This relies on our column sizes being defined in pixel values, which is currently true as we calculate to pixel values in the `useSetupColumnSizes` hook
132
+ minStickyLeftOffset += maybeSticky === "left" ? parseInt(columnSizes[columnIndex].replace("px", ""), 10) : 0;
107
133
  const cellId = `${row.kind}_${row.id}_${column.id}`;
108
134
  const applyCellHighlight = cellHighlight && !!column.id && !isHeader && !isTotals;
109
135
  const isCellActive = tableState.activeCellId === cellId;
@@ -132,14 +158,22 @@ function RowImpl(props) {
132
158
  ...(isHeader && style.headerCellCss),
133
159
  // Then apply any totals-specific override
134
160
  ...(isTotals && style.totalsCellCss),
161
+ ...(isTotals && hasExpandableHeader && Css_1.Css.boxShadow(`inset 0 -1px 0 ${Css_1.Palette.Gray200}`).$),
162
+ // Then apply any expandable header specific override
163
+ ...(isExpandableHeader && style.expandableHeaderCss),
164
+ // Apply the right border styling for the header row when using expandable tables and this column is the last expandable column, or not expanded.
165
+ ...(hasExpandableHeader &&
166
+ (isHeader || isTotals) &&
167
+ currentExpandedColumnCount === 0 &&
168
+ Css_1.Css.boxShadow(`inset -1px -1px 0 ${Css_1.Palette.Gray200}`).$),
135
169
  // Or level-specific styling
136
- ...(!isHeader && !isTotals && !!style.levels && ((_c = style.levels[level]) === null || _c === void 0 ? void 0 : _c.cellCss)),
170
+ ...(!isHeader && !isTotals && !isExpandableHeader && !!style.levels && ((_g = style.levels[level]) === null || _g === void 0 ? void 0 : _g.cellCss)),
137
171
  // Level specific styling for the first content column
138
- ...(applyFirstContentColumnStyles && !!style.levels && ((_d = style.levels[level]) === null || _d === void 0 ? void 0 : _d.firstContentColumn)),
172
+ ...(applyFirstContentColumnStyles && !!style.levels && ((_h = style.levels[level]) === null || _h === void 0 ? void 0 : _h.firstContentColumn)),
139
173
  // The specific cell's css (if any from GridCellContent)
140
174
  ...rowStyleCellCss,
141
175
  // Apply active row styling for non-nested card styles.
142
- ...(isActive ? Css_1.Css.bgColor((_e = style.activeBgColor) !== null && _e !== void 0 ? _e : Css_1.Palette.LightBlue50).$ : {}),
176
+ ...(isActive ? Css_1.Css.bgColor((_j = style.activeBgColor) !== null && _j !== void 0 ? _j : Css_1.Palette.LightBlue50).$ : {}),
143
177
  // Add any cell specific style overrides
144
178
  ...((0, utils_1.isGridCellContent)(maybeContent) && maybeContent.typeScale ? Css_1.Css[maybeContent.typeScale].$ : {}),
145
179
  // And any cell specific css
@@ -148,14 +182,16 @@ function RowImpl(props) {
148
182
  ...Css_1.Css.if(applyCellHighlight && isCellActive).br4.boxShadow(`inset 0 0 0 1px ${Css_1.Palette.LightBlue700}`).$,
149
183
  // Define the width of the column on each cell. Supports col spans.
150
184
  width: `calc(${columnSizes.slice(columnIndex, columnIndex + currentColspan).join(" + ")})`,
151
- ...(column.mw ? Css_1.Css.mw(column.mw).$ : {}),
185
+ ...(typeof column.mw === "string" ? Css_1.Css.mw(column.mw).$ : {}),
152
186
  };
153
187
  const cellClassNames = revealOnRowHover ? revealOnRowHoverClass : undefined;
154
188
  const cellOnClick = applyCellHighlight ? () => api.setActiveCellId(cellId) : undefined;
189
+ // If the expandable header is expanded, then we need to set a colspan on it which includes all expanded columns + this column.
190
+ const expandableHeaderColSpan = (isExpandableHeader && isExpanded ? (_l = (_k = column.expandColumns) === null || _k === void 0 ? void 0 : _k.length) !== null && _l !== void 0 ? _l : 0 : 0) + 1;
155
191
  const renderFn = ((rowStyle === null || rowStyle === void 0 ? void 0 : rowStyle.renderCell) || (rowStyle === null || rowStyle === void 0 ? void 0 : rowStyle.rowLink)) && wrapAction
156
192
  ? (0, cell_1.rowLinkRenderFn)(as)
157
- : isHeader
158
- ? (0, cell_1.headerRenderFn)(column, as)
193
+ : isHeader || isTotals || isExpandableHeader
194
+ ? (0, cell_1.headerRenderFn)(column, as, expandableHeaderColSpan)
159
195
  : (rowStyle === null || rowStyle === void 0 ? void 0 : rowStyle.onClick) && wrapAction
160
196
  ? (0, cell_1.rowClickRenderFn)(as, api)
161
197
  : (0, cell_1.defaultRenderFn)(as);
@@ -32,8 +32,11 @@ export declare type GridCellContent = {
32
32
  export declare type RenderCellFn<R extends Kinded> = (idx: number, css: Properties, content: ReactNode, row: R, rowStyle: RowStyle<R> | undefined, classNames: string | undefined, onClick: (() => void) | undefined) => ReactNode;
33
33
  /** Renders our default cell element, i.e. if no row links and no custom renderCell are used. */
34
34
  export declare const defaultRenderFn: (as: RenderAs) => RenderCellFn<any>;
35
- /** Sets up the `GridContext` so that header cells can access the current sort settings. */
36
- export declare const headerRenderFn: (column: GridColumnWithId<any>, as: RenderAs) => RenderCellFn<any>;
35
+ /**
36
+ * Sets up the `GridContext` so that header cells can access the current sort settings.
37
+ * Used for the Header, Totals, and Expanded Header row's cells.
38
+ * */
39
+ export declare const headerRenderFn: (column: GridColumnWithId<any>, as: RenderAs, colSpan: number) => RenderCellFn<any>;
37
40
  /** Renders a cell element when a row link is in play. */
38
41
  export declare const rowLinkRenderFn: (as: RenderAs) => RenderCellFn<any>;
39
42
  /** Renders a cell that will fire the RowStyle.onClick. */
@@ -12,10 +12,13 @@ const defaultRenderFn = (as) => (key, css, content, row, rowStyle, classNames, o
12
12
  return ((0, jsx_runtime_1.jsx)(Cell, Object.assign({ css: { ...css, ...(0, TableStyles_1.tableRowStyles)(as) }, className: classNames, onClick: onClick }, { children: content }), key));
13
13
  };
14
14
  exports.defaultRenderFn = defaultRenderFn;
15
- /** Sets up the `GridContext` so that header cells can access the current sort settings. */
16
- const headerRenderFn = (column, as) => (key, css, content, row, rowStyle, classNames) => {
15
+ /**
16
+ * Sets up the `GridContext` so that header cells can access the current sort settings.
17
+ * Used for the Header, Totals, and Expanded Header row's cells.
18
+ * */
19
+ const headerRenderFn = (column, as, colSpan) => (key, css, content, row, rowStyle, classNames) => {
17
20
  const Cell = as === "table" ? "th" : "div";
18
- return ((0, jsx_runtime_1.jsx)(Cell, Object.assign({ css: { ...css, ...(0, TableStyles_1.tableRowStyles)(as, column) }, className: classNames }, { children: content }), key));
21
+ return ((0, jsx_runtime_1.jsx)(Cell, Object.assign({ css: { ...css, ...(0, TableStyles_1.tableRowStyles)(as, column) }, className: classNames }, (as === "table" && { colSpan }), { children: content }), key));
19
22
  };
20
23
  exports.headerRenderFn = headerRenderFn;
21
24
  /** Renders a cell element when a row link is in play. */
@@ -9,7 +9,6 @@ export * from "./components/SortHeader";
9
9
  export { SortHeader } from "./components/SortHeader";
10
10
  export { useGridTableApi } from "./GridTableApi";
11
11
  export type { GridTableApi } from "./GridTableApi";
12
- export * from "./hooks/useColumns";
13
12
  export * from "./hooks/useSetupColumnSizes";
14
13
  export { cardStyle, condensedStyle, defaultStyle, getTableStyles } from "./TableStyles";
15
14
  export type { GridStyle, RowStyle, RowStyles } from "./TableStyles";
@@ -27,7 +27,6 @@ var SortHeader_1 = require("./components/SortHeader");
27
27
  Object.defineProperty(exports, "SortHeader", { enumerable: true, get: function () { return SortHeader_1.SortHeader; } });
28
28
  var GridTableApi_1 = require("./GridTableApi");
29
29
  Object.defineProperty(exports, "useGridTableApi", { enumerable: true, get: function () { return GridTableApi_1.useGridTableApi; } });
30
- __exportStar(require("./hooks/useColumns"), exports);
31
30
  __exportStar(require("./hooks/useSetupColumnSizes"), exports);
32
31
  var TableStyles_1 = require("./TableStyles");
33
32
  Object.defineProperty(exports, "cardStyle", { enumerable: true, get: function () { return TableStyles_1.cardStyle; } });
@@ -37,10 +37,12 @@ export declare type GridColumn<R extends Kinded> = {
37
37
  row: GridRowKind<R, K>;
38
38
  api: GridTableApi<R>;
39
39
  level: number;
40
+ expanded: boolean;
40
41
  }) => ReactNode | GridCellContent : (data: undefined, opts: {
41
42
  row: GridRowKind<R, K>;
42
43
  api: GridTableApi<R>;
43
44
  level: number;
45
+ expanded: boolean;
44
46
  }) => ReactNode | GridCellContent);
45
47
  } & {
46
48
  /**
@@ -66,13 +68,20 @@ export declare type GridColumn<R extends Kinded> = {
66
68
  isAction?: true;
67
69
  /** Column id that will be used to generate an unique identifier for every row cell */
68
70
  id?: string;
71
+ /** String identifier of the column. Typically the same text content as in column header. This is used to in things like the Edit Columns Button */
72
+ name?: string;
69
73
  /** Flag that will allow to know which columns are hide-able */
70
74
  canHide?: boolean;
71
75
  /** Flag that will allow to know which hide-able columns are visible on initial load */
72
76
  initVisible?: boolean;
77
+ /** A list of columns that should only be shown when this column is "expanded" */
78
+ expandColumns?: GridColumn<R>[];
79
+ /** Determines whether the group should initially be expanded on load of the table */
80
+ initExpanded?: boolean;
73
81
  };
74
82
  export declare type GridColumnWithId<R extends Kinded> = GridColumn<R> & {
75
83
  id: string;
84
+ expandColumns?: GridColumnWithId<R>[];
76
85
  };
77
86
  export declare const nonKindGridColumnKeys: string[];
78
87
  /**
@@ -13,4 +13,6 @@ exports.nonKindGridColumnKeys = [
13
13
  "id",
14
14
  "canHide",
15
15
  "initVisible",
16
+ "expandColumns",
17
+ "initExpanded",
16
18
  ];
@@ -1,3 +1,4 @@
1
+ import { ObservableSet } from "mobx";
1
2
  import React from "react";
2
3
  import { GridDataRow } from "../components/Row";
3
4
  import { GridSortConfig } from "../GridTable";
@@ -30,6 +31,10 @@ export declare class TableState {
30
31
  sort: SortState;
31
32
  private initialSortState;
32
33
  private onSort;
34
+ columns: GridColumnWithId<any>[];
35
+ private expandedColumns;
36
+ visibleColumns: ObservableSet<string>;
37
+ private visibleColumnStorageKey;
33
38
  /**
34
39
  * Creates the `RowState` for a given `GridTable`.
35
40
  */
@@ -40,6 +45,11 @@ export declare class TableState {
40
45
  setSortKey(clickedColumnId: string): void;
41
46
  get sortState(): SortState | undefined;
42
47
  setRows(rows: GridDataRow<any>[]): void;
48
+ setColumns(columns: GridColumnWithId<any>[]): void;
49
+ setVisibleColumns(ids: string[]): void;
50
+ get visibleColumnIds(): string[];
51
+ get expandedColumnIds(): string[];
52
+ toggleExpandedColumn(columnId: string): void;
43
53
  setMatchedRows(rowIds: string[]): void;
44
54
  get selectedIds(): string[];
45
55
  getSelected(id: string): SelectedState;
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.deriveSortState = exports.TableStateContext = exports.TableState = void 0;
7
+ const change_case_1 = require("change-case");
7
8
  const mobx_1 = require("mobx");
8
9
  const react_1 = __importDefault(require("react"));
9
10
  const utils_1 = require("./utils");
@@ -41,15 +42,25 @@ class TableState {
41
42
  this.activeCellId = undefined;
42
43
  // Provide some defaults to get the sort state to properly work.
43
44
  this.sort = {};
45
+ // Non-reactive list of our columns
46
+ this.columns = [];
47
+ // An observable set of column ids to keep track of which columns are currently expanded
48
+ this.expandedColumns = new mobx_1.ObservableSet();
49
+ // An observable set of column ids to keep track of which columns are visible
50
+ this.visibleColumns = new mobx_1.ObservableSet();
51
+ this.visibleColumnStorageKey = "";
44
52
  // Make ourselves an observable so that mobx will do caching of .collapseIds so
45
53
  // that it'll be a stable identity for GridTable to useMemo against.
46
- (0, mobx_1.makeAutoObservable)(this,
47
- // We only shallow observe rows so that:
48
- // a) we don't deeply/needlessly proxy-ize a large Apollo fragment cache, but
49
- // b) if rows changes, we re-run computeds like getSelectedRows that may need to see the
50
- // updated _contents_ of a given row, even if our other selected/matched row states don't change.
51
- // (as any b/c rows is private, so the mapped type doesn't see it)
52
- { rows: mobx_1.observable.shallow });
54
+ (0, mobx_1.makeAutoObservable)(this, {
55
+ // We only shallow observe rows so that:
56
+ // a) we don't deeply/needlessly proxy-ize a large Apollo fragment cache, but
57
+ // b) if rows changes, we re-run computeds like getSelectedRows that may need to see the
58
+ // updated _contents_ of a given row, even if our other selected/matched row states don't change.
59
+ // (as any b/c rows is private, so the mapped type doesn't see it)
60
+ rows: mobx_1.observable.shallow,
61
+ // Do not observe columns, expect this to be a non-reactive value for us to base our reactive values off of.
62
+ columns: false,
63
+ });
53
64
  // Whenever our `matchedRows` change (i.e. via filtering) then we need to re-derive header and parent rows' selected state.
54
65
  (0, mobx_1.reaction)(() => [...this.matchedRows.values()].sort(), () => {
55
66
  const map = new Map();
@@ -165,6 +176,33 @@ class TableState {
165
176
  // Finally replace our existing list of rows
166
177
  this.rows = rows;
167
178
  }
179
+ setColumns(columns) {
180
+ if (columns !== this.columns) {
181
+ this.columns = columns;
182
+ this.visibleColumnStorageKey = (0, change_case_1.camelCase)(columns.map((c) => c.id).join());
183
+ this.visibleColumns.replace(readOrSetLocalVisibleColumnState(columns, this.visibleColumnStorageKey));
184
+ const expandedColumnIds = columns.filter((c) => c.initExpanded).map((c) => c.id);
185
+ this.expandedColumns.replace(expandedColumnIds);
186
+ }
187
+ }
188
+ setVisibleColumns(ids) {
189
+ sessionStorage.setItem(this.visibleColumnStorageKey, JSON.stringify(ids));
190
+ this.visibleColumns.replace(ids);
191
+ }
192
+ get visibleColumnIds() {
193
+ return [...this.visibleColumns.values()];
194
+ }
195
+ get expandedColumnIds() {
196
+ return [...this.expandedColumns.values()];
197
+ }
198
+ toggleExpandedColumn(columnId) {
199
+ if (this.expandedColumns.has(columnId)) {
200
+ this.expandedColumns.delete(columnId);
201
+ }
202
+ else {
203
+ this.expandedColumns.add(columnId);
204
+ }
205
+ }
168
206
  setMatchedRows(rowIds) {
169
207
  // ObservableSet doesn't seem to do a `diff` inside `replace` before firing
170
208
  // observers/reactions that watch it, which can lead to render loops with the
@@ -319,6 +357,16 @@ function readLocalCollapseState(persistCollapse) {
319
357
  const collapsedGridRowIds = sessionStorage.getItem(persistCollapse);
320
358
  return collapsedGridRowIds ? JSON.parse(collapsedGridRowIds) : [];
321
359
  }
360
+ // Get the columns that are already in the visible state so we keep them toggled.
361
+ function readOrSetLocalVisibleColumnState(columns, storageKey) {
362
+ const storageValue = sessionStorage.getItem(storageKey);
363
+ if (storageValue) {
364
+ return JSON.parse(storageValue);
365
+ }
366
+ const visibleColumnIds = columns.filter((c) => c.initVisible || !c.canHide).map((c) => c.id);
367
+ sessionStorage.setItem(storageKey, JSON.stringify(visibleColumnIds));
368
+ return visibleColumnIds;
369
+ }
322
370
  /** Finds a row by id, and returns it + any parents. */
323
371
  function findRow(rows, id) {
324
372
  // This is technically an array of "maybe FoundRow"
@@ -5,7 +5,8 @@ const jsx_runtime_1 = require("@emotion/react/jsx-runtime");
5
5
  const CollapseToggle_1 = require("../components/CollapseToggle");
6
6
  const SelectToggle_1 = require("../components/SelectToggle");
7
7
  const types_1 = require("../types");
8
- const utils_1 = require("../../../utils");
8
+ const utils_1 = require("./utils");
9
+ const utils_2 = require("../../../utils");
9
10
  /** Provides default styling for a GridColumn representing a Date. */
10
11
  function column(columnDef) {
11
12
  return { ...columnDef };
@@ -44,10 +45,14 @@ function selectColumn(columnDef) {
44
45
  w: "48px",
45
46
  wrapAction: false,
46
47
  isAction: true,
48
+ expandColumns: undefined,
49
+ // Select Column should not display the select toggle for `expandableHeader` or `totals` row kinds
50
+ expandableHeader: utils_1.emptyCell,
51
+ totals: utils_1.emptyCell,
47
52
  // Use any of the user's per-row kind methods if they have them.
48
53
  ...columnDef,
49
54
  };
50
- return (0, utils_1.newMethodMissingProxy)(base, (key) => {
55
+ return (0, utils_2.newMethodMissingProxy)(base, (key) => {
51
56
  return (data, { row }) => ({
52
57
  content: (0, jsx_runtime_1.jsx)(SelectToggle_1.SelectToggle, { id: row.id, disabled: row.selectable === false }, void 0),
53
58
  });
@@ -71,9 +76,13 @@ function collapseColumn(columnDef) {
71
76
  w: "38px",
72
77
  wrapAction: false,
73
78
  isAction: true,
79
+ expandColumns: undefined,
80
+ // Collapse Column should not display the collapse toggle for `expandableHeader` or `totals` row kinds
81
+ expandableHeader: utils_1.emptyCell,
82
+ totals: utils_1.emptyCell,
74
83
  ...columnDef,
75
84
  };
76
- return (0, utils_1.newMethodMissingProxy)(base, (key) => {
85
+ return (0, utils_2.newMethodMissingProxy)(base, (key) => {
77
86
  return (data, { row, level }) => ({
78
87
  content: (0, jsx_runtime_1.jsx)(CollapseToggle_1.CollapseToggle, { row: row, compact: level > 0 }, void 0),
79
88
  });
@@ -153,8 +162,23 @@ exports.calcColumnSizes = calcColumnSizes;
153
162
  function assignDefaultColumnIds(columns) {
154
163
  // Note: we are not _always_ spreading the `c` property as we need to be able to return the whole proxy object that
155
164
  // exists as part of `selectColumn` and `collapseColumn`.
156
- return columns.map((c, idx) => { var _a; return (c.id ? c : { ...c, id: (_a = c.id) !== null && _a !== void 0 ? _a : (0, exports.generateColumnId)(idx) }); });
165
+ return columns.map((c, idx) => {
166
+ var _a;
167
+ const { expandColumns = [] } = c;
168
+ const expandColumnsWithId = expandColumns.map((ec, ecIdx) => {
169
+ var _a;
170
+ return ({
171
+ ...ec,
172
+ id: (_a = ec.id) !== null && _a !== void 0 ? _a : `${(0, exports.generateColumnId)(idx)}_${ecIdx}`,
173
+ // Defining this as undefined to make TS happy for now.
174
+ // If we do not explicitly set to `undefined`, TS thinks `expandColumns` could still be of type GridColumn<T> (not WithId).
175
+ // We only support a single level of expanding columns, so this is safe to do.
176
+ expandColumns: undefined,
177
+ });
178
+ });
179
+ return Object.assign(c, { id: (_a = c.id) !== null && _a !== void 0 ? _a : (0, exports.generateColumnId)(idx), expandColumns: expandColumnsWithId });
180
+ });
157
181
  }
158
182
  exports.assignDefaultColumnIds = assignDefaultColumnIds;
159
- const generateColumnId = (columnIndex) => `c${columnIndex}`;
183
+ const generateColumnId = (columnIndex) => `beamColumn_${columnIndex}`;
160
184
  exports.generateColumnId = generateColumnId;
@@ -19,6 +19,11 @@ export declare const simpleHeader: {
19
19
  id: string;
20
20
  data: {};
21
21
  };
22
+ export declare const simpleExpandableHeader: {
23
+ kind: "expandableHeader";
24
+ id: string;
25
+ data: {};
26
+ };
22
27
  /** Like `simpleRows` but for `SimpleHeaderAndData`. */
23
28
  export declare function simpleDataRows<R extends SimpleHeaderAndData<D>, D>(data?: Array<D & {
24
29
  id: string;
@@ -1,8 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.simpleDataRows = exports.simpleHeader = void 0;
3
+ exports.simpleDataRows = exports.simpleExpandableHeader = exports.simpleHeader = void 0;
4
4
  /** A const for a marker header row. */
5
5
  exports.simpleHeader = { kind: "header", id: "header", data: {} };
6
+ exports.simpleExpandableHeader = { kind: "expandableHeader", id: "expandableHeader", data: {} };
6
7
  /** Like `simpleRows` but for `SimpleHeaderAndData`. */
7
8
  function simpleDataRows(data = []) {
8
9
  // @ts-ignore Not sure why this doesn't type-check, something esoteric with the DiscriminateUnion type
@@ -1,7 +1,7 @@
1
1
  import { ReactNode } from "react";
2
2
  import { GridCellContent } from "../components/cell";
3
3
  import { GridDataRow } from "../components/Row";
4
- import { GridColumn, GridColumnWithId, Kinded } from "../types";
4
+ import { GridColumnWithId, Kinded } from "../types";
5
5
  import { SortOn, SortState } from "./TableState";
6
6
  export declare function sortRows<R extends Kinded>(columns: GridColumnWithId<R>[], rows: GridDataRow<R>[], sortState: SortState, caseSensitive: boolean): GridDataRow<R>[];
7
- export declare function ensureClientSideSortValueIsSortable(sortOn: SortOn, isHeader: boolean, column: GridColumn<any>, idx: number, maybeContent: ReactNode | GridCellContent): void;
7
+ export declare function ensureClientSideSortValueIsSortable(sortOn: SortOn, isHeader: boolean, column: GridColumnWithId<any>, idx: number, maybeContent: ReactNode | GridCellContent): void;
@@ -50,8 +50,8 @@ function getPin(pin) {
50
50
  return typeof pin === "string" ? pin : pin === null || pin === void 0 ? void 0 : pin.at;
51
51
  }
52
52
  function compare(column, a, b, invert, caseSensitive) {
53
- const v1 = sortValue((0, utils_1.applyRowFn)(column, a, {}, 0), caseSensitive);
54
- const v2 = sortValue((0, utils_1.applyRowFn)(column, b, {}, 0), caseSensitive);
53
+ const v1 = sortValue((0, utils_1.applyRowFn)(column, a, {}, 0, false), caseSensitive);
54
+ const v2 = sortValue((0, utils_1.applyRowFn)(column, b, {}, 0, false), caseSensitive);
55
55
  const v1e = v1 === null || v1 === undefined;
56
56
  const v2e = v2 === null || v2 === undefined;
57
57
  if ((v1e && v2e) || v1 === v2) {
@@ -91,10 +91,12 @@ function sortValue(value, caseSensitive) {
91
91
  return typeof maybeFn === "string" && !caseSensitive ? maybeFn.toLowerCase() : maybeFn;
92
92
  }
93
93
  function ensureClientSideSortValueIsSortable(sortOn, isHeader, column, idx, maybeContent) {
94
+ var _a;
94
95
  if (process.env.NODE_ENV !== "production" && !isHeader && sortOn === "client" && column.clientSideSort !== false) {
95
96
  const value = sortValue(maybeContent, false);
96
97
  if (!canClientSideSort(value)) {
97
- throw new Error(`Column ${idx} passed an unsortable value, use GridCellContent or clientSideSort=false`);
98
+ const columnIdentifier = !column.id.startsWith("beamColumn_") ? column.id : (_a = column.name) !== null && _a !== void 0 ? _a : idx;
99
+ throw new Error(`Column ${columnIdentifier} passed an unsortable value, use GridCellContent or clientSideSort=false`);
98
100
  }
99
101
  }
100
102
  }
@@ -6,10 +6,10 @@ import { GridStyle, RowStyle } from "../TableStyles";
6
6
  import { GridCellAlignment, GridColumnWithId, Kinded, RenderAs } from "../types";
7
7
  import { Properties } from "../../../Css";
8
8
  /** If a column def return just string text for a given row, apply some default styling. */
9
- export declare function toContent(maybeContent: ReactNode | GridCellContent, isHeader: boolean, canSortColumn: boolean, isClientSideSorting: boolean, style: GridStyle, as: RenderAs, alignment: GridCellAlignment, column: GridColumnWithId<any>): ReactNode;
9
+ export declare function toContent(maybeContent: ReactNode | GridCellContent, isHeader: boolean, canSortColumn: boolean, isClientSideSorting: boolean, style: GridStyle, as: RenderAs, alignment: GridCellAlignment, column: GridColumnWithId<any>, isExpandableHeader: boolean, isExpandable: boolean, minStickyLeftOffset: number): ReactNode;
10
10
  export declare function isGridCellContent(content: ReactNode | GridCellContent): content is GridCellContent;
11
11
  /** Return the content for a given column def applied to a given row. */
12
- export declare function applyRowFn<R extends Kinded>(column: GridColumnWithId<R>, row: GridDataRow<R>, api: GridTableApi<R>, level: number): ReactNode | GridCellContent;
12
+ export declare function applyRowFn<R extends Kinded>(column: GridColumnWithId<R>, row: GridDataRow<R>, api: GridTableApi<R>, level: number, expanded: boolean): ReactNode | GridCellContent;
13
13
  export declare const ASC: "ASC";
14
14
  export declare const DESC: "DESC";
15
15
  export declare const emptyCell: GridCellContent;
@@ -21,3 +21,13 @@ export declare function getJustification(column: GridColumnWithId<any>, maybeCon
21
21
  };
22
22
  export declare function maybeApplyFunction<T>(row: T, maybeFn: Properties | ((row: T) => Properties) | undefined): Properties | undefined;
23
23
  export declare function matchesFilter(maybeContent: ReactNode | GridCellContent, filter: string): boolean;
24
+ export declare const HEADER = "header";
25
+ export declare const TOTALS = "totals";
26
+ export declare const EXPANDABLE_HEADER = "expandableHeader";
27
+ export declare const reservedRowKinds: string[];
28
+ export declare const zIndices: {
29
+ stickyHeader: number;
30
+ stickyColumns: number;
31
+ expandableHeaderTitle: number;
32
+ expandableHeaderIcon: number;
33
+ };
@@ -1,12 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.matchesFilter = exports.maybeApplyFunction = exports.getJustification = exports.getAlignment = exports.getFirstOrLastCellCss = exports.getIndentationCss = exports.emptyCell = exports.DESC = exports.ASC = exports.applyRowFn = exports.isGridCellContent = exports.toContent = void 0;
3
+ exports.zIndices = exports.reservedRowKinds = exports.EXPANDABLE_HEADER = exports.TOTALS = exports.HEADER = exports.matchesFilter = exports.maybeApplyFunction = exports.getJustification = exports.getAlignment = exports.getFirstOrLastCellCss = exports.getIndentationCss = exports.emptyCell = exports.DESC = exports.ASC = exports.applyRowFn = exports.isGridCellContent = exports.toContent = void 0;
4
4
  const jsx_runtime_1 = require("@emotion/react/jsx-runtime");
5
+ const ExpandableHeader_1 = require("../components/ExpandableHeader");
5
6
  const SortHeader_1 = require("../components/SortHeader");
6
7
  const Css_1 = require("../../../Css");
7
8
  const getInteractiveElement_1 = require("../../../utils/getInteractiveElement");
8
9
  /** If a column def return just string text for a given row, apply some default styling. */
9
- function toContent(maybeContent, isHeader, canSortColumn, isClientSideSorting, style, as, alignment, column) {
10
+ function toContent(maybeContent, isHeader, canSortColumn, isClientSideSorting, style, as, alignment, column, isExpandableHeader, isExpandable, minStickyLeftOffset) {
10
11
  var _a, _b, _c;
11
12
  let content = isGridCellContent(maybeContent) ? maybeContent.content : maybeContent;
12
13
  if (typeof content === "function") {
@@ -34,6 +35,12 @@ function toContent(maybeContent, isHeader, canSortColumn, isClientSideSorting, s
34
35
  if (content && typeof content === "string" && isHeader && canSortColumn) {
35
36
  return ((0, jsx_runtime_1.jsx)(SortHeader_1.SortHeader, { content: content, iconOnLeft: alignment === "right", sortKey: (_b = column.serverSideSortKey) !== null && _b !== void 0 ? _b : column.id }, void 0));
36
37
  }
38
+ else if (content && typeof content === "string" && isExpandableHeader && isExpandable) {
39
+ return (0, jsx_runtime_1.jsx)(ExpandableHeader_1.ExpandableHeader, { title: content, column: column, minStickyLeftOffset: minStickyLeftOffset, as: as }, void 0);
40
+ }
41
+ else if (content && typeof content === "string" && isExpandableHeader) {
42
+ return (0, jsx_runtime_1.jsx)("span", Object.assign({ css: Css_1.Css.lineClamp2.$ }, { children: content }), void 0);
43
+ }
37
44
  else if (content && ((_c = style === null || style === void 0 ? void 0 : style.presentationSettings) === null || _c === void 0 ? void 0 : _c.wrap) === false && typeof content === "string") {
38
45
  // In order to truncate the text properly, then we need to wrap it in another element
39
46
  // as our cell element is a flex container, which don't allow for applying truncation styles directly on it.
@@ -55,12 +62,12 @@ function isContentEmpty(content) {
55
62
  return emptyValues.includes(content);
56
63
  }
57
64
  /** Return the content for a given column def applied to a given row. */
58
- function applyRowFn(column, row, api, level) {
65
+ function applyRowFn(column, row, api, level, expanded) {
59
66
  // Usually this is a function to apply against the row, but sometimes it's a hard-coded value, i.e. for headers
60
67
  const maybeContent = column[row.kind];
61
68
  if (typeof maybeContent === "function") {
62
69
  // Auto-destructure data
63
- return maybeContent(row["data"], { row: row, api, level });
70
+ return maybeContent(row["data"], { row: row, api, level, expanded });
64
71
  }
65
72
  else {
66
73
  return maybeContent;
@@ -146,3 +153,13 @@ function matchesFilter(maybeContent, filter) {
146
153
  return false;
147
154
  }
148
155
  exports.matchesFilter = matchesFilter;
156
+ exports.HEADER = "header";
157
+ exports.TOTALS = "totals";
158
+ exports.EXPANDABLE_HEADER = "expandableHeader";
159
+ exports.reservedRowKinds = [exports.HEADER, exports.TOTALS, exports.EXPANDABLE_HEADER];
160
+ exports.zIndices = {
161
+ stickyHeader: 4,
162
+ stickyColumns: 3,
163
+ expandableHeaderTitle: 2,
164
+ expandableHeaderIcon: 1,
165
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@homebound/beam",
3
- "version": "2.208.1",
3
+ "version": "2.209.0",
4
4
  "author": "Homebound",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -1,3 +0,0 @@
1
- import { Dispatch, SetStateAction } from "react";
2
- import { GridColumn, Kinded } from "../types";
3
- export declare function useColumns<R extends Kinded>(tableColumns: GridColumn<R>[], maybeStorageKey?: string): [GridColumn<R>[], Dispatch<SetStateAction<GridColumn<R>[]>>];
@@ -1,33 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.useColumns = void 0;
4
- const change_case_1 = require("change-case");
5
- const react_1 = require("react");
6
- const useSessionStorage_1 = require("../../../hooks/useSessionStorage");
7
- function useColumns(tableColumns, maybeStorageKey) {
8
- const { selectedColumns, hideColumns } = tableColumns.reduce((acc, column) => {
9
- // Only include options that can be hidden and have the `id` property defined.
10
- if (!column.id || column.id.length === 0) {
11
- console.warn("Column is missing 'id' property required by the Edit Columns button", column);
12
- return acc;
13
- }
14
- // Add hide-able columns
15
- if (column.canHide) {
16
- acc.hideColumns.push(column.id);
17
- }
18
- // Add selected columns
19
- if (!column.canHide || (column.canHide && column.initVisible)) {
20
- acc.selectedColumns.push(column.id);
21
- }
22
- return { ...acc };
23
- }, { selectedColumns: [], hideColumns: [] });
24
- const storageKey = maybeStorageKey !== null && maybeStorageKey !== void 0 ? maybeStorageKey : (0, change_case_1.camelCase)(hideColumns.map((c) => c).join(""));
25
- const [storageNames, setStorageNames] = (0, useSessionStorage_1.useSessionStorage)(storageKey, selectedColumns);
26
- const storageColumns = storageNames && storageNames.map((sc) => tableColumns.find((column) => column.id === sc));
27
- const [columns, setColumns] = (0, react_1.useState)(storageColumns);
28
- (0, react_1.useEffect)(() => {
29
- setStorageNames(columns.map((column) => column.id));
30
- }, [columns]);
31
- return [columns, setColumns];
32
- }
33
- exports.useColumns = useColumns;