@linzjs/step-ag-grid 21.0.0 → 21.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.css CHANGED
@@ -337,10 +337,9 @@
337
337
  flex: 1;
338
338
  }
339
339
 
340
- .Grid-sortIsStale span.ag-icon.ag-icon-desc::after {
341
- content: "*";
342
- }
343
- .Grid-sortIsStale span.ag-icon.ag-icon-asc::after {
340
+ .Grid-sortIsStale span.ag-sort-indicator-icon::before {
341
+ margin-left: -6px;
342
+ position: absolute;
344
343
  content: "*";
345
344
  }
346
345
 
@@ -7,5 +7,5 @@ interface PostSortRowsHookProps {
7
7
  * Then applies this sort until next sort column change.
8
8
  * Handles stale sort, when you edit a row but don't want to re-sort.
9
9
  */
10
- export declare const usePostSortRowsHook: ({ setStaleGrid }: PostSortRowsHookProps) => ({ api, columnApi, nodes }: PostSortRowsParams) => void;
10
+ export declare const usePostSortRowsHook: ({ setStaleGrid }: PostSortRowsHookProps) => ({ api, nodes }: PostSortRowsParams) => void;
11
11
  export {};
@@ -1,5 +1,5 @@
1
1
  /// <reference types="react" />
2
- import { ColDef, ColumnApi, GridApi, IRowNode } from "ag-grid-community";
2
+ import { ColDef, GridApi, IRowNode } from "ag-grid-community";
3
3
  import { CsvExportParams } from "ag-grid-community";
4
4
  import { ColDefT, GridBaseRow } from "../components";
5
5
  export type GridFilterExternal<TData extends GridBaseRow> = (data: TData, rowNode: IRowNode) => boolean;
@@ -18,7 +18,7 @@ export interface GridContextType<TData extends GridBaseRow> {
18
18
  getColDef: (colId?: string) => ColDef | undefined;
19
19
  getColumns: (filter?: keyof ColDef | ((r: ColDef) => boolean | undefined | null | number | string)) => ColDefT<TData, any>[];
20
20
  getColumnIds: (filter?: keyof ColDef | ((r: ColDef) => boolean | undefined | null | number | string)) => string[];
21
- setApis: (gridApi: GridApi | undefined, columnApi: ColumnApi | undefined, dataTestId?: string) => void;
21
+ setApis: (gridApi: GridApi | undefined, dataTestId?: string) => void;
22
22
  prePopupOps: () => void;
23
23
  postPopupOps: () => void;
24
24
  setQuickFilter: (quickFilter: string) => void;
@@ -302,15 +302,15 @@ const usePostSortRowsHook = ({ setStaleGrid }) => {
302
302
  // As a sort on a stale row should just resort, not change sort direction
303
303
  const previousColSort = React.useRef([]);
304
304
  const previousQuickFilter = React.useRef("");
305
- return React.useCallback(({ api, columnApi, nodes }) => {
305
+ return React.useCallback(({ api, nodes }) => {
306
306
  // Grid is destroyed
307
- if (!api || !columnApi)
307
+ if (!api)
308
308
  return;
309
309
  const previousRowSortIndex = previousRowSortIndexRef.current;
310
310
  const hashNode = (node) => {
311
311
  return node ? JSON.stringify(node.data) : "";
312
312
  };
313
- const copyCurrentSortSettings = () => columnApi.getColumnState().map((row) => ({ colId: row.colId, sort: row.sort, sortIndex: row.sortIndex }));
313
+ const copyCurrentSortSettings = () => api.getColumnState().map((row) => ({ colId: row.colId, sort: row.sort, sortIndex: row.sortIndex }));
314
314
  const backupSortOrder = () => {
315
315
  for (const x in previousRowSortIndex)
316
316
  delete previousRowSortIndex[x];
@@ -319,7 +319,7 @@ const usePostSortRowsHook = ({ setStaleGrid }) => {
319
319
  // Check if column is the first sorted column. Note: column is preconfigured to sort its sortIndex is null not 1
320
320
  const isFirstSortColumn = (row) => row.sort && [0, null].includes(row.sortIndex ?? null);
321
321
  const isSameColumnAndDifferentSort = (col1, col2) => col1 && col2 && col1.colId === col2.colId && col1.sort != col2.sort;
322
- const restorePreviousSortColumnState = () => columnApi.applyColumnState({ state: previousColSort.current });
322
+ const restorePreviousSortColumnState = () => api.applyColumnState({ state: previousColSort.current });
323
323
  const sortNodesByPreviousSort = () => {
324
324
  nodes.sort((a, b) => (previousRowSortIndex[`${a.data.id}`]?.index ?? Number.MAX_SAFE_INTEGER) -
325
325
  (previousRowSortIndex[`${b.data.id}`]?.index ?? Number.MAX_SAFE_INTEGER));
@@ -397,7 +397,7 @@ const usePostSortRowsHook = ({ setStaleGrid }) => {
397
397
  wasStale = true;
398
398
  }
399
399
  else if (changedRowCount === 2 && newRowCount === 0) {
400
- // This must be a swap rows
400
+ // This must be a swap rows (sometimes it's not, needs further attention)
401
401
  backupSortOrder();
402
402
  wasStale = false;
403
403
  }
@@ -445,13 +445,15 @@ const GridHeaderSelect = ({ api }) => {
445
445
  // This is used to force an update on selection change
446
446
  const [updateCounter, setUpdateCounter] = React.useState(0);
447
447
  const selectedNodeCount = api.getSelectedRows().length;
448
- const clickHandler = React.useCallback(() => {
449
- setUpdateCounter(updateCounter + 1);
450
- }, [updateCounter]);
451
448
  React.useEffect(() => {
449
+ const clickHandler = () => {
450
+ setUpdateCounter(updateCounter + 1);
451
+ };
452
452
  api.addEventListener("selectionChanged", clickHandler);
453
- return () => api.removeEventListener("selectionChanged", clickHandler);
454
- }, [api, clickHandler]);
453
+ return () => {
454
+ !api.isDestroyed() && api.removeEventListener("selectionChanged", clickHandler);
455
+ };
456
+ }, [api, updateCounter]);
455
457
  const handleMultiSelect = () => {
456
458
  if (selectedNodeCount == 0) {
457
459
  api.selectAllFiltered();
@@ -460,7 +462,7 @@ const GridHeaderSelect = ({ api }) => {
460
462
  api.deselectAll();
461
463
  }
462
464
  };
463
- const totalNodeCount = api.getModel().getRowCount();
465
+ const totalNodeCount = api.getDisplayedRowCount();
464
466
  const partialSelect = selectedNodeCount != 0 && selectedNodeCount != totalNodeCount;
465
467
  const allSelected = selectedNodeCount != 0 && selectedNodeCount == totalNodeCount;
466
468
  return (jsxRuntime.jsx("div", { className: clsx("ag-wrapper ag-input-wrapper ag-checkbox-input-wrapper", partialSelect && "ag-indeterminate", allSelected && "ag-checked"), onClick: handleMultiSelect, children: jsxRuntime.jsx("input", { type: "checkbox", className: "ag-checkbox-input-wrapper", onChange: () => {
@@ -2362,16 +2364,20 @@ const Grid = ({ "data-testid": dataTestId, rowSelection = "multiple", suppressCo
2362
2364
  const skipHeader = sizeColumns === "auto-skip-headers" && gridRendered === "rows-visible";
2363
2365
  if (sizeColumns === "auto" || skipHeader) {
2364
2366
  const result = autoSizeColumns({ skipHeader, userSizedColIds: userSizedColIds.current, includeFlex: true });
2367
+ if (!result) {
2368
+ needsAutoSize.current = true;
2369
+ return;
2370
+ }
2365
2371
  if (gridRendered === "empty") {
2366
2372
  if (!hasSetContentSizeEmpty.current && result && !hasSetContentSize.current) {
2367
2373
  hasSetContentSizeEmpty.current = true;
2368
- params.onContentSize && params.onContentSize(result);
2374
+ params.onContentSize?.(result);
2369
2375
  }
2370
2376
  }
2371
2377
  else if (gridRendered === "rows-visible") {
2372
2378
  if (result && !hasSetContentSize.current) {
2373
2379
  hasSetContentSize.current = true;
2374
- params.onContentSize && params.onContentSize(result);
2380
+ params.onContentSize?.(result);
2375
2381
  }
2376
2382
  }
2377
2383
  else {
@@ -2398,7 +2404,7 @@ const Grid = ({ "data-testid": dataTestId, rowSelection = "multiple", suppressCo
2398
2404
  needsAutoSize.current = true;
2399
2405
  }
2400
2406
  }
2401
- if (needsAutoSize.current) {
2407
+ if (needsAutoSize.current || (!hasSetContentSize.current && sizeColumns === "auto")) {
2402
2408
  needsAutoSize.current = false;
2403
2409
  setInitialContentSize();
2404
2410
  }
@@ -2558,7 +2564,7 @@ const Grid = ({ "data-testid": dataTestId, rowSelection = "multiple", suppressCo
2558
2564
  * When grid is ready set the apis to the grid context and sync selected items to grid.
2559
2565
  */
2560
2566
  const onGridReady = React.useCallback((event) => {
2561
- setApis(event.api, event.columnApi, dataTestId);
2567
+ setApis(event.api, dataTestId);
2562
2568
  event.api.showNoRowsOverlay();
2563
2569
  synchroniseExternallySelectedItemsToGrid();
2564
2570
  }, [dataTestId, setApis, synchroniseExternallySelectedItemsToGrid]);
@@ -2779,7 +2785,7 @@ const Grid = ({ "data-testid": dataTestId, rowSelection = "multiple", suppressCo
2779
2785
  }
2780
2786
  const moved = event.node.data;
2781
2787
  const target = event.overNode?.data;
2782
- moved.id != target.id && //moved over a different row
2788
+ moved.id !== target?.id && //moved over a different row
2783
2789
  event.node.rowIndex != targetIndex && //moved to a different index
2784
2790
  params.onRowDragEnd &&
2785
2791
  (await params.onRowDragEnd(moved, target, targetIndex));
@@ -2789,7 +2795,7 @@ const Grid = ({ "data-testid": dataTestId, rowSelection = "multiple", suppressCo
2789
2795
  // This is setting a ref in the GridContext so won't be triggering an update loop
2790
2796
  setOnCellEditingComplete(params.onCellEditingComplete);
2791
2797
  const headerRowCount = columnDefs.some((c) => c.children) ? 2 : 1;
2792
- return (jsxRuntime.jsxs("div", { "data-testid": dataTestId, className: clsx("Grid-container", theme, "theme-specific", staleGrid && "Grid-sortIsStale", gridReady && rowData && autoSized && "Grid-ready"), children: [gridContextMenu.component, jsxRuntime.jsx("div", { style: { flex: 1 }, ref: gridDivRef, children: jsxRuntime.jsx(agGridReact.AgGridReact, { rowHeight: rowHeight, animateRows: params.animateRows ?? false, rowClassRules: params.rowClassRules, getRowId: (params) => `${params.data.id}`, suppressRowClickSelection: true, rowSelection: rowSelection, suppressBrowserResizeObserver: true, onGridSizeChanged: onGridSizeChanged, suppressColumnVirtualisation: suppressColumnVirtualization, suppressClickEdit: true, onColumnVisible: () => {
2798
+ return (jsxRuntime.jsxs("div", { "data-testid": dataTestId, className: clsx("Grid-container", theme, "theme-specific", staleGrid && "Grid-sortIsStale", gridReady && rowData && autoSized && "Grid-ready"), children: [gridContextMenu.component, jsxRuntime.jsx("div", { style: { flex: 1 }, ref: gridDivRef, children: jsxRuntime.jsx(agGridReact.AgGridReact, { reactiveCustomComponents: true, rowHeight: rowHeight, animateRows: params.animateRows ?? false, rowClassRules: params.rowClassRules, getRowId: (params) => `${params.data.id}`, suppressRowClickSelection: true, rowSelection: rowSelection, suppressBrowserResizeObserver: true, onGridSizeChanged: onGridSizeChanged, suppressColumnVirtualisation: suppressColumnVirtualization, suppressClickEdit: true, onColumnVisible: () => {
2793
2799
  setInitialContentSize();
2794
2800
  }, onRowDataUpdated: onRowDataChanged, onCellKeyDown: onCellKeyPress, onCellClicked: onCellClicked, onCellDoubleClicked: onCellDoubleClick, onCellEditingStarted: refreshSelectedRows, domLayout: params.domLayout, onColumnResized: onColumnResized, defaultColDef: { minWidth: 48, ...lodashEs.omit(params.defaultColDef, ["editable"]) }, columnDefs: columnDefsAdjusted, rowData: rowData, noRowsOverlayComponent: (event) => {
2795
2801
  let rowCount = 0;
@@ -4553,7 +4559,6 @@ const isFlexColumn = (colDef) => !!colDef.flex && !isGridCellFiller(colDef);
4553
4559
  const GridContextProvider = (props) => {
4554
4560
  const { modifyUpdating, checkUpdating } = React.useContext(GridUpdatingContext);
4555
4561
  const [gridApi, setGridApi] = React.useState();
4556
- const [columnApi, setColumnApi] = React.useState();
4557
4562
  const [gridReady, setGridReady] = React.useState(false);
4558
4563
  const [quickFilter, setQuickFilter] = React.useState("");
4559
4564
  const [invisibleColumnIds, _setInvisibleColumnIds] = React.useState();
@@ -4570,7 +4575,7 @@ const GridContextProvider = (props) => {
4570
4575
  * Set quick filter directly on grid, based on previously save quickFilter state.
4571
4576
  */
4572
4577
  React.useEffect(() => {
4573
- gridApi?.setQuickFilter(quickFilter);
4578
+ gridApi?.setGridOption("quickFilterText", quickFilter);
4574
4579
  }, [gridApi, quickFilter]);
4575
4580
  /**
4576
4581
  * Wraps things that require gridApi in common handling, for when gridApi not present.
@@ -4616,21 +4621,19 @@ const GridContextProvider = (props) => {
4616
4621
  /**
4617
4622
  * Set the grid api when the grid is ready.
4618
4623
  */
4619
- const setApis = React.useCallback((gridApi, columnApi, dataTestId) => {
4624
+ const setApis = React.useCallback((gridApi, dataTestId) => {
4620
4625
  testId.current = dataTestId;
4621
4626
  setGridApi(gridApi);
4622
- setColumnApi(columnApi);
4623
- gridApi?.setQuickFilter(quickFilter);
4627
+ gridApi?.setGridOption("quickFilterText", quickFilter);
4624
4628
  setGridReady(!!gridApi);
4625
4629
  }, [quickFilter]);
4626
4630
  /**
4627
4631
  * Used to check if it's OK to autosize.
4628
4632
  */
4629
4633
  const gridRenderState = React.useCallback(() => {
4630
- // Even though getModel can't be null, sometimes it is
4631
- if (!gridApi || !gridApi.getModel())
4634
+ if (!gridApi)
4632
4635
  return null;
4633
- if (!gridApi.getModel().isRowsToRender())
4636
+ if (!gridApi.getDisplayedRowCount())
4634
4637
  return "empty";
4635
4638
  if (!lodashEs.isEmpty(gridApi.getRenderedNodes()))
4636
4639
  return "rows-visible";
@@ -4703,7 +4706,7 @@ const GridContextProvider = (props) => {
4703
4706
  /**
4704
4707
  * Get ColDefs, with flattened ColGroupDefs
4705
4708
  */
4706
- const getColumns = React.useCallback((filterDef = () => true) => lodashEs.filter(columnApi?.getColumns()?.map((col) => col.getColDef()) ?? [], filterDef), [columnApi]);
4709
+ const getColumns = React.useCallback((filterDef = () => true) => lodashEs.filter(gridApi?.getColumns()?.map((col) => col.getColDef()) ?? [], filterDef), [gridApi]);
4707
4710
  const getColumnIds = React.useCallback((filterDef = () => true) => lodashEs.compact(getColumns(filterDef).map(getColId)), [getColumns]);
4708
4711
  /**
4709
4712
  * Internal method for selecting and flashing rows.
@@ -4826,22 +4829,22 @@ const GridContextProvider = (props) => {
4826
4829
  * Resize columns to fit container
4827
4830
  */
4828
4831
  const autoSizeColumns = React.useCallback(({ skipHeader, colIds, userSizedColIds, includeFlex } = {}) => {
4829
- if (!columnApi)
4832
+ if (!gridApi || !gridApi.getColumnState())
4830
4833
  return null;
4831
4834
  const colIdsSet = colIds instanceof Set ? colIds : new Set(colIds);
4832
- const colsToResize = columnApi.getColumnState().filter((colState) => {
4835
+ const colsToResize = gridApi.getColumnState()?.filter?.((colState) => {
4833
4836
  const colId = colState.colId;
4834
4837
  return ((lodashEs.isEmpty(colIdsSet) || colIdsSet.has(colId)) &&
4835
4838
  !userSizedColIds?.has(colId) &&
4836
4839
  (includeFlex || !colState.flex));
4837
4840
  });
4838
4841
  if (!lodashEs.isEmpty(colsToResize)) {
4839
- columnApi.autoSizeColumns(colsToResize.map((colState) => colState.colId), skipHeader);
4842
+ gridApi.autoSizeColumns(colsToResize.map((colState) => colState.colId), skipHeader);
4840
4843
  }
4841
4844
  return {
4842
- width: lodashEs.sumBy(columnApi.getColumnState().filter((col) => !col.hide), "width"),
4845
+ width: lodashEs.sumBy(gridApi.getColumnState().filter((col) => !col.hide), "width"),
4843
4846
  };
4844
- }, [columnApi]);
4847
+ }, [gridApi]);
4845
4848
  /**
4846
4849
  * Resize columns to fit container
4847
4850
  */
@@ -4890,7 +4893,7 @@ const GridContextProvider = (props) => {
4890
4893
  */
4891
4894
  const cancelEdit = React.useCallback(() => {
4892
4895
  stopEditing();
4893
- cellEditingCompleteCallbackRef.current && cellEditingCompleteCallbackRef.current();
4896
+ cellEditingCompleteCallbackRef.current?.();
4894
4897
  }, [stopEditing]);
4895
4898
  const cellEditingCompleteCallbackRef = React.useRef();
4896
4899
  const setOnCellEditingComplete = React.useCallback((cellEditingCompleteCallback) => {
@@ -4962,7 +4965,7 @@ const GridContextProvider = (props) => {
4962
4965
  }
4963
4966
  else {
4964
4967
  // Don't set saving if ok as the form has already closed
4965
- setSaving && setSaving(false);
4968
+ setSaving?.(false);
4966
4969
  }
4967
4970
  // Only focus next cell if user hasn't already manually changed focus
4968
4971
  const postPopupFocusedCell = gridApi.getFocusedCell();
@@ -5019,7 +5022,7 @@ const GridContextProvider = (props) => {
5019
5022
  * Apply column visibility
5020
5023
  */
5021
5024
  React.useEffect(() => {
5022
- if (!columnApi || !invisibleColumnIds)
5025
+ if (!gridApi || !invisibleColumnIds)
5023
5026
  return;
5024
5027
  // show all columns that aren't invisible
5025
5028
  const newVisibleColumns = getColumns((col) => !col.lockVisible && col.colId && !invisibleColumnIds.includes(col.colId) && !isGridCellFiller(col));
@@ -5029,22 +5032,22 @@ const GridContextProvider = (props) => {
5029
5032
  const fillerColumn = getColumns(isGridCellFiller)[0];
5030
5033
  fillerColumn && newVisibleColumns.push(fillerColumn);
5031
5034
  }
5032
- columnApi.setColumnsVisible(lodashEs.compact(newVisibleColumns.map(getColId)), true);
5035
+ gridApi.setColumnsVisible(lodashEs.compact(newVisibleColumns.map(getColId)), true);
5033
5036
  // Hide the filler column if there's already a flex column
5034
5037
  const invisibleColumnIdsWithOptionalFiller = visibleColumnsContainsAFlex
5035
5038
  ? [...invisibleColumnIds, GridCellFillerColId]
5036
5039
  : invisibleColumnIds;
5037
- columnApi.setColumnsVisible(invisibleColumnIdsWithOptionalFiller, false);
5038
- }, [invisibleColumnIds, columnApi, getColumns]);
5040
+ gridApi.setColumnsVisible(invisibleColumnIdsWithOptionalFiller, false);
5041
+ }, [invisibleColumnIds, getColumns, gridApi]);
5039
5042
  /**
5040
5043
  * Download visible columns as a CSV
5041
5044
  */
5042
5045
  const downloadCsv = React.useCallback((csvExportParams) => {
5043
- if (!gridApi || !columnApi)
5046
+ if (!gridApi)
5044
5047
  return;
5045
5048
  const fileName = csvExportParams?.fileName && sanitiseFileName(fnOrVar(csvExportParams.fileName));
5046
- const columnKeys = columnApi
5047
- ?.getColumnState()
5049
+ const columnKeys = gridApi
5050
+ .getColumnState()
5048
5051
  .filter((cs) => {
5049
5052
  const colDef = gridApi.getColumnDef(cs.colId);
5050
5053
  return !cs.hide && colDef && !isGridCellFiller(colDef) && colDef.headerComponentParams?.exportable !== false;
@@ -5056,7 +5059,7 @@ const GridContextProvider = (props) => {
5056
5059
  ...csvExportParams,
5057
5060
  fileName,
5058
5061
  });
5059
- }, [columnApi, gridApi]);
5062
+ }, [gridApi]);
5060
5063
  return (jsxRuntime.jsx(GridContext.Provider, { value: {
5061
5064
  gridRenderState,
5062
5065
  getColDef,
@@ -5138,7 +5141,7 @@ const downloadCsvUseValueFormattersProcessCellCallback = (params) => {
5138
5141
  console.error(`downloadCsv: String type (registered) value formatters are unsupported in downloadCsv, colId: ${colDef.colId}`);
5139
5142
  return encodeToString(params.value);
5140
5143
  }
5141
- const result = valueFormatter({ ...params, data: params.node?.data, colDef });
5144
+ const result = valueFormatter({ ...params, data: params.node?.data, colDef, node: null });
5142
5145
  // type may not be string due to casting, leave the type check in
5143
5146
  if (params.value != null && typeof result !== "string") {
5144
5147
  console.error(`downloadCsv: valueFormatter is returning non string values, colDef:", colId: ${colDef.colId}`);