@linzjs/step-ag-grid 14.9.3 → 14.10.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.
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@linzjs/step-ag-grid",
3
3
  "repository": "github:linz/step-ag-grid.git",
4
4
  "license": "MIT",
5
- "version": "14.9.3",
5
+ "version": "14.10.0",
6
6
  "keywords": [
7
7
  "aggrid",
8
8
  "ag-grid",
@@ -1,4 +1,4 @@
1
- import { CellClickedEvent, ColDef, ColumnResizedEvent, ModelUpdatedEvent } from "ag-grid-community";
1
+ import { CellClickedEvent, ColDef, ColGroupDef, ColumnResizedEvent, ModelUpdatedEvent } from "ag-grid-community";
2
2
  import { CellClassParams, EditableCallback, EditableCallbackParams } from "ag-grid-community/dist/lib/entities/colDef";
3
3
  import { GridOptions } from "ag-grid-community/dist/lib/entities/gridOptions";
4
4
  import { CellEvent, GridReadyEvent, SelectionChangedEvent } from "ag-grid-community/dist/lib/events";
@@ -153,11 +153,21 @@ export const Grid = ({
153
153
  needsAutoSize.current = false;
154
154
  }, [autoSizeColumns, params, sizeColumns, sizeColumnsToFit]);
155
155
 
156
+ const lastOwnerDocumentRef = useRef<Document>();
157
+
156
158
  /**
157
159
  * Auto-size windows that had deferred auto-size
158
160
  */
159
161
  useIntervalHook({
160
162
  callback: () => {
163
+ // Check if window has been popped out and needs resize
164
+ const currentDocument = gridDivRef.current?.ownerDocument;
165
+ if (currentDocument !== lastOwnerDocumentRef.current) {
166
+ lastOwnerDocumentRef.current = currentDocument;
167
+ if (currentDocument) {
168
+ needsAutoSize.current = true;
169
+ }
170
+ }
161
171
  if (needsAutoSize.current) {
162
172
  needsAutoSize.current = false;
163
173
  setInitialContentSize();
@@ -277,7 +287,7 @@ export const Grid = ({
277
287
  /**
278
288
  * Add selectable column to colDefs. Adjust column defs to block fit for auto sized columns.
279
289
  */
280
- const columnDefs = useMemo((): ColDef[] => {
290
+ const columnDefs = useMemo((): (ColDef | ColGroupDef)[] => {
281
291
  const adjustColDefs = params.columnDefs.map((colDef) => {
282
292
  const colDefEditable = colDef.editable;
283
293
  const editable = combineEditables(params.readOnly !== true, params.defaultColDef?.editable, colDefEditable);
@@ -471,15 +481,23 @@ export const Grid = ({
471
481
  * Once the grid has auto-sized we want to run fit to fit the grid in its container,
472
482
  * but we don't want the non-flex auto-sized columns to "fit" size, so suppressSizeToFit is set to true.
473
483
  */
474
- const columnDefsAdjusted = useMemo(
475
- () =>
476
- columnDefs.map((colDef) => ({
477
- ...colDef,
478
- suppressSizeToFit: (sizeColumns === "auto" || sizeColumns === "auto-skip-headers") && !colDef.flex,
479
- sortable: colDef.sortable && params.defaultColDef?.sortable !== false,
480
- })),
481
- [columnDefs, params.defaultColDef?.sortable, sizeColumns],
482
- );
484
+ const columnDefsAdjusted = useMemo(() => {
485
+ const adjustColDefOrGroup = (colDef: ColDef | ColGroupDef) =>
486
+ "children" in colDef ? adjustGroupColDef(colDef) : adjustColDef(colDef);
487
+
488
+ const adjustGroupColDef = (colDef: ColGroupDef): ColGroupDef => ({
489
+ ...colDef,
490
+ children: colDef.children.map((colDef) => adjustColDefOrGroup(colDef)),
491
+ });
492
+
493
+ const adjustColDef = (colDef: ColDef): ColDef => ({
494
+ ...colDef,
495
+ suppressSizeToFit: (sizeColumns === "auto" || sizeColumns === "auto-skip-headers") && !colDef.flex,
496
+ sortable: colDef.sortable && params.defaultColDef?.sortable !== false,
497
+ });
498
+
499
+ return columnDefs.map((colDef) => adjustColDefOrGroup(colDef));
500
+ }, [columnDefs, params.defaultColDef?.sortable, sizeColumns]);
483
501
 
484
502
  /**
485
503
  * Set of colIds that need auto-sizing.
@@ -0,0 +1,11 @@
1
+ import { ColDef } from "ag-grid-community";
2
+
3
+ export const GridCellFillerColId = "gridCellFiller";
4
+
5
+ export const isGridCellFiller = (col: ColDef) => col.colId === GridCellFillerColId;
6
+
7
+ export const GridCellFiller = (): ColDef => ({
8
+ colId: GridCellFillerColId,
9
+ headerName: "",
10
+ flex: 1,
11
+ });
@@ -16,17 +16,20 @@ export interface GridFilterColumnsToggleProps {
16
16
 
17
17
  export const GridFilterColumnsToggle = ({ saveState = true }: GridFilterColumnsToggleProps): JSX.Element => {
18
18
  const [loaded, setLoaded] = useState(false);
19
- const { getColumns, invisibleColumnIds, setInvisibleColumnIds } = useContext(GridContext);
19
+ const { getColumns, getColumnIds, invisibleColumnIds, setInvisibleColumnIds } = useContext(GridContext);
20
20
 
21
21
  const columnStorageKey = useMemo(
22
22
  () =>
23
- isEmpty(getColumns())
23
+ isEmpty(getColumnIds())
24
24
  ? null // Grid hasn't been initialised yet
25
- : "stepAgGrid_invisibleColumnIds_" +
26
- getColumns()
27
- .map((col) => col.colId || "")
28
- .join("_"),
29
- [getColumns],
25
+ : "stepAgGrid_invisibleColumnIds_" + getColumnIds().join("_"),
26
+ [getColumnIds],
27
+ );
28
+
29
+ // infer the invisible ids from colDefs
30
+ const resetColumns = useCallback(
31
+ () => setInvisibleColumnIds(getColumnIds("initialHide")),
32
+ [getColumnIds, setInvisibleColumnIds],
30
33
  );
31
34
 
32
35
  // Load state on start
@@ -35,20 +38,24 @@ export const GridFilterColumnsToggle = ({ saveState = true }: GridFilterColumnsT
35
38
  if (saveState) {
36
39
  try {
37
40
  const stored = window.localStorage.getItem(columnStorageKey);
38
- const invisibleIds = JSON.parse(stored ?? "[]");
39
- if (!Array.isArray(invisibleIds)) {
40
- console.error(`stored invisible ids not an array: ${stored}`);
41
- } else if (!invisibleIds.every((id) => typeof id === "string")) {
42
- console.error(`stored invisible ids not strings: ${stored}`);
41
+ if (!stored) {
42
+ resetColumns();
43
43
  } else {
44
- invisibleIds && setInvisibleColumnIds(invisibleIds);
44
+ const invisibleIds = JSON.parse(stored ?? "[]");
45
+ if (!Array.isArray(invisibleIds)) {
46
+ console.error(`stored invisible ids not an array: ${stored}`);
47
+ } else if (!invisibleIds.every((id) => typeof id === "string")) {
48
+ console.error(`stored invisible ids not strings: ${stored}`);
49
+ } else {
50
+ invisibleIds && setInvisibleColumnIds(invisibleIds);
51
+ }
45
52
  }
46
53
  } catch (ex) {
47
54
  console.error(ex);
48
55
  }
49
56
  setLoaded(true);
50
57
  }
51
- }, [columnStorageKey, loaded, saveState, setInvisibleColumnIds]);
58
+ }, [columnStorageKey, getColumns, loaded, resetColumns, saveState, setInvisibleColumnIds]);
52
59
 
53
60
  // Save state on column visibility change
54
61
  useEffect(() => {
@@ -60,7 +67,7 @@ export const GridFilterColumnsToggle = ({ saveState = true }: GridFilterColumnsT
60
67
 
61
68
  const toggleColumn = useCallback(
62
69
  (colId?: string) => {
63
- if (!colId) return;
70
+ if (!colId || !invisibleColumnIds) return;
64
71
  setInvisibleColumnIds(
65
72
  invisibleColumnIds.includes(colId)
66
73
  ? invisibleColumnIds.filter((id) => id !== colId)
@@ -70,10 +77,6 @@ export const GridFilterColumnsToggle = ({ saveState = true }: GridFilterColumnsT
70
77
  [invisibleColumnIds, setInvisibleColumnIds],
71
78
  );
72
79
 
73
- const resetColumns = () => {
74
- setInvisibleColumnIds([]);
75
- };
76
-
77
80
  const numericRegExp = /^\d+$/;
78
81
  const isNonManageableColumn = (col: ColDefT<GridBaseRow>) => {
79
82
  return col.lockVisible || col.colId == null || numericRegExp.test(col.colId);
@@ -87,40 +90,38 @@ export const GridFilterColumnsToggle = ({ saveState = true }: GridFilterColumnsT
87
90
  unmountOnClose={true}
88
91
  >
89
92
  <div className={"GridFilterColumnsToggle-container"}>
90
- {getColumns()
91
- .filter((col) => !!col.headerName)
92
- .map((col) => (
93
- <MenuItem
94
- key={col.colId}
95
- disabled={isNonManageableColumn(col)}
96
- onClick={(e: ClickEvent) => {
97
- // Global react-menu MenuItem handler handles tabs
98
- if (e.key !== "Tab") {
99
- e.keepOpen = true;
100
- if (e.key !== "Enter") {
101
- toggleColumn(col.colId);
102
- }
93
+ {getColumns("headerName").map((col) => (
94
+ <MenuItem
95
+ key={col.colId}
96
+ disabled={isNonManageableColumn(col)}
97
+ onClick={(e: ClickEvent) => {
98
+ // Global react-menu MenuItem handler handles tabs
99
+ if (e.key !== "Tab") {
100
+ e.keepOpen = true;
101
+ if (e.key !== "Enter") {
102
+ toggleColumn(col.colId);
103
103
  }
104
+ }
105
+ }}
106
+ >
107
+ <LuiCheckboxInput
108
+ isChecked={!!invisibleColumnIds && !invisibleColumnIds.includes(col.colId ?? "")}
109
+ value={`${col.colId}`}
110
+ label={col.headerName ?? ""}
111
+ isDisabled={isNonManageableColumn(col)}
112
+ inputProps={{
113
+ onClick: (e) => {
114
+ // Click is handled by MenuItem onClick so keyboard events work
115
+ e.preventDefault();
116
+ e.stopPropagation();
117
+ },
118
+ }}
119
+ onChange={() => {
120
+ /*Do nothing, change handled by menuItem*/
104
121
  }}
105
- >
106
- <LuiCheckboxInput
107
- isChecked={!invisibleColumnIds.includes(col.colId ?? "")}
108
- value={`${col.colId}`}
109
- label={col.headerName ?? ""}
110
- isDisabled={isNonManageableColumn(col)}
111
- inputProps={{
112
- onClick: (e) => {
113
- // Click is handled by MenuItem onClick so keyboard events work
114
- e.preventDefault();
115
- e.stopPropagation();
116
- },
117
- }}
118
- onChange={() => {
119
- /*Do nothing, change handled by menuItem*/
120
- }}
121
- />
122
- </MenuItem>
123
- ))}
122
+ />
123
+ </MenuItem>
124
+ ))}
124
125
  </div>
125
126
  <MenuDivider key={`$$divider_reset_columns`} />
126
127
  <MenuItem
@@ -0,0 +1,6 @@
1
+ import { ColDef } from "ag-grid-community";
2
+
3
+ import { isGridCellFiller } from "./GridCellFiller";
4
+
5
+ export const getColId = (colDef: ColDef): string => colDef.colId ?? "";
6
+ export const isFlexColumn = (colDef: ColDef): boolean => !!colDef.flex && !isGridCellFiller(colDef);
@@ -1,6 +1,7 @@
1
1
  export * from "./ComponentLoadingWrapper";
2
2
  export * from "./Grid";
3
3
  export * from "./GridCell";
4
+ export * from "./GridCellFiller";
4
5
  export * from "./GridCellMultiEditor";
5
6
  export * from "./GridCellMultiSelectClassRules";
6
7
  export * from "./gridFilter";
@@ -17,7 +17,10 @@ export type AutoSizeColumnsResult = { width: number } | null;
17
17
  export interface GridContextType<RowType extends GridBaseRow> {
18
18
  gridReady: boolean;
19
19
  getColDef: (colId?: string) => ColDef | undefined;
20
- getColumns: () => ColDefT<RowType>[];
20
+ getColumns: (
21
+ filter?: keyof ColDef | ((r: ColDef) => boolean | undefined | null | number | string),
22
+ ) => ColDefT<RowType>[];
23
+ getColumnIds: (filter?: keyof ColDef | ((r: ColDef) => boolean | undefined | null | number | string)) => string[];
21
24
  setApis: (gridApi: GridApi | undefined, columnApi: ColumnApi | undefined, dataTestId?: string) => void;
22
25
  prePopupOps: () => void;
23
26
  setQuickFilter: (quickFilter: string) => void;
@@ -55,7 +58,7 @@ export interface GridContextType<RowType extends GridBaseRow> {
55
58
  removeExternalFilter: (filter: GridFilterExternal<RowType>) => void;
56
59
  isExternalFilterPresent: () => boolean;
57
60
  doesExternalFilterPass: (node: RowNode) => boolean;
58
- invisibleColumnIds: string[];
61
+ invisibleColumnIds: string[] | undefined;
59
62
  setInvisibleColumnIds: (colIds: string[]) => void;
60
63
  downloadCsv: (csvExportParams?: CsvExportParams) => void;
61
64
  setOnCellEditingComplete: (callback: (() => void) | undefined) => void;
@@ -71,7 +74,11 @@ export const GridContext = createContext<GridContextType<any>>({
71
74
  console.error("no context provider for getColumns");
72
75
  return [];
73
76
  },
74
- invisibleColumnIds: [],
77
+ getColumnIds: () => {
78
+ console.error("no context provider for getColumnIds");
79
+ return [];
80
+ },
81
+ invisibleColumnIds: undefined,
75
82
  setInvisibleColumnIds: () => {
76
83
  console.error("no context provider for setInvisibleColumnIds");
77
84
  },
@@ -3,10 +3,12 @@ import { CellPosition } from "ag-grid-community/dist/lib/entities/cellPosition";
3
3
  import { ValueFormatterParams } from "ag-grid-community/dist/lib/entities/colDef";
4
4
  import { CsvExportParams, ProcessCellForExportParams } from "ag-grid-community/dist/lib/interfaces/exportParams";
5
5
  import debounce from "debounce-promise";
6
- import { compact, defer, delay, difference, isEmpty, last, remove, sortBy, sumBy } from "lodash-es";
6
+ import { compact, defer, delay, difference, filter, isEmpty, last, pull, remove, sortBy, sumBy } from "lodash-es";
7
7
  import { ReactElement, ReactNode, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
8
8
 
9
9
  import { ColDefT, GridBaseRow } from "../components";
10
+ import { GridCellFillerColId, isGridCellFiller } from "../components/GridCellFiller";
11
+ import { getColId, isFlexColumn } from "../components/gridUtil";
10
12
  import { isNotEmpty, sanitiseFileName, wait } from "../utils/util";
11
13
  import { AutoSizeColumnsProps, AutoSizeColumnsResult, GridContext, GridFilterExternal } from "./GridContext";
12
14
  import { GridUpdatingContext } from "./GridUpdatingContext";
@@ -26,13 +28,19 @@ export const GridContextProvider = <RowType extends GridBaseRow>(props: GridCont
26
28
  const [columnApi, setColumnApi] = useState<ColumnApi>();
27
29
  const [gridReady, setGridReady] = useState(false);
28
30
  const [quickFilter, setQuickFilter] = useState("");
29
- const [invisibleColumnIds, setInvisibleColumnIds] = useState<string[]>([]);
31
+ const [invisibleColumnIds, _setInvisibleColumnIds] = useState<string[]>();
30
32
  const testId = useRef<string | undefined>();
31
33
  const idsBeforeUpdate = useRef<number[]>([]);
32
34
  const prePopupFocusedCell = useRef<CellPosition>();
33
35
  const [externallySelectedItemsAreInSync, setExternallySelectedItemsAreInSync] = useState(false);
34
36
  const externalFilters = useRef<GridFilterExternal<RowType>[]>([]);
35
37
 
38
+ /**
39
+ * Make extra sure the GridCellFillerColId never gets added to invisibleColumnIds as it's dynamically determined
40
+ */
41
+ const setInvisibleColumnIds = (invisibleColumnIds: string[]) =>
42
+ _setInvisibleColumnIds(pull(invisibleColumnIds, GridCellFillerColId));
43
+
36
44
  /**
37
45
  * Set quick filter directly on grid, based on previously save quickFilter state.
38
46
  */
@@ -152,9 +160,7 @@ export const GridContextProvider = <RowType extends GridBaseRow>(props: GridCont
152
160
  const _getNewNodes = useCallback((): RowNode[] => {
153
161
  return gridApiOp(
154
162
  (gridApi) =>
155
- difference(_getAllRowIds(), idsBeforeUpdate.current)
156
- .map((rowId) => gridApi.getRowNode("" + rowId)) //
157
- .filter((r) => r) as RowNode[],
163
+ compact(difference(_getAllRowIds(), idsBeforeUpdate.current).map((rowId) => gridApi.getRowNode("" + rowId))),
158
164
  () => [],
159
165
  );
160
166
  }, [_getAllRowIds, gridApiOp]);
@@ -168,16 +174,30 @@ export const GridContextProvider = <RowType extends GridBaseRow>(props: GridCont
168
174
  const _rowIdsToNodes = useCallback(
169
175
  (rowIds: number[]): RowNode[] => {
170
176
  return gridApiOp(
171
- (gridApi) =>
172
- rowIds
173
- .map((rowId) => gridApi.getRowNode("" + rowId)) //
174
- .filter((r) => r) as RowNode[],
177
+ (gridApi) => compact(rowIds.map((rowId) => gridApi.getRowNode("" + rowId))),
175
178
  () => [] as RowNode[],
176
179
  );
177
180
  },
178
181
  [gridApiOp],
179
182
  );
180
183
 
184
+ /**
185
+ * Get ColDefs, with flattened ColGroupDefs
186
+ */
187
+ const getColumns = useCallback(
188
+ (
189
+ filterDef: keyof ColDef | ((r: ColDef) => boolean | undefined | null | number | string) = () => true,
190
+ ): ColDefT<RowType>[] =>
191
+ filter(columnApi?.getAllColumns()?.map((col) => col.getColDef()) ?? [], filterDef) as ColDefT<RowType>[],
192
+ [columnApi],
193
+ );
194
+
195
+ const getColumnIds = useCallback(
196
+ (filterDef: keyof ColDef | ((r: ColDef) => boolean | undefined | null | number | string) = () => true): string[] =>
197
+ compact(getColumns(filterDef).map(getColId)),
198
+ [getColumns],
199
+ );
200
+
181
201
  /**
182
202
  * Internal method for selecting and flashing rows.
183
203
  *
@@ -211,9 +231,9 @@ export const GridContextProvider = <RowType extends GridBaseRow>(props: GridCont
211
231
  const firstNode = rowsThatNeedSelecting[0];
212
232
  if (firstNode) {
213
233
  defer(() => gridApi.ensureNodeVisible(firstNode));
214
- const colDefs = gridApi.getColumnDefs();
215
- if (colDefs?.length) {
216
- const col = colDefs[0] as ColDef; // We don't support ColGroupDef
234
+ const colDefs = getColumns();
235
+ if (!isEmpty(colDefs)) {
236
+ const col = colDefs[0];
217
237
  const rowIndex = firstNode.rowIndex;
218
238
  if (rowIndex != null && col != null) {
219
239
  const colId = col.colId;
@@ -244,7 +264,7 @@ export const GridContextProvider = <RowType extends GridBaseRow>(props: GridCont
244
264
  }
245
265
  });
246
266
  },
247
- [_getNewNodes, _rowIdsToNodes, gridApiOp],
267
+ [_getNewNodes, _rowIdsToNodes, getColumns, gridApiOp],
248
268
  );
249
269
 
250
270
  const selectRowsById = useCallback(
@@ -536,9 +556,7 @@ export const GridContextProvider = <RowType extends GridBaseRow>(props: GridCont
536
556
 
537
557
  const redrawRows = useCallback(
538
558
  (rowNodes?: RowNode[]) => {
539
- gridApiOp((gridApi) => {
540
- gridApi.redrawRows(rowNodes ? { rowNodes } : undefined);
541
- });
559
+ gridApiOp((gridApi) => gridApi.redrawRows(rowNodes ? { rowNodes } : undefined));
542
560
  },
543
561
  [gridApiOp],
544
562
  );
@@ -574,33 +592,39 @@ export const GridContextProvider = <RowType extends GridBaseRow>(props: GridCont
574
592
  onFilterChanged().then();
575
593
  };
576
594
 
577
- const isExternalFilterPresent = (): boolean => externalFilters.current.length > 0;
595
+ const isExternalFilterPresent = (): boolean => !isEmpty(externalFilters.current);
578
596
 
579
- const doesExternalFilterPass = (node: RowNode): boolean => {
580
- return externalFilters.current.every((filter) => filter(node.data, node));
581
- };
597
+ const doesExternalFilterPass = (node: RowNode): boolean =>
598
+ externalFilters.current.every((filter) => filter(node.data, node));
582
599
 
583
600
  const getColDef = useCallback(
584
601
  (colId?: string): ColDef | undefined => (!!colId && gridApi?.getColumnDef(colId)) || undefined,
585
602
  [gridApi],
586
603
  );
587
604
 
588
- const getColumns: () => ColDefT<RowType>[] = useCallback(() => gridApi?.getColumnDefs() ?? [], [gridApi]);
589
-
605
+ /**
606
+ * Apply column visibility
607
+ */
590
608
  useEffect(() => {
591
- if (columnApi) {
592
- // show all columns that aren't invisible
593
- columnApi.setColumnsVisible(
594
- compact(
595
- getColumns()
596
- .filter((col) => !col.lockVisible && col.colId && !invisibleColumnIds.includes(col.colId))
597
- .map((col) => col.colId),
598
- ),
599
- true,
600
- );
601
- // hide all invisible columns
602
- columnApi.setColumnsVisible(invisibleColumnIds, false);
609
+ if (!columnApi || !invisibleColumnIds) return;
610
+
611
+ // show all columns that aren't invisible
612
+ const newVisibleColumns = getColumns(
613
+ (col) => !col.lockVisible && col.colId && !invisibleColumnIds.includes(col.colId) && !isGridCellFiller(col),
614
+ );
615
+ // If there's no flex column showing add the filler column if defined
616
+ const visibleColumnsContainsAFlex = newVisibleColumns.some(isFlexColumn);
617
+ if (!visibleColumnsContainsAFlex) {
618
+ const fillerColumn = getColumns(isGridCellFiller)[0];
619
+ fillerColumn && newVisibleColumns.push(fillerColumn);
603
620
  }
621
+ columnApi.setColumnsVisible(compact(newVisibleColumns.map(getColId)), true);
622
+
623
+ // Hide the filler column if there's already a flex column
624
+ const invisibleColumnIdsWithOptionalFiller = visibleColumnsContainsAFlex
625
+ ? [...invisibleColumnIds, GridCellFillerColId]
626
+ : invisibleColumnIds;
627
+ columnApi.setColumnsVisible(invisibleColumnIdsWithOptionalFiller, false);
604
628
  }, [invisibleColumnIds, columnApi, getColumns]);
605
629
 
606
630
  /**
@@ -614,7 +638,10 @@ export const GridContextProvider = <RowType extends GridBaseRow>(props: GridCont
614
638
 
615
639
  const columnKeys = columnApi
616
640
  ?.getColumnState()
617
- .filter((cs) => !cs.hide && gridApi.getColumnDef(cs.colId)?.headerComponentParams?.exportable !== false)
641
+ .filter((cs) => {
642
+ const colDef = gridApi.getColumnDef(cs.colId);
643
+ return !cs.hide && colDef && !isGridCellFiller(colDef) && colDef.headerComponentParams?.exportable !== false;
644
+ })
618
645
  .map((cs) => cs.colId);
619
646
  gridApi.exportDataAsCsv({
620
647
  columnKeys,
@@ -631,6 +658,7 @@ export const GridContextProvider = <RowType extends GridBaseRow>(props: GridCont
631
658
  value={{
632
659
  getColDef,
633
660
  getColumns,
661
+ getColumnIds,
634
662
  invisibleColumnIds,
635
663
  setInvisibleColumnIds,
636
664
  gridReady,
@@ -25,6 +25,7 @@ import {
25
25
  } from "../..";
26
26
  import { GridFilterColumnsToggle } from "../../components";
27
27
  import { GridFilterDownloadCsvButton } from "../../components";
28
+ import { GridCellFiller } from "../../components/GridCellFiller";
28
29
  import "../../styles/GridTheme.scss";
29
30
  import "../../styles/index.scss";
30
31
 
@@ -55,6 +56,7 @@ interface ITestRow {
55
56
  id: number;
56
57
  position: string;
57
58
  age: number;
59
+ height: number;
58
60
  desc: string;
59
61
  dd: string;
60
62
  }
@@ -76,15 +78,27 @@ const GridReadOnlyTemplate: ComponentStory<typeof Grid> = (props: GridProps) =>
76
78
  info: (props) => props.value === "Developer" && "Developers are awesome",
77
79
  },
78
80
  }),
79
- GridCell({
80
- field: "age",
81
- headerName: "Age",
82
- }),
81
+ {
82
+ headerName: "Metrics",
83
+ marryChildren: true,
84
+ children: [
85
+ GridCell({
86
+ field: "age",
87
+ headerName: "Age",
88
+ }),
89
+ GridCell({
90
+ field: "height",
91
+ headerName: "Height",
92
+ }),
93
+ ],
94
+ },
83
95
  GridCell({
84
96
  field: "desc",
85
97
  headerName: "Description",
86
98
  flex: 1,
99
+ initialHide: true,
87
100
  }),
101
+ GridCellFiller(),
88
102
  GridPopoverMessage(
89
103
  {
90
104
  headerName: "Popout message",
@@ -187,9 +201,9 @@ const GridReadOnlyTemplate: ComponentStory<typeof Grid> = (props: GridProps) =>
187
201
  );
188
202
 
189
203
  const [rowData] = useState([
190
- { id: 1000, position: "Tester", age: 30, desc: "Tests application", dd: "1" },
191
- { id: 1001, position: "Developer", age: 12, desc: "Develops application", dd: "2" },
192
- { id: 1002, position: "Manager", age: 65, desc: "Manages", dd: "3" },
204
+ { id: 1000, position: "Tester", age: 30, height: `6'4"`, desc: "Tests application", dd: "1" },
205
+ { id: 1001, position: "Developer", age: 12, height: `5'3"`, desc: "Develops application", dd: "2" },
206
+ { id: 1002, position: "Manager", age: 65, height: `5'9"`, desc: "Manages", dd: "3" },
193
207
  ]);
194
208
 
195
209
  return (