@linzjs/step-ag-grid 21.0.0 → 21.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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": "21.0.0",
5
+ "version": "21.0.1",
6
6
  "keywords": [
7
7
  "aggrid",
8
8
  "ag-grid",
@@ -79,7 +79,7 @@
79
79
  "devDependencies": {
80
80
  "@babel/plugin-proposal-private-property-in-object": "^7.21.11",
81
81
  "@chromatic-com/storybook": "^1.3.5",
82
- "@linzjs/lui": ">=21",
82
+ "@linzjs/lui": "^21.30.0",
83
83
  "@rollup/plugin-commonjs": "^25.0.7",
84
84
  "@rollup/plugin-json": "^6.1.0",
85
85
  "@rollup/plugin-node-resolve": "^15.2.3",
@@ -104,8 +104,8 @@
104
104
  "@types/react": "^18.3.2",
105
105
  "@types/react-dom": "^18.3.0",
106
106
  "@types/uuid": "^9.0.8",
107
- "@typescript-eslint/eslint-plugin": "^7.9.0",
108
- "@typescript-eslint/parser": "^7.9.0",
107
+ "@typescript-eslint/eslint-plugin": "^7.10.0",
108
+ "@typescript-eslint/parser": "^7.10.0",
109
109
  "@vitejs/plugin-react-swc": "^3.6.0",
110
110
  "ag-grid-community": "^31",
111
111
  "ag-grid-react": "^31",
@@ -185,12 +185,12 @@ export const Grid = ({
185
185
  if (gridRendered === "empty") {
186
186
  if (!hasSetContentSizeEmpty.current && result && !hasSetContentSize.current) {
187
187
  hasSetContentSizeEmpty.current = true;
188
- params.onContentSize && params.onContentSize(result);
188
+ params.onContentSize?.(result);
189
189
  }
190
190
  } else if (gridRendered === "rows-visible") {
191
191
  if (result && !hasSetContentSize.current) {
192
192
  hasSetContentSize.current = true;
193
- params.onContentSize && params.onContentSize(result);
193
+ params.onContentSize?.(result);
194
194
  }
195
195
  } else {
196
196
  // It should be impossible to get here
@@ -219,7 +219,7 @@ export const Grid = ({
219
219
  needsAutoSize.current = true;
220
220
  }
221
221
  }
222
- if (needsAutoSize.current) {
222
+ if (needsAutoSize.current || (!hasSetContentSize.current && sizeColumns === "auto")) {
223
223
  needsAutoSize.current = false;
224
224
  setInitialContentSize();
225
225
  }
@@ -394,7 +394,7 @@ export const Grid = ({
394
394
  */
395
395
  const onGridReady = useCallback(
396
396
  (event: GridReadyEvent) => {
397
- setApis(event.api, event.columnApi, dataTestId);
397
+ setApis(event.api, dataTestId);
398
398
  event.api.showNoRowsOverlay();
399
399
  synchroniseExternallySelectedItemsToGrid();
400
400
  },
@@ -657,7 +657,7 @@ export const Grid = ({
657
657
 
658
658
  const moved = event.node.data;
659
659
  const target = event.overNode?.data;
660
- moved.id != target.id && //moved over a different row
660
+ moved.id !== target?.id && //moved over a different row
661
661
  event.node.rowIndex != targetIndex && //moved to a different index
662
662
  params.onRowDragEnd &&
663
663
  (await params.onRowDragEnd(moved, target, targetIndex));
@@ -686,6 +686,7 @@ export const Grid = ({
686
686
  {gridContextMenu.component}
687
687
  <div style={{ flex: 1 }} ref={gridDivRef}>
688
688
  <AgGridReact
689
+ reactiveCustomComponents={true}
689
690
  rowHeight={rowHeight}
690
691
  animateRows={params.animateRows ?? false}
691
692
  rowClassRules={params.rowClassRules}
@@ -38,9 +38,9 @@ export const usePostSortRowsHook = ({ setStaleGrid }: PostSortRowsHookProps) =>
38
38
  const previousQuickFilter = useRef("");
39
39
 
40
40
  return useCallback(
41
- ({ api, columnApi, nodes }: PostSortRowsParams) => {
41
+ ({ api, nodes }: PostSortRowsParams) => {
42
42
  // Grid is destroyed
43
- if (!api || !columnApi) return;
43
+ if (!api) return;
44
44
 
45
45
  const previousRowSortIndex = previousRowSortIndexRef.current;
46
46
 
@@ -49,7 +49,7 @@ export const usePostSortRowsHook = ({ setStaleGrid }: PostSortRowsHookProps) =>
49
49
  };
50
50
 
51
51
  const copyCurrentSortSettings = (): ColumnState[] =>
52
- columnApi.getColumnState().map((row) => ({ colId: row.colId, sort: row.sort, sortIndex: row.sortIndex }));
52
+ api.getColumnState().map((row) => ({ colId: row.colId, sort: row.sort, sortIndex: row.sortIndex }));
53
53
 
54
54
  const backupSortOrder = () => {
55
55
  for (const x in previousRowSortIndex) delete previousRowSortIndex[x];
@@ -62,7 +62,7 @@ export const usePostSortRowsHook = ({ setStaleGrid }: PostSortRowsHookProps) =>
62
62
  const isSameColumnAndDifferentSort = (col1: ColumnState | undefined, col2: ColumnState | undefined) =>
63
63
  col1 && col2 && col1.colId === col2.colId && col1.sort != col2.sort;
64
64
 
65
- const restorePreviousSortColumnState = () => columnApi.applyColumnState({ state: previousColSort.current });
65
+ const restorePreviousSortColumnState = () => api.applyColumnState({ state: previousColSort.current });
66
66
 
67
67
  const sortNodesByPreviousSort = () => {
68
68
  nodes.sort(
@@ -149,7 +149,7 @@ export const usePostSortRowsHook = ({ setStaleGrid }: PostSortRowsHookProps) =>
149
149
  previousRowSortIndex[`${lastNewNode?.data.id}`] = { index: newIndex, hash: hashNode(lastNewNode) };
150
150
  wasStale = true;
151
151
  } else if (changedRowCount === 2 && newRowCount === 0) {
152
- // This must be a swap rows
152
+ // This must be a swap rows (sometimes it's not, needs further attention)
153
153
  backupSortOrder();
154
154
  wasStale = false;
155
155
  } else if (changedRowCount > 1 && newRowCount === 1) {
@@ -1,6 +1,6 @@
1
1
  import { IHeaderParams } from "ag-grid-community";
2
2
  import clsx from "clsx";
3
- import { useCallback, useEffect, useState } from "react";
3
+ import { useEffect, useState } from "react";
4
4
 
5
5
  /**
6
6
  * AgGrid's existing select header doesn't work the way we want.
@@ -12,14 +12,16 @@ export const GridHeaderSelect = ({ api }: IHeaderParams) => {
12
12
  const [updateCounter, setUpdateCounter] = useState(0);
13
13
  const selectedNodeCount = api.getSelectedRows().length;
14
14
 
15
- const clickHandler = useCallback(() => {
16
- setUpdateCounter(updateCounter + 1);
17
- }, [updateCounter]);
18
-
19
15
  useEffect(() => {
16
+ const clickHandler = () => {
17
+ setUpdateCounter(updateCounter + 1);
18
+ };
19
+
20
20
  api.addEventListener("selectionChanged", clickHandler);
21
- return () => api.removeEventListener("selectionChanged", clickHandler);
22
- }, [api, clickHandler]);
21
+ return () => {
22
+ !api.isDestroyed() && api.removeEventListener("selectionChanged", clickHandler);
23
+ };
24
+ }, [api, updateCounter]);
23
25
 
24
26
  const handleMultiSelect = () => {
25
27
  if (selectedNodeCount == 0) {
@@ -29,7 +31,7 @@ export const GridHeaderSelect = ({ api }: IHeaderParams) => {
29
31
  }
30
32
  };
31
33
 
32
- const totalNodeCount = api.getModel().getRowCount();
34
+ const totalNodeCount = api.getDisplayedRowCount();
33
35
  const partialSelect = selectedNodeCount != 0 && selectedNodeCount != totalNodeCount;
34
36
  const allSelected = selectedNodeCount != 0 && selectedNodeCount == totalNodeCount;
35
37
 
@@ -1,4 +1,4 @@
1
- import { ColDef, ColumnApi, GridApi, IRowNode } from "ag-grid-community";
1
+ import { ColDef, GridApi, IRowNode } from "ag-grid-community";
2
2
  import { CsvExportParams } from "ag-grid-community";
3
3
  import { createContext, useContext } from "react";
4
4
 
@@ -23,7 +23,7 @@ export interface GridContextType<TData extends GridBaseRow> {
23
23
  filter?: keyof ColDef | ((r: ColDef) => boolean | undefined | null | number | string),
24
24
  ) => ColDefT<TData, any>[];
25
25
  getColumnIds: (filter?: keyof ColDef | ((r: ColDef) => boolean | undefined | null | number | string)) => string[];
26
- setApis: (gridApi: GridApi | undefined, columnApi: ColumnApi | undefined, dataTestId?: string) => void;
26
+ setApis: (gridApi: GridApi | undefined, dataTestId?: string) => void;
27
27
  prePopupOps: () => void;
28
28
  postPopupOps: () => void;
29
29
  setQuickFilter: (quickFilter: string) => void;
@@ -1,5 +1,4 @@
1
- import { CellPosition, ColDef, ColumnApi, GridApi, IRowNode, RowNode } from "ag-grid-community";
2
- import { ValueFormatterParams } from "ag-grid-community";
1
+ import { CellPosition, ColDef, GridApi, IRowNode, RowNode } from "ag-grid-community";
3
2
  import { CsvExportParams, ProcessCellForExportParams } from "ag-grid-community";
4
3
  import debounce from "debounce-promise";
5
4
  import { compact, defer, delay, difference, filter, isEmpty, last, pull, remove, sortBy, sumBy } from "lodash-es";
@@ -20,7 +19,6 @@ import { GridUpdatingContext } from "./GridUpdatingContext";
20
19
  export const GridContextProvider = <TData extends GridBaseRow>(props: PropsWithChildren): ReactElement => {
21
20
  const { modifyUpdating, checkUpdating } = useContext(GridUpdatingContext);
22
21
  const [gridApi, setGridApi] = useState<GridApi>();
23
- const [columnApi, setColumnApi] = useState<ColumnApi>();
24
22
  const [gridReady, setGridReady] = useState(false);
25
23
  const [quickFilter, setQuickFilter] = useState("");
26
24
  const [invisibleColumnIds, _setInvisibleColumnIds] = useState<string[]>();
@@ -40,7 +38,7 @@ export const GridContextProvider = <TData extends GridBaseRow>(props: PropsWithC
40
38
  * Set quick filter directly on grid, based on previously save quickFilter state.
41
39
  */
42
40
  useEffect(() => {
43
- gridApi?.setQuickFilter(quickFilter);
41
+ gridApi?.setGridOption("quickFilterText", quickFilter);
44
42
  }, [gridApi, quickFilter]);
45
43
 
46
44
  /**
@@ -94,11 +92,10 @@ export const GridContextProvider = <TData extends GridBaseRow>(props: PropsWithC
94
92
  * Set the grid api when the grid is ready.
95
93
  */
96
94
  const setApis = useCallback(
97
- (gridApi: GridApi | undefined, columnApi: ColumnApi | undefined, dataTestId?: string) => {
95
+ (gridApi: GridApi | undefined, dataTestId?: string) => {
98
96
  testId.current = dataTestId;
99
97
  setGridApi(gridApi);
100
- setColumnApi(columnApi);
101
- gridApi?.setQuickFilter(quickFilter);
98
+ gridApi?.setGridOption("quickFilterText", quickFilter);
102
99
  setGridReady(!!gridApi);
103
100
  },
104
101
  [quickFilter],
@@ -108,9 +105,8 @@ export const GridContextProvider = <TData extends GridBaseRow>(props: PropsWithC
108
105
  * Used to check if it's OK to autosize.
109
106
  */
110
107
  const gridRenderState = useCallback((): null | "empty" | "rows-visible" => {
111
- // Even though getModel can't be null, sometimes it is
112
- if (!gridApi || !gridApi.getModel()) return null;
113
- if (!gridApi.getModel().isRowsToRender()) return "empty";
108
+ if (!gridApi) return null;
109
+ if (!gridApi.getDisplayedRowCount()) return "empty";
114
110
  if (!isEmpty(gridApi.getRenderedNodes())) return "rows-visible";
115
111
  // If there are rows to render, but there are no rendered nodes then we should wait
116
112
  return null;
@@ -205,8 +201,8 @@ export const GridContextProvider = <TData extends GridBaseRow>(props: PropsWithC
205
201
  (
206
202
  filterDef: keyof ColDef | ((r: ColDef) => boolean | undefined | null | number | string) = () => true,
207
203
  ): ColDefT<TData>[] =>
208
- filter(columnApi?.getColumns()?.map((col) => col.getColDef()) ?? [], filterDef) as ColDefT<TData>[],
209
- [columnApi],
204
+ filter(gridApi?.getColumns()?.map((col) => col.getColDef()) ?? [], filterDef) as ColDefT<TData>[],
205
+ [gridApi],
210
206
  );
211
207
 
212
208
  const getColumnIds = useCallback(
@@ -407,9 +403,9 @@ export const GridContextProvider = <TData extends GridBaseRow>(props: PropsWithC
407
403
  */
408
404
  const autoSizeColumns = useCallback(
409
405
  ({ skipHeader, colIds, userSizedColIds, includeFlex }: AutoSizeColumnsProps = {}): AutoSizeColumnsResult => {
410
- if (!columnApi) return null;
406
+ if (!gridApi) return null;
411
407
  const colIdsSet = colIds instanceof Set ? colIds : new Set(colIds);
412
- const colsToResize = columnApi.getColumnState().filter((colState) => {
408
+ const colsToResize = gridApi.getColumnState().filter((colState) => {
413
409
  const colId = colState.colId;
414
410
  return (
415
411
  (isEmpty(colIdsSet) || colIdsSet.has(colId)) &&
@@ -418,19 +414,19 @@ export const GridContextProvider = <TData extends GridBaseRow>(props: PropsWithC
418
414
  );
419
415
  });
420
416
  if (!isEmpty(colsToResize)) {
421
- columnApi.autoSizeColumns(
417
+ gridApi.autoSizeColumns(
422
418
  colsToResize.map((colState) => colState.colId),
423
419
  skipHeader,
424
420
  );
425
421
  }
426
422
  return {
427
423
  width: sumBy(
428
- columnApi.getColumnState().filter((col) => !col.hide),
424
+ gridApi.getColumnState().filter((col) => !col.hide),
429
425
  "width",
430
426
  ),
431
427
  };
432
428
  },
433
- [columnApi],
429
+ [gridApi],
434
430
  );
435
431
 
436
432
  /**
@@ -489,7 +485,7 @@ export const GridContextProvider = <TData extends GridBaseRow>(props: PropsWithC
489
485
  */
490
486
  const cancelEdit = useCallback((): void => {
491
487
  stopEditing();
492
- cellEditingCompleteCallbackRef.current && cellEditingCompleteCallbackRef.current();
488
+ cellEditingCompleteCallbackRef.current?.();
493
489
  }, [stopEditing]);
494
490
 
495
491
  const cellEditingCompleteCallbackRef = useRef<() => void>();
@@ -583,7 +579,7 @@ export const GridContextProvider = <TData extends GridBaseRow>(props: PropsWithC
583
579
  gridApi.refreshClientSideRowModel();
584
580
  } else {
585
581
  // Don't set saving if ok as the form has already closed
586
- setSaving && setSaving(false);
582
+ setSaving?.(false);
587
583
  }
588
584
 
589
585
  // Only focus next cell if user hasn't already manually changed focus
@@ -667,7 +663,7 @@ export const GridContextProvider = <TData extends GridBaseRow>(props: PropsWithC
667
663
  * Apply column visibility
668
664
  */
669
665
  useEffect(() => {
670
- if (!columnApi || !invisibleColumnIds) return;
666
+ if (!gridApi || !invisibleColumnIds) return;
671
667
 
672
668
  // show all columns that aren't invisible
673
669
  const newVisibleColumns = getColumns(
@@ -679,26 +675,26 @@ export const GridContextProvider = <TData extends GridBaseRow>(props: PropsWithC
679
675
  const fillerColumn = getColumns(isGridCellFiller)[0];
680
676
  fillerColumn && newVisibleColumns.push(fillerColumn);
681
677
  }
682
- columnApi.setColumnsVisible(compact(newVisibleColumns.map(getColId)), true);
678
+ gridApi.setColumnsVisible(compact(newVisibleColumns.map(getColId)), true);
683
679
 
684
680
  // Hide the filler column if there's already a flex column
685
681
  const invisibleColumnIdsWithOptionalFiller = visibleColumnsContainsAFlex
686
682
  ? [...invisibleColumnIds, GridCellFillerColId]
687
683
  : invisibleColumnIds;
688
- columnApi.setColumnsVisible(invisibleColumnIdsWithOptionalFiller, false);
689
- }, [invisibleColumnIds, columnApi, getColumns]);
684
+ gridApi.setColumnsVisible(invisibleColumnIdsWithOptionalFiller, false);
685
+ }, [invisibleColumnIds, getColumns, gridApi]);
690
686
 
691
687
  /**
692
688
  * Download visible columns as a CSV
693
689
  */
694
690
  const downloadCsv = useCallback(
695
691
  (csvExportParams?: CsvExportParams) => {
696
- if (!gridApi || !columnApi) return;
692
+ if (!gridApi) return;
697
693
 
698
694
  const fileName = csvExportParams?.fileName && sanitiseFileName(fnOrVar(csvExportParams.fileName));
699
695
 
700
- const columnKeys = columnApi
701
- ?.getColumnState()
696
+ const columnKeys = gridApi
697
+ .getColumnState()
702
698
  .filter((cs) => {
703
699
  const colDef = gridApi.getColumnDef(cs.colId);
704
700
  return !cs.hide && colDef && !isGridCellFiller(colDef) && colDef.headerComponentParams?.exportable !== false;
@@ -711,7 +707,7 @@ export const GridContextProvider = <TData extends GridBaseRow>(props: PropsWithC
711
707
  fileName,
712
708
  });
713
709
  },
714
- [columnApi, gridApi],
710
+ [gridApi],
715
711
  );
716
712
 
717
713
  return (
@@ -807,7 +803,7 @@ export const downloadCsvUseValueFormattersProcessCellCallback = (params: Process
807
803
  return encodeToString(params.value);
808
804
  }
809
805
 
810
- const result = valueFormatter({ ...params, data: params.node?.data, colDef } as ValueFormatterParams);
806
+ const result = valueFormatter({ ...params, data: params.node?.data, colDef, node: null });
811
807
  // type may not be string due to casting, leave the type check in
812
808
  if (params.value != null && typeof result !== "string") {
813
809
  console.error(`downloadCsv: valueFormatter is returning non string values, colDef:", colId: ${colDef.colId}`);
@@ -91,7 +91,7 @@ const GridDragRowTemplate: StoryFn<typeof Grid> = (props: GridProps) => {
91
91
  [],
92
92
  );
93
93
 
94
- const [rowData] = useState([
94
+ const [rowData, setRowData] = useState([
95
95
  { id: 1000, position: "Tester", age: 30, height: `6'4"`, desc: "Tests application", dd: "1" },
96
96
  { id: 1001, position: "Developer", age: 12, height: `5'3"`, desc: "Develops application", dd: "2" },
97
97
  { id: 1002, position: "Manager", age: 65, height: `5'9"`, desc: "Manages", dd: "3" },
@@ -109,8 +109,14 @@ const GridDragRowTemplate: StoryFn<typeof Grid> = (props: GridProps) => {
109
109
  columnDefs={columnDefs}
110
110
  defaultColDef={{ sortable: false }}
111
111
  rowData={rowData}
112
- onRowDragEnd={async (row, _, targetIndex) => {
113
- alert(`Row ${row.id} request to be moved to index ${targetIndex}.`);
112
+ onRowDragEnd={async (movedRow, targetRow, _targetIndex) => {
113
+ setRowData(
114
+ rowData.map((r) => {
115
+ if (r.id === movedRow.id) return targetRow;
116
+ if (r.id === targetRow.id) return movedRow;
117
+ return r;
118
+ }),
119
+ );
114
120
  }}
115
121
  rowDragText={({ rowNode }) => `${rowNode?.data.id} - ${rowNode?.data.position}`}
116
122
  />
@@ -290,6 +290,15 @@ const GridEditDropDownTemplate: StoryFn<typeof Grid> = (props: GridProps) => {
290
290
  code: "O2",
291
291
  sub: "one",
292
292
  },
293
+ {
294
+ id: 1002,
295
+ position: "Scrum Master",
296
+ position2: "2",
297
+ position3: "Architect",
298
+ position4: { code: "O2", desc: "Object Two" },
299
+ code: "O2",
300
+ sub: "one",
301
+ },
293
302
  ] as ITestRow[]);
294
303
 
295
304
  return (
@@ -15,13 +15,10 @@
15
15
  flex: 1;
16
16
  }
17
17
 
18
-
19
18
  .Grid-sortIsStale {
20
- span.ag-icon.ag-icon-desc::after {
21
- content: "*";
22
- }
23
-
24
- span.ag-icon.ag-icon-asc::after {
19
+ span.ag-sort-indicator-icon::before {
20
+ margin-left: -6px;
21
+ position: absolute;
25
22
  content: "*";
26
23
  }
27
24
  }