@linzjs/step-ag-grid 14.3.2 → 14.4.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.3.2",
5
+ "version": "14.4.0",
6
6
  "keywords": [
7
7
  "aggrid",
8
8
  "ag-grid",
@@ -1,12 +1,7 @@
1
1
  import { CellClickedEvent, ColDef, 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
- import {
5
- CellEditingStoppedEvent,
6
- CellEvent,
7
- GridReadyEvent,
8
- SelectionChangedEvent,
9
- } from "ag-grid-community/dist/lib/events";
4
+ import { CellEvent, GridReadyEvent, SelectionChangedEvent } from "ag-grid-community/dist/lib/events";
10
5
  import { AgGridReact } from "ag-grid-react";
11
6
  import clsx from "clsx";
12
7
  import { difference, isEmpty, last, omit, xorBy } from "lodash-es";
@@ -88,7 +83,6 @@ export const Grid = ({
88
83
  const {
89
84
  gridReady,
90
85
  setApis,
91
- prePopupOps,
92
86
  ensureRowVisible,
93
87
  getFirstRowId,
94
88
  selectRowsById,
@@ -101,8 +95,10 @@ export const Grid = ({
101
95
  isExternalFilterPresent,
102
96
  doesExternalFilterPass,
103
97
  setOnCellEditingComplete,
98
+ getColDef,
104
99
  } = useContext(GridContext);
105
- const { checkUpdating, updatedDep, isUpdating } = useContext(GridUpdatingContext);
100
+ const { updatedDep, updatingCols } = useContext(GridUpdatingContext);
101
+ const gridContext = useContext(GridContext);
106
102
 
107
103
  const gridDivRef = useRef<HTMLDivElement>(null);
108
104
 
@@ -351,12 +347,12 @@ export const Grid = ({
351
347
  lastUpdatedDep.current = updatedDep;
352
348
 
353
349
  // Don't update while there are spinners
354
- if (isUpdating()) return;
350
+ if (!isEmpty(updatingCols())) return;
355
351
 
356
352
  const skipHeader = sizeColumns === "auto-skip-headers";
357
353
  autoSizeColumns({ skipHeader, userSizedColIds: userSizedColIds.current, colIds: colIdsEdited.current });
358
354
  colIdsEdited.current.clear();
359
- }, [autoSizeColumns, isUpdating, params.rowData?.length, setInitialContentSize, sizeColumns, updatedDep]);
355
+ }, [autoSizeColumns, params.rowData?.length, setInitialContentSize, sizeColumns, updatedDep, updatingCols]);
360
356
 
361
357
  /**
362
358
  * Show/hide no rows overlay when model changes.
@@ -391,23 +387,13 @@ export const Grid = ({
391
387
  */
392
388
  const startCellEditing = useCallback(
393
389
  (event: CellEvent) => {
394
- prePopupOps();
395
- if (!event.node.isSelected()) {
396
- event.node.setSelected(true, true);
397
- }
398
- // Cell already being edited, so don't re-edit until finished
399
- if (checkUpdating([event.colDef.field ?? ""], event.data.id)) {
400
- return;
401
- }
402
-
403
- if (event.rowIndex !== null) {
404
- event.api.startEditingCell({
405
- rowIndex: event.rowIndex,
406
- colKey: event.column.getColId(),
390
+ event.data.id &&
391
+ gridContext.startCellEditing({
392
+ rowId: event.data.id,
393
+ colId: event.column.getColId(),
407
394
  });
408
- }
409
395
  },
410
- [checkUpdating, prePopupOps],
396
+ [gridContext],
411
397
  );
412
398
 
413
399
  /**
@@ -478,48 +464,39 @@ export const Grid = ({
478
464
  * Set of colIds that need auto-sizing.
479
465
  */
480
466
  const colIdsEdited = useRef(new Set<string>());
481
-
482
- /**
483
- * When cell editing has completed tag the colId as needing auto-sizing
484
- */
485
- const onCellEditingStopped = useCallback(
486
- (e: CellEditingStoppedEvent) => {
487
- const skipHeader = sizeColumns === "auto-skip-headers";
488
- if (sizeColumns === "auto" || skipHeader) {
489
- // This may be wrong as the cell update hasn't completed?
490
- const colId = e.colDef.colId;
491
- if (colId && !e.colDef.flex) {
492
- // This auto-sizes based on updatingContext completing
493
- colIdsEdited.current.add(colId);
494
- // This auto-sizes immediately in case it was an in place update
495
- !isUpdating() &&
496
- autoSizeColumns({
497
- skipHeader,
498
- userSizedColIds: userSizedColIds.current,
499
- colIds: [colId],
500
- });
501
- }
502
- }
503
- },
504
- [autoSizeColumns, isUpdating, sizeColumns],
505
- );
506
-
507
467
  const lastUpdatedDep = useRef(updatedDep);
508
468
 
509
469
  /**
510
- * If columns are edited, wait for the updating context to complete then auto-size them.
470
+ * When cell editing has completed the colId as needing auto-sizing
511
471
  */
512
472
  useEffect(() => {
513
- if (lastUpdatedDep.current === updatedDep || isEmpty(colIdsEdited.current)) return;
473
+ if (lastUpdatedDep.current === updatedDep) return;
514
474
  lastUpdatedDep.current = updatedDep;
515
475
 
516
- // Don't update while there are spinners
517
- if (isUpdating()) return;
518
-
519
- const skipHeader = sizeColumns === "auto-skip-headers";
520
- autoSizeColumns({ skipHeader, userSizedColIds: userSizedColIds.current, colIds: colIdsEdited.current });
521
- colIdsEdited.current.clear();
522
- }, [autoSizeColumns, updatedDep, sizeColumns, isUpdating]);
476
+ const colIds = updatingCols();
477
+ // Updating possibly completed
478
+ if (isEmpty(colIds)) {
479
+ // Columns to resize?
480
+ if (!isEmpty(colIdsEdited.current)) {
481
+ const skipHeader = sizeColumns === "auto-skip-headers";
482
+ if (sizeColumns === "auto" || skipHeader) {
483
+ autoSizeColumns({
484
+ skipHeader,
485
+ userSizedColIds: userSizedColIds.current,
486
+ colIds: colIdsEdited.current,
487
+ });
488
+ }
489
+ colIdsEdited.current.clear();
490
+ }
491
+ } else {
492
+ // Updates not complete, add them to a list of columns needing resize
493
+ colIds.forEach((colId) => {
494
+ if (colId && !getColDef(colId)?.flex) {
495
+ colIdsEdited.current.add(colId);
496
+ }
497
+ });
498
+ }
499
+ }, [autoSizeColumns, getColDef, sizeColumns, updatedDep, updatingCols]);
523
500
 
524
501
  /**
525
502
  * Resize columns to fit if required on window/container resize
@@ -583,7 +560,6 @@ export const Grid = ({
583
560
  onCellDoubleClicked={onCellDoubleClick}
584
561
  onCellEditingStarted={refreshSelectedRows}
585
562
  domLayout={params.domLayout}
586
- onCellEditingStopped={onCellEditingStopped}
587
563
  onColumnResized={onColumnResized}
588
564
  defaultColDef={{ minWidth: 48, ...omit(params.defaultColDef, ["editable"]) }}
589
565
  columnDefs={columnDefsAdjusted}
@@ -1,4 +1,4 @@
1
- import { ColumnApi, GridApi, RowNode } from "ag-grid-community";
1
+ import { ColDef, ColumnApi, GridApi, RowNode } from "ag-grid-community";
2
2
  import { CsvExportParams } from "ag-grid-community/dist/lib/interfaces/exportParams";
3
3
  import { createContext, useContext } from "react";
4
4
 
@@ -16,6 +16,8 @@ export type AutoSizeColumnsResult = { width: number } | null;
16
16
 
17
17
  export interface GridContextType<RowType extends GridBaseRow> {
18
18
  gridReady: boolean;
19
+ getColDef: (colId?: string) => ColDef | undefined;
20
+ getColumns: () => ColDefT<RowType>[];
19
21
  setApis: (gridApi: GridApi | undefined, columnApi: ColumnApi | undefined, dataTestId?: string) => void;
20
22
  prePopupOps: () => void;
21
23
  setQuickFilter: (quickFilter: string) => void;
@@ -37,6 +39,7 @@ export interface GridContextType<RowType extends GridBaseRow> {
37
39
  autoSizeColumns: (props?: AutoSizeColumnsProps) => AutoSizeColumnsResult;
38
40
  sizeColumnsToFit: () => void;
39
41
  cancelEdit: () => void;
42
+ startCellEditing: ({ rowId, colId }: { rowId: number; colId: string }) => void;
40
43
  stopEditing: () => void;
41
44
  updatingCells: (
42
45
  props: { selectedRows: GridBaseRow[]; field?: string },
@@ -52,7 +55,6 @@ export interface GridContextType<RowType extends GridBaseRow> {
52
55
  removeExternalFilter: (filter: GridFilterExternal<RowType>) => void;
53
56
  isExternalFilterPresent: () => boolean;
54
57
  doesExternalFilterPass: (node: RowNode) => boolean;
55
- getColumns: () => ColDefT<RowType>[];
56
58
  invisibleColumnIds: string[];
57
59
  setInvisibleColumnIds: (colIds: string[]) => void;
58
60
  downloadCsv: (csvExportParams?: CsvExportParams) => void;
@@ -61,6 +63,10 @@ export interface GridContextType<RowType extends GridBaseRow> {
61
63
 
62
64
  export const GridContext = createContext<GridContextType<any>>({
63
65
  gridReady: false,
66
+ getColDef: () => {
67
+ console.error("no context provider for getColDef");
68
+ return undefined;
69
+ },
64
70
  getColumns: () => {
65
71
  console.error("no context provider for getColumns");
66
72
  return [];
@@ -142,6 +148,9 @@ export const GridContext = createContext<GridContextType<any>>({
142
148
  cancelEdit: () => {
143
149
  console.error("no context provider for cancelEdit");
144
150
  },
151
+ startCellEditing: () => {
152
+ console.error("no context provider for startCellEditing");
153
+ },
145
154
  stopEditing: () => {
146
155
  console.error("no context provider for stopEditing");
147
156
  },
@@ -21,7 +21,7 @@ interface GridContextProps {
21
21
  * Also, make sure the provider is created in a separate component, otherwise it won't be found.
22
22
  */
23
23
  export const GridContextProvider = <RowType extends GridBaseRow>(props: GridContextProps): ReactElement => {
24
- const { modifyUpdating } = useContext(GridUpdatingContext);
24
+ const { modifyUpdating, checkUpdating } = useContext(GridUpdatingContext);
25
25
  const [gridApi, setGridApi] = useState<GridApi>();
26
26
  const [columnApi, setColumnApi] = useState<ColumnApi>();
27
27
  const [gridReady, setGridReady] = useState(false);
@@ -377,6 +377,41 @@ export const GridContextProvider = <RowType extends GridBaseRow>(props: GridCont
377
377
  gridApi.stopEditing();
378
378
  }, [gridApi]);
379
379
 
380
+ const startCellEditing = useCallback(
381
+ async ({ rowId, colId }: { rowId: number; colId: string }) => {
382
+ if (!gridApi) return;
383
+
384
+ const colDef = gridApi.getColumnDef(colId);
385
+ if (!colDef) return;
386
+
387
+ // Cell already being edited, so don't re-edit until finished
388
+ if (checkUpdating([colDef.field ?? ""], rowId)) {
389
+ return;
390
+ }
391
+ const rowNode = gridApi.getRowNode(`${rowId}`);
392
+ if (!rowNode) {
393
+ return;
394
+ }
395
+
396
+ if (!rowNode.isSelected()) {
397
+ rowNode.setSelected(true, true);
398
+ }
399
+ prePopupOps();
400
+
401
+ const rowIndex = rowNode.rowIndex;
402
+ if (rowIndex != null) {
403
+ const focusAndEdit = () => {
404
+ gridApi.startEditingCell({
405
+ rowIndex,
406
+ colKey: colId,
407
+ });
408
+ };
409
+ defer(focusAndEdit);
410
+ }
411
+ },
412
+ [checkUpdating, gridApi, prePopupOps],
413
+ );
414
+
380
415
  /**
381
416
  * This differs from stopEdit in that it will also invoke cellEditingCompleteCallback
382
417
  */
@@ -544,6 +579,11 @@ export const GridContextProvider = <RowType extends GridBaseRow>(props: GridCont
544
579
  return externalFilters.current.every((filter) => filter(node.data, node));
545
580
  };
546
581
 
582
+ const getColDef = useCallback(
583
+ (colId?: string): ColDef | undefined => (!!colId && gridApi?.getColumnDef(colId)) || undefined,
584
+ [gridApi],
585
+ );
586
+
547
587
  const getColumns: () => ColDefT<RowType>[] = useCallback(() => gridApi?.getColumnDefs() ?? [], [gridApi]);
548
588
 
549
589
  useEffect(() => {
@@ -588,6 +628,7 @@ export const GridContextProvider = <RowType extends GridBaseRow>(props: GridCont
588
628
  return (
589
629
  <GridContext.Provider
590
630
  value={{
631
+ getColDef,
591
632
  getColumns,
592
633
  invisibleColumnIds,
593
634
  setInvisibleColumnIds,
@@ -612,6 +653,7 @@ export const GridContextProvider = <RowType extends GridBaseRow>(props: GridCont
612
653
  ensureSelectedRowIsVisible,
613
654
  sizeColumnsToFit,
614
655
  autoSizeColumns,
656
+ startCellEditing,
615
657
  stopEditing,
616
658
  cancelEdit,
617
659
  updatingCells,
@@ -2,13 +2,13 @@ import { createContext } from "react";
2
2
 
3
3
  export type GridUpdatingContextType = {
4
4
  checkUpdating: (fields: string | string[], id: number | string) => boolean;
5
- isUpdating: () => boolean;
6
5
  modifyUpdating: (
7
6
  fields: string | string[],
8
7
  ids: (number | string)[],
9
8
  fn: () => void | Promise<void>,
10
9
  ) => Promise<void>;
11
10
  updatedDep: number;
11
+ updatingCols: () => string[];
12
12
  };
13
13
 
14
14
  export const GridUpdatingContext = createContext<GridUpdatingContextType>({
@@ -16,9 +16,9 @@ export const GridUpdatingContext = createContext<GridUpdatingContextType>({
16
16
  console.error("Missing GridUpdatingContext");
17
17
  return false;
18
18
  },
19
- isUpdating: () => {
19
+ updatingCols: () => {
20
20
  console.error("Missing GridUpdatingContext");
21
- return false;
21
+ return [];
22
22
  },
23
23
  modifyUpdating: async () => {
24
24
  console.error("Missing GridUpdatingContext");
@@ -1,4 +1,4 @@
1
- import { castArray, flatten, isEmpty, remove } from "lodash-es";
1
+ import { castArray, flatten, remove } from "lodash-es";
2
2
  import { ReactNode, useRef, useState } from "react";
3
3
 
4
4
  import { GridUpdatingContext } from "./GridUpdatingContext";
@@ -29,8 +29,7 @@ export const GridUpdatingContextProvider = (props: UpdatingContextProviderProps)
29
29
  updating.current = mergedUpdatingBlocks;
30
30
  setUpdatedDep((updatedDep) => updatedDep + 1);
31
31
  };
32
-
33
- const isUpdating = () => !isEmpty(updating.current);
32
+ const updatingCols = () => Object.keys(updating.current);
34
33
 
35
34
  const modifyUpdating = async (
36
35
  fields: string | string[],
@@ -55,7 +54,7 @@ export const GridUpdatingContextProvider = (props: UpdatingContextProviderProps)
55
54
  castArray(fields).some((f) => updating.current[f]?.includes(id));
56
55
 
57
56
  return (
58
- <GridUpdatingContext.Provider value={{ modifyUpdating, checkUpdating, isUpdating, updatedDep }}>
57
+ <GridUpdatingContext.Provider value={{ modifyUpdating, checkUpdating, updatingCols, updatedDep }}>
59
58
  {props.children}
60
59
  </GridUpdatingContext.Provider>
61
60
  );