@linzjs/step-ag-grid 14.1.1 → 14.2.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.
@@ -1,7 +1,7 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
2
  import { LuiMiniSpinner, LuiIcon, LuiButton, LuiCheckboxInput, LuiButtonGroup } from '@linzjs/lui';
3
3
  import { AgGridReact } from 'ag-grid-react';
4
- import { negate, isEmpty, xorBy, last, difference, sortBy, findIndex, debounce as debounce$1, delay, partition, omit, pick, groupBy, fromPairs, toPairs, defer as defer$1, sumBy, compact, remove, castArray, flatten, isEqual } from 'lodash-es';
4
+ import { negate, isEmpty, xorBy, last, difference, omit, sortBy, findIndex, debounce as debounce$1, delay, partition, pick, groupBy, fromPairs, toPairs, defer as defer$1, sumBy, compact, remove, castArray, flatten, isEqual } from 'lodash-es';
5
5
  import * as React from 'react';
6
6
  import { createContext, useContext, useRef, useCallback, useState, useEffect, useMemo, forwardRef, useLayoutEffect, memo, useReducer, cloneElement, useImperativeHandle, Fragment as Fragment$1 } from 'react';
7
7
  import ReactDOM, { unstable_batchedUpdates, flushSync, createPortal } from 'react-dom';
@@ -201,8 +201,8 @@ var GridContext = createContext({
201
201
  console.error("no context provider for getFirstRowId");
202
202
  return -1;
203
203
  },
204
- autoSizeAllColumns: function () {
205
- console.error("no context provider for autoSizeAllColumns");
204
+ autoSizeColumns: function () {
205
+ console.error("no context provider for autoSizeColumns");
206
206
  return null;
207
207
  },
208
208
  sizeColumnsToFit: function () {
@@ -213,6 +213,9 @@ var GridContext = createContext({
213
213
  console.error("no context provider for editingCells");
214
214
  return false;
215
215
  },
216
+ cancelEdit: function () {
217
+ console.error("no context provider for cancelEdit");
218
+ },
216
219
  stopEditing: function () {
217
220
  console.error("no context provider for stopEditing");
218
221
  },
@@ -250,6 +253,9 @@ var GridContext = createContext({
250
253
  },
251
254
  downloadCsv: function () {
252
255
  console.error("no context provider for downloadCsv");
256
+ },
257
+ setOnCellEditingComplete: function () {
258
+ console.error("no context provider for setOnCellEditingComplete");
253
259
  }
254
260
  });
255
261
  var useGridContext = function () { return useContext(GridContext); };
@@ -259,6 +265,10 @@ var GridUpdatingContext = createContext({
259
265
  console.error("Missing GridUpdatingContext");
260
266
  return false;
261
267
  },
268
+ isUpdating: function () {
269
+ console.error("Missing GridUpdatingContext");
270
+ return false;
271
+ },
262
272
  modifyUpdating: function () { return __awaiter(void 0, void 0, void 0, function () {
263
273
  return __generator(this, function (_a) {
264
274
  console.error("Missing GridUpdatingContext");
@@ -660,24 +670,48 @@ var GridHeaderSelect = function (_a) {
660
670
  var Grid = function (_a) {
661
671
  var _b, _c, _d;
662
672
  var dataTestId = _a["data-testid"], _e = _a.rowSelection, rowSelection = _e === void 0 ? "multiple" : _e, _f = _a.suppressColumnVirtualization, suppressColumnVirtualization = _f === void 0 ? true : _f, _g = _a.theme, theme = _g === void 0 ? "ag-theme-alpine" : _g, _h = _a.sizeColumns, sizeColumns = _h === void 0 ? "auto-skip-headers" : _h, params = __rest(_a, ["data-testid", "rowSelection", "suppressColumnVirtualization", "theme", "sizeColumns"]);
663
- var _j = useContext(GridContext), gridReady = _j.gridReady, setApis = _j.setApis, prePopupOps = _j.prePopupOps, ensureRowVisible = _j.ensureRowVisible, getFirstRowId = _j.getFirstRowId, selectRowsById = _j.selectRowsById, focusByRowById = _j.focusByRowById, ensureSelectedRowIsVisible = _j.ensureSelectedRowIsVisible, autoSizeAllColumns = _j.autoSizeAllColumns, sizeColumnsToFit = _j.sizeColumnsToFit, externallySelectedItemsAreInSync = _j.externallySelectedItemsAreInSync, setExternallySelectedItemsAreInSync = _j.setExternallySelectedItemsAreInSync, isExternalFilterPresent = _j.isExternalFilterPresent, doesExternalFilterPass = _j.doesExternalFilterPass;
664
- var checkUpdating = useContext(GridUpdatingContext).checkUpdating;
673
+ var _j = useContext(GridContext), gridReady = _j.gridReady, setApis = _j.setApis, prePopupOps = _j.prePopupOps, ensureRowVisible = _j.ensureRowVisible, getFirstRowId = _j.getFirstRowId, selectRowsById = _j.selectRowsById, focusByRowById = _j.focusByRowById, ensureSelectedRowIsVisible = _j.ensureSelectedRowIsVisible, autoSizeColumns = _j.autoSizeColumns, sizeColumnsToFit = _j.sizeColumnsToFit, externallySelectedItemsAreInSync = _j.externallySelectedItemsAreInSync, setExternallySelectedItemsAreInSync = _j.setExternallySelectedItemsAreInSync, isExternalFilterPresent = _j.isExternalFilterPresent, doesExternalFilterPass = _j.doesExternalFilterPass, setOnCellEditingComplete = _j.setOnCellEditingComplete;
674
+ var _k = useContext(GridUpdatingContext), checkUpdating = _k.checkUpdating, updatedDep = _k.updatedDep, isUpdating = _k.isUpdating;
665
675
  var lastSelectedIds = useRef([]);
666
- var _k = useState(false), staleGrid = _k[0], setStaleGrid = _k[1];
676
+ var _l = useState(false), staleGrid = _l[0], setStaleGrid = _l[1];
667
677
  var postSortRows = usePostSortRowsHook({ setStaleGrid: setStaleGrid });
678
+ /**
679
+ * onContentSize should only be called at maximum twice.
680
+ * Once when an empty grid is loaded.
681
+ * And again when the grid has content.
682
+ */
683
+ var hasSetContentSize = useRef(false);
684
+ var hasSetContentSizeEmpty = useRef(false);
668
685
  var setInitialContentSize = useCallback(function () {
669
- var skipHeaders = sizeColumns === "auto-skip-headers";
670
- if (sizeColumns === "auto" || skipHeaders) {
671
- // If we aren't skipping headers and there's no data, then don't skip headers
672
- var result = autoSizeAllColumns({ skipHeader: skipHeaders && !isEmpty(params.rowData) });
673
- params.onContentSize && result && params.onContentSize(result);
686
+ var skipHeader = sizeColumns === "auto-skip-headers";
687
+ if (sizeColumns === "auto" || skipHeader) {
688
+ var result = autoSizeColumns({ skipHeader: skipHeader, userSizedColIds: userSizedColIds.current });
689
+ if (isEmpty(params.rowData)) {
690
+ if (!hasSetContentSizeEmpty.current && !hasSetContentSize.current) {
691
+ hasSetContentSizeEmpty.current = true;
692
+ params.onContentSize && result && params.onContentSize(result);
693
+ }
694
+ }
695
+ else {
696
+ if (!hasSetContentSize.current) {
697
+ hasSetContentSize.current = true;
698
+ params.onContentSize && result && params.onContentSize(result);
699
+ }
700
+ }
674
701
  }
675
702
  if (sizeColumns !== "none") {
676
703
  sizeColumnsToFit();
677
704
  }
678
- }, [autoSizeAllColumns, params, sizeColumns, sizeColumnsToFit]);
705
+ }, [autoSizeColumns, params, sizeColumns, sizeColumnsToFit]);
706
+ /**
707
+ * When the grid becomes ready resize it
708
+ */
709
+ var previousGridReady = useRef(gridReady);
679
710
  useEffect(function () {
680
- gridReady && setInitialContentSize();
711
+ if (!previousGridReady.current && gridReady) {
712
+ previousGridReady.current = true;
713
+ setInitialContentSize();
714
+ }
681
715
  }, [gridReady, setInitialContentSize]);
682
716
  /**
683
717
  * On data load select the first row of the grid if required.
@@ -750,12 +784,16 @@ var Grid = function (_a) {
750
784
  }
751
785
  var selectedIds = params.externalSelectedItems.map(function (row) { return row.id; });
752
786
  var lastNewId = last(difference(selectedIds, lastSelectedIds.current));
753
- if (lastNewId != null)
787
+ if (lastNewId != null) {
754
788
  ensureRowVisible(lastNewId);
789
+ }
755
790
  lastSelectedIds.current = selectedIds;
756
791
  selectRowsById(selectedIds);
757
792
  setExternallySelectedItemsAreInSync(true);
758
793
  }, [gridReady, params.externalSelectedItems, ensureRowVisible, selectRowsById, setExternallySelectedItemsAreInSync]);
794
+ /**
795
+ * Combine grid and cell editable into one function
796
+ */
759
797
  var combineEditables = function () {
760
798
  var editables = [];
761
799
  for (var _i = 0; _i < arguments.length; _i++) {
@@ -773,9 +811,10 @@ var Grid = function (_a) {
773
811
  /**
774
812
  * Synchronise externally selected items to grid on externalSelectedItems change
775
813
  */
776
- useEffect(function () {
777
- synchroniseExternallySelectedItemsToGrid();
778
- }, [synchroniseExternallySelectedItemsToGrid]);
814
+ useEffect(synchroniseExternallySelectedItemsToGrid, [synchroniseExternallySelectedItemsToGrid]);
815
+ /**
816
+ * Add selectable column to colDefs. Adjust column defs to block fit for auto sized columns.
817
+ */
779
818
  var columnDefs = useMemo(function () {
780
819
  var adjustColDefs = params.columnDefs.map(function (colDef) {
781
820
  var _a;
@@ -818,6 +857,9 @@ var Grid = function (_a) {
818
857
  rowSelection,
819
858
  clickSelectorCheckboxWhenContainingCellClicked,
820
859
  ]);
860
+ /**
861
+ * When grid is ready set the apis to the grid context and sync selected items to grid.
862
+ */
821
863
  var onGridReady = useCallback(function (event) {
822
864
  setApis(event.api, event.columnApi, dataTestId);
823
865
  synchroniseExternallySelectedItemsToGrid();
@@ -827,26 +869,53 @@ var Grid = function (_a) {
827
869
  * This will resize columns when we have at least one row.
828
870
  */
829
871
  var previousRowDataLength = useRef(0);
830
- useEffect(function () {
872
+ var onRowDataChanged = useCallback(function () {
831
873
  var _a, _b;
832
874
  var length = (_b = (_a = params.rowData) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
833
875
  if (previousRowDataLength.current !== length) {
834
- if (previousRowDataLength.current === 0 && length > 0) {
835
- setInitialContentSize();
836
- }
876
+ setInitialContentSize();
837
877
  previousRowDataLength.current = length;
838
878
  }
839
- }, [(_c = params.rowData) === null || _c === void 0 ? void 0 : _c.length, setInitialContentSize]);
879
+ if (lastUpdatedDep.current === updatedDep || isEmpty(colIdsEdited.current))
880
+ return;
881
+ lastUpdatedDep.current = updatedDep;
882
+ // Don't update while there are spinners
883
+ if (isUpdating())
884
+ return;
885
+ var skipHeader = sizeColumns === "auto-skip-headers";
886
+ autoSizeColumns({ skipHeader: skipHeader, userSizedColIds: userSizedColIds.current, colIds: colIdsEdited.current });
887
+ colIdsEdited.current.clear();
888
+ }, [autoSizeColumns, isUpdating, (_c = params.rowData) === null || _c === void 0 ? void 0 : _c.length, setInitialContentSize, sizeColumns, updatedDep]);
889
+ /**
890
+ * Show/hide no rows overlay when model changes.
891
+ */
892
+ var isShowingNoRowsOverlay = useRef(false);
840
893
  var onModelUpdated = useCallback(function (event) {
841
- event.api.getDisplayedRowCount() === 0 ? event.api.showNoRowsOverlay() : event.api.hideOverlay();
894
+ if (event.api.getDisplayedRowCount() === 0) {
895
+ if (!isShowingNoRowsOverlay.current) {
896
+ event.api.showNoRowsOverlay();
897
+ isShowingNoRowsOverlay.current = true;
898
+ }
899
+ }
900
+ else {
901
+ if (isShowingNoRowsOverlay.current) {
902
+ event.api.hideOverlay();
903
+ isShowingNoRowsOverlay.current = false;
904
+ }
905
+ }
842
906
  }, []);
907
+ /**
908
+ * Force-refresh all selected rows to re-run class function, to update selection highlighting
909
+ */
843
910
  var refreshSelectedRows = useCallback(function (event) {
844
- // Force-refresh all selected rows to re-run class function, to update selection highlighting
845
911
  event.api.refreshCells({
846
912
  force: true,
847
913
  rowNodes: event.api.getSelectedNodes()
848
914
  });
849
915
  }, []);
916
+ /**
917
+ * Make sure node is selected for editing and start edit
918
+ */
850
919
  var startCellEditing = useCallback(function (event) {
851
920
  var _a;
852
921
  prePopupOps();
@@ -864,16 +933,25 @@ var Grid = function (_a) {
864
933
  });
865
934
  }
866
935
  }, [checkUpdating, prePopupOps]);
936
+ /**
937
+ * Handle double click edit
938
+ */
867
939
  var onCellDoubleClick = useCallback(function (event) {
868
940
  if (!invokeEditAction(event))
869
941
  startCellEditing(event);
870
942
  }, [startCellEditing]);
943
+ /**
944
+ * Handle single click edits
945
+ */
871
946
  var onCellClicked = useCallback(function (event) {
872
947
  var _a, _b;
873
948
  if ((_b = (_a = event.colDef) === null || _a === void 0 ? void 0 : _a.cellRendererParams) === null || _b === void 0 ? void 0 : _b.singleClickEdit) {
874
949
  startCellEditing(event);
875
950
  }
876
951
  }, [startCellEditing]);
952
+ /**
953
+ * If cell has an edit action invoke it (if editable)
954
+ */
877
955
  var invokeEditAction = function (e) {
878
956
  var _a, _b, _c;
879
957
  var editAction = (_b = (_a = e.colDef) === null || _a === void 0 ? void 0 : _a.cellRendererParams) === null || _b === void 0 ? void 0 : _b.editAction;
@@ -888,15 +966,15 @@ var Grid = function (_a) {
888
966
  }
889
967
  return true;
890
968
  };
969
+ /**
970
+ * Start editing on pressing Enter
971
+ */
891
972
  var onCellKeyPress = useCallback(function (e) {
892
973
  if (e.event.key === "Enter") {
893
974
  if (!invokeEditAction(e))
894
975
  startCellEditing(e);
895
976
  }
896
977
  }, [startCellEditing]);
897
- var onGridSizeChanged = useCallback(function () {
898
- sizeColumns !== "none" && sizeColumnsToFit();
899
- }, [sizeColumns, sizeColumnsToFit]);
900
978
  /**
901
979
  * Once the grid has auto-sized we want to run fit to fit the grid in its container,
902
980
  * but we don't want the non-flex auto-sized columns to "fit" size, so suppressSizeToFit is set to true.
@@ -904,7 +982,72 @@ var Grid = function (_a) {
904
982
  var columnDefsAdjusted = useMemo(function () {
905
983
  return columnDefs.map(function (colDef) { return (__assign(__assign({}, colDef), { suppressSizeToFit: (sizeColumns === "auto" || sizeColumns === "auto-skip-headers") && !colDef.flex })); });
906
984
  }, [columnDefs, sizeColumns]);
907
- return (jsx("div", __assign({ "data-testid": dataTestId, className: clsx("Grid-container", theme, staleGrid && "Grid-sortIsStale", gridReady && params.rowData && "Grid-ready") }, { children: jsx("div", __assign({ style: { flex: 1 } }, { children: jsx(AgGridReact, { animateRows: params.animateRows, rowClassRules: params.rowClassRules, getRowId: function (params) { return "".concat(params.data.id); }, suppressRowClickSelection: true, rowSelection: rowSelection, suppressBrowserResizeObserver: true, onGridSizeChanged: onGridSizeChanged, suppressColumnVirtualisation: suppressColumnVirtualization, suppressClickEdit: true, onCellKeyPress: onCellKeyPress, onCellClicked: onCellClicked, onCellDoubleClicked: onCellDoubleClick, onCellEditingStarted: refreshSelectedRows, domLayout: params.domLayout, columnDefs: columnDefsAdjusted, rowData: params.rowData, noRowsOverlayComponent: GridNoRowsOverlay, noRowsOverlayComponentParams: { rowData: params.rowData, noRowsOverlayText: params.noRowsOverlayText }, onModelUpdated: onModelUpdated, onGridReady: onGridReady, onSortChanged: ensureSelectedRowIsVisible, postSortRows: (_d = params.postSortRows) !== null && _d !== void 0 ? _d : postSortRows, onSelectionChanged: synchroniseExternalStateToGridSelection, onColumnMoved: params.onColumnMoved, alwaysShowVerticalScroll: params.alwaysShowVerticalScroll, isExternalFilterPresent: isExternalFilterPresent, doesExternalFilterPass: doesExternalFilterPass, maintainColumnOrder: true }) })) })));
985
+ /**
986
+ * Set of colIds that need auto-sizing.
987
+ */
988
+ var colIdsEdited = useRef(new Set());
989
+ /**
990
+ * When cell editing has completed tag the colId as needing auto-sizing
991
+ */
992
+ var onCellEditingStopped = useCallback(function (e) {
993
+ var skipHeader = sizeColumns === "auto-skip-headers";
994
+ if (sizeColumns === "auto" || skipHeader) {
995
+ // This may be wrong as the cell update hasn't completed?
996
+ var colId = e.colDef.colId;
997
+ if (colId && !e.colDef.flex) {
998
+ // This auto-sizes based on updatingContext completing
999
+ colIdsEdited.current.add(colId);
1000
+ // This auto-sizes immediately in case it was an in place update
1001
+ !isUpdating() && autoSizeColumns({ skipHeader: skipHeader, userSizedColIds: userSizedColIds.current, colIds: [colId] });
1002
+ }
1003
+ }
1004
+ }, [autoSizeColumns, isUpdating, sizeColumns]);
1005
+ var lastUpdatedDep = useRef(updatedDep);
1006
+ /**
1007
+ * If columns are edited, wait for the updating context to complete then auto-size them.
1008
+ */
1009
+ useEffect(function () {
1010
+ if (lastUpdatedDep.current === updatedDep || isEmpty(colIdsEdited.current))
1011
+ return;
1012
+ lastUpdatedDep.current = updatedDep;
1013
+ // Don't update while there are spinners
1014
+ if (isUpdating())
1015
+ return;
1016
+ var skipHeader = sizeColumns === "auto-skip-headers";
1017
+ autoSizeColumns({ skipHeader: skipHeader, userSizedColIds: userSizedColIds.current, colIds: colIdsEdited.current });
1018
+ colIdsEdited.current.clear();
1019
+ }, [autoSizeColumns, updatedDep, sizeColumns, isUpdating]);
1020
+ /**
1021
+ * Resize columns to fit if required on window/container resize
1022
+ */
1023
+ var onGridSizeChanged = useCallback(function () {
1024
+ if (sizeColumns !== "none") {
1025
+ sizeColumnsToFit();
1026
+ }
1027
+ }, [sizeColumns, sizeColumnsToFit]);
1028
+ /**
1029
+ * Set of column Id's that are prevented from auto-sizing as they are user set
1030
+ */
1031
+ var userSizedColIds = useRef(new Set());
1032
+ /**
1033
+ * Lock/unlock column width on user edit/reset.
1034
+ */
1035
+ var onColumnResized = useCallback(function (e) {
1036
+ var _a;
1037
+ var colId = (_a = e.column) === null || _a === void 0 ? void 0 : _a.getColId();
1038
+ if (colId == null)
1039
+ return;
1040
+ switch (e.source) {
1041
+ case "uiColumnDragged":
1042
+ userSizedColIds.current.add(colId);
1043
+ break;
1044
+ case "autosizeColumns":
1045
+ userSizedColIds.current["delete"](colId);
1046
+ break;
1047
+ }
1048
+ }, []);
1049
+ setOnCellEditingComplete(params.onCellEditingComplete);
1050
+ return (jsx("div", __assign({ "data-testid": dataTestId, className: clsx("Grid-container", theme, staleGrid && "Grid-sortIsStale", gridReady && params.rowData && "Grid-ready") }, { children: jsx("div", __assign({ style: { flex: 1 } }, { children: jsx(AgGridReact, { animateRows: params.animateRows, rowClassRules: params.rowClassRules, getRowId: function (params) { return "".concat(params.data.id); }, suppressRowClickSelection: true, rowSelection: rowSelection, suppressBrowserResizeObserver: true, onGridSizeChanged: onGridSizeChanged, suppressColumnVirtualisation: suppressColumnVirtualization, suppressClickEdit: true, onRowDataChanged: onRowDataChanged, onCellKeyPress: onCellKeyPress, onCellClicked: onCellClicked, onCellDoubleClicked: onCellDoubleClick, onCellEditingStarted: refreshSelectedRows, domLayout: params.domLayout, onCellEditingStopped: onCellEditingStopped, onColumnResized: onColumnResized, defaultColDef: __assign({ minWidth: 48 }, omit(params.defaultColDef, ["editable"])), columnDefs: columnDefsAdjusted, rowData: params.rowData, noRowsOverlayComponent: GridNoRowsOverlay, noRowsOverlayComponentParams: { rowData: params.rowData, noRowsOverlayText: params.noRowsOverlayText }, onModelUpdated: onModelUpdated, onGridReady: onGridReady, onSortChanged: ensureSelectedRowIsVisible, postSortRows: (_d = params.postSortRows) !== null && _d !== void 0 ? _d : postSortRows, onSelectionChanged: synchroniseExternalStateToGridSelection, onColumnMoved: params.onColumnMoved, alwaysShowVerticalScroll: params.alwaysShowVerticalScroll, isExternalFilterPresent: isExternalFilterPresent, doesExternalFilterPass: doesExternalFilterPass, maintainColumnOrder: true }) })) })));
908
1051
  };
909
1052
 
910
1053
  var GridPopoverContext = createContext({
@@ -1044,7 +1187,7 @@ var generateFilterGetter = function (field, filterValueGetter, valueFormatter) {
1044
1187
  * All cells should use this.
1045
1188
  */
1046
1189
  var GridCell = function (props, custom) {
1047
- var _a, _b, _c;
1190
+ var _a, _b, _c, _d;
1048
1191
  // Generate a default filter value getter which uses the formatted value plus
1049
1192
  // the editable value if it's a string and different from the formatted value.
1050
1193
  // This is so that e.g. bearings can be searched for by DMS or raw number.
@@ -1053,12 +1196,12 @@ var GridCell = function (props, custom) {
1053
1196
  var exportable = props.exportable;
1054
1197
  // Can't leave this here ag-grid will complain
1055
1198
  delete props.exportable;
1056
- return __assign(__assign(__assign(__assign(__assign(__assign({ colId: (_a = props.field) !== null && _a !== void 0 ? _a : props.field, headerTooltip: props.headerName, sortable: !!((props === null || props === void 0 ? void 0 : props.field) || (props === null || props === void 0 ? void 0 : props.valueGetter)), resizable: true, minWidth: props.flex ? 150 : 48, editable: (_b = props.editable) !== null && _b !== void 0 ? _b : false }, ((custom === null || custom === void 0 ? void 0 : custom.editor) && {
1199
+ return __assign(__assign(__assign(__assign(__assign(__assign({ colId: (_a = props.field) !== null && _a !== void 0 ? _a : props.field, headerTooltip: props.headerName, sortable: !!((props === null || props === void 0 ? void 0 : props.field) || (props === null || props === void 0 ? void 0 : props.valueGetter)), resizable: true, editable: (_b = props.editable) !== null && _b !== void 0 ? _b : false }, ((custom === null || custom === void 0 ? void 0 : custom.editor) && {
1057
1200
  cellClassRules: GridCellMultiSelectClassRules,
1058
1201
  editable: (_c = props.editable) !== null && _c !== void 0 ? _c : true,
1059
1202
  cellEditor: GenericCellEditorComponentWrapper(custom === null || custom === void 0 ? void 0 : custom.editor)
1060
1203
  })), { suppressKeyboardEvent: suppressCellKeyboardEvents }), ((custom === null || custom === void 0 ? void 0 : custom.editorParams) && {
1061
- cellEditorParams: __assign(__assign({}, custom.editorParams), { multiEdit: custom.multiEdit })
1204
+ cellEditorParams: __assign(__assign({}, custom.editorParams), { multiEdit: custom.multiEdit, preventAutoEdit: (_d = custom.preventAutoEdit) !== null && _d !== void 0 ? _d : false })
1062
1205
  })), {
1063
1206
  // If there's a valueFormatter and no filterValueGetter then create a filterValueGetter
1064
1207
  filterValueGetter: filterValueGetter,
@@ -2264,7 +2407,21 @@ var MenuList = function (_a) {
2264
2407
  }
2265
2408
  : undefined;
2266
2409
  }, [dontShrinkIfDirectionIsTop, expandedDirection, isSubmenuOpen]);
2267
- return (jsxs("ul", __assign({ role: "menu", "aria-label": ariaLabel }, mergeProps({ onKeyDown: onKeyDown, onAnimationEnd: onAnimationEnd }, restProps), commonProps(isDisabled), { ref: useCombinedRef(externalRef, menuRef), className: useBEM({ block: menuClass, modifiers: modifiers, className: menuClassName }), style: __assign(__assign(__assign(__assign({}, menuStyle), overflowStyle), dontShrinkOps), { margin: 0, display: state === "closed" ? "none" : undefined, position: "absolute", left: menuPosition.x, top: menuPosition.y }) }, { children: [jsx("div", { ref: focusRef, tabIndex: -1, style: { position: "absolute", left: 0, top: 0 } }), arrow && (jsx("div", { className: _arrowClass, style: __assign(__assign({}, arrowStyle), { position: "absolute", left: arrowPosition.x, top: arrowPosition.y }), ref: arrowRef })), jsx(MenuListContext.Provider, __assign({ value: listContext }, { children: jsx(MenuListItemContext.Provider, __assign({ value: itemContext }, { children: jsx(HoverItemContext.Provider, __assign({ value: hoverItem }, { children: children })) })) }))] })));
2410
+ return (jsxs("ul", __assign({ role: "menu", "aria-label": ariaLabel }, mergeProps({ onKeyDown: onKeyDown, onAnimationEnd: onAnimationEnd }, restProps), commonProps(isDisabled), { ref: useCombinedRef(externalRef, menuRef), className: useBEM({ block: menuClass, modifiers: modifiers, className: menuClassName }), style: __assign(__assign(__assign(__assign({}, menuStyle), overflowStyle), dontShrinkOps), { margin: 0, display: state === "closed" ? "none" : undefined, position: "absolute", left: menuPosition.x, top: menuPosition.y }) }, { children: [jsx("div", { ref: focusRef, tabIndex: -1, style: { position: "absolute", left: 0, top: 0 }, onKeyDown: function (event) {
2411
+ if (event.key == "Tab") {
2412
+ event.preventDefault();
2413
+ event.stopPropagation();
2414
+ safeCall(onClose, {
2415
+ key: event.key,
2416
+ shiftKey: event.shiftKey,
2417
+ reason: event.key === "Tab"
2418
+ ? event.shiftKey
2419
+ ? CloseReason.TAB_BACKWARD
2420
+ : CloseReason.TAB_FORWARD
2421
+ : CloseReason.CLICK
2422
+ });
2423
+ }
2424
+ } }), arrow && (jsx("div", { className: _arrowClass, style: __assign(__assign({}, arrowStyle), { position: "absolute", left: arrowPosition.x, top: arrowPosition.y }), ref: arrowRef })), jsx(MenuListContext.Provider, __assign({ value: listContext }, { children: jsx(MenuListItemContext.Provider, __assign({ value: itemContext }, { children: jsx(HoverItemContext.Provider, __assign({ value: hoverItem }, { children: children })) })) }))] })));
2268
2425
  };
2269
2426
 
2270
2427
  var ControlledMenuFr = function (_a, externalRef) {
@@ -3339,10 +3496,10 @@ var textMatch = function (text, filter) {
3339
3496
  };
3340
3497
 
3341
3498
  var useGridPopoverHook = function (props) {
3342
- var stopEditing = useContext(GridContext).stopEditing;
3343
- var _a = useGridPopoverContext(), anchorRef = _a.anchorRef, saving = _a.saving, updateValue = _a.updateValue;
3499
+ var _a = useContext(GridContext), stopEditing = _a.stopEditing, cancelEdit = _a.cancelEdit;
3500
+ var _b = useGridPopoverContext(), anchorRef = _b.anchorRef, saving = _b.saving, updateValue = _b.updateValue;
3344
3501
  var saveButtonRef = useRef(null);
3345
- var _b = useState(false), isOpen = _b[0], setOpen = _b[1];
3502
+ var _c = useState(false), isOpen = _c[0], setOpen = _c[1];
3346
3503
  useEffect(function () {
3347
3504
  setOpen(true);
3348
3505
  }, []);
@@ -3351,14 +3508,14 @@ var useGridPopoverHook = function (props) {
3351
3508
  switch (_a.label) {
3352
3509
  case 0:
3353
3510
  if (reason == CloseReason.CANCEL) {
3354
- stopEditing();
3511
+ cancelEdit();
3355
3512
  return [2 /*return*/];
3356
3513
  }
3357
3514
  if (props.invalid && props.invalid()) {
3358
3515
  return [2 /*return*/];
3359
3516
  }
3360
3517
  if (!!props.save) return [3 /*break*/, 1];
3361
- stopEditing();
3518
+ cancelEdit();
3362
3519
  return [3 /*break*/, 3];
3363
3520
  case 1:
3364
3521
  if (!props.save) return [3 /*break*/, 3];
@@ -3375,7 +3532,7 @@ var useGridPopoverHook = function (props) {
3375
3532
  case 3: return [2 /*return*/];
3376
3533
  }
3377
3534
  });
3378
- }); }, [props, stopEditing, updateValue]);
3535
+ }); }, [cancelEdit, props, stopEditing, updateValue]);
3379
3536
  var popoverWrapper = useCallback(function (children) {
3380
3537
  return (jsx(Fragment, { children: anchorRef.current && (jsxs(ControlledMenu, __assign({ state: isOpen ? "open" : "closed", portal: true, unmountOnClose: true, anchorRef: anchorRef, saveButtonRef: saveButtonRef, menuClassName: "step-ag-grid-react-menu", onClose: function (event) {
3381
3538
  // Prevent menu from closing when modals are invoked
@@ -3465,15 +3622,7 @@ var GridFormDropDown = function (props) {
3465
3622
  }
3466
3623
  : item;
3467
3624
  });
3468
- if (props.filtered) {
3469
- // This is needed otherwise when filter input is rendered and sets autofocus
3470
- // the mouse up of the double click edit triggers the cell to cancel editing
3471
- setOptions(optionsList);
3472
- //delay(() => setOptions(optionsList), 100);
3473
- }
3474
- else {
3475
- setOptions(optionsList);
3476
- }
3625
+ setOptions(optionsList);
3477
3626
  }
3478
3627
  return [2 /*return*/];
3479
3628
  }
@@ -4401,7 +4550,7 @@ var GridPopoverMenu = function (colDef, custom) {
4401
4550
  return GridCell(__assign(__assign({ minWidth: 48, maxWidth: 48, width: 40, editable: colDef.editable != null ? colDef.editable : true, exportable: false, cellStyle: { flex: 1, justifyContent: "center" }, cellRenderer: GridRenderPopoutMenuCell }, colDef), { cellRendererParams: {
4402
4551
  // Menus open on single click, this parameter is picked up in Grid.tsx
4403
4552
  singleClickEdit: true
4404
- } }), __assign({ editor: GridFormPopoverMenu }, custom));
4553
+ } }), __assign({ editor: GridFormPopoverMenu, preventAutoEdit: true }, custom));
4405
4554
  };
4406
4555
 
4407
4556
  var GridPopoverEditBearingLike = function (colDef, props) {
@@ -4493,14 +4642,14 @@ var GridContextProvider = function (props) {
4493
4642
  * @return true if row is found, else false
4494
4643
  */
4495
4644
  var ensureRowVisible = useCallback(function (id) {
4496
- return gridApiOp(function (gridApi) {
4497
- var node = gridApi.getRowNode("".concat(id));
4498
- if (!node)
4499
- return false;
4500
- gridApi.ensureNodeVisible(node);
4501
- return true;
4502
- });
4503
- }, [gridApiOp]);
4645
+ if (!gridApi)
4646
+ return false;
4647
+ var node = gridApi === null || gridApi === void 0 ? void 0 : gridApi.getRowNode("".concat(id));
4648
+ if (!node)
4649
+ return false;
4650
+ defer$1(function () { return gridApi.ensureNodeVisible(node); });
4651
+ return true;
4652
+ }, [gridApi]);
4504
4653
  var getFirstRowId = useCallback(function () {
4505
4654
  var id = 0;
4506
4655
  try {
@@ -4612,17 +4761,16 @@ var GridContextProvider = function (props) {
4612
4761
  var rowsThatNeedSelecting = sortBy(rowNodes.filter(function (node) { return !node.isSelected(); }), function (node) { return node.data.id; });
4613
4762
  var firstNode = rowsThatNeedSelecting[0];
4614
4763
  if (firstNode) {
4615
- gridApi.ensureNodeVisible(firstNode);
4764
+ defer$1(function () { return gridApi.ensureNodeVisible(firstNode); });
4616
4765
  var colDefs = gridApi.getColumnDefs();
4617
- if (colDefs && colDefs.length) {
4766
+ if (colDefs === null || colDefs === void 0 ? void 0 : colDefs.length) {
4618
4767
  var col = colDefs[0]; // We don't support ColGroupDef
4619
4768
  var rowIndex_1 = firstNode.rowIndex;
4620
4769
  if (rowIndex_1 != null && col != null) {
4621
4770
  var colId_1 = col.colId;
4622
4771
  // We need to make sure we aren't currently editing a cell otherwise tests will fail
4623
4772
  // as they will start to edit the cell before this stuff has a chance to run
4624
- colId_1 != null &&
4625
- defer$1(function () { return isEmpty(gridApi.getEditingCells()) && gridApi.setFocusedCell(rowIndex_1, colId_1); });
4773
+ colId_1 && defer$1(function () { return isEmpty(gridApi.getEditingCells()) && gridApi.setFocusedCell(rowIndex_1, colId_1); });
4626
4774
  }
4627
4775
  }
4628
4776
  }
@@ -4717,43 +4865,97 @@ var GridContextProvider = function (props) {
4717
4865
  var selectedNodes = gridApi.getSelectedNodes();
4718
4866
  if (isEmpty(selectedNodes))
4719
4867
  return;
4720
- gridApi.ensureNodeVisible(last(selectedNodes));
4868
+ defer$1(function () { return gridApi.ensureNodeVisible(last(selectedNodes)); });
4721
4869
  });
4722
4870
  }, [gridApiOp]);
4723
4871
  /**
4724
4872
  * Resize columns to fit container
4725
4873
  */
4726
- var autoSizeAllColumns = useCallback(function (_a) {
4727
- var skipHeader = _a.skipHeader;
4728
- if (columnApi) {
4729
- columnApi.autoSizeAllColumns(skipHeader);
4730
- return { width: sumBy(columnApi.getColumnState(), "width") };
4731
- }
4732
- return null;
4874
+ var autoSizeColumns = useCallback(function (_a) {
4875
+ var _b = _a === void 0 ? {} : _a, skipHeader = _b.skipHeader, colIds = _b.colIds, userSizedColIds = _b.userSizedColIds;
4876
+ if (!columnApi)
4877
+ return null;
4878
+ var colIdsSet = colIds instanceof Set ? colIds : new Set(colIds !== null && colIds !== void 0 ? colIds : []);
4879
+ columnApi.getColumnState().forEach(function (col) {
4880
+ var colId = col.colId;
4881
+ if ((isEmpty(colIdsSet) || colIdsSet.has(colId)) && !(userSizedColIds === null || userSizedColIds === void 0 ? void 0 : userSizedColIds.has(colId))) {
4882
+ columnApi.autoSizeColumn(colId, skipHeader);
4883
+ }
4884
+ });
4885
+ return {
4886
+ width: sumBy(columnApi.getColumnState().filter(function (col) { return !col.hide; }), "width")
4887
+ };
4733
4888
  }, [columnApi]);
4734
4889
  /**
4735
4890
  * Resize columns to fit container
4736
4891
  */
4737
4892
  var sizeColumnsToFit = useCallback(function () {
4738
- if (gridApi) {
4739
- gridApi.sizeColumnsToFit();
4740
- }
4893
+ gridApi && gridApi.sizeColumnsToFit();
4741
4894
  }, [gridApi]);
4742
4895
  var stopEditing = useCallback(function () {
4896
+ if (!gridApi)
4897
+ return;
4743
4898
  if (prePopupFocusedCell.current) {
4744
4899
  gridApi === null || gridApi === void 0 ? void 0 : gridApi.setFocusedCell(prePopupFocusedCell.current.rowIndex, prePopupFocusedCell.current.column);
4745
4900
  }
4746
- gridApiOp(function (gridApi) { return gridApi.stopEditing(); });
4747
- }, [gridApi, gridApiOp]);
4748
- var selectNextCell = useCallback(function (tabDirection) {
4749
- if (tabDirection === void 0) { tabDirection = 0; }
4750
- gridApiOp(function (gridApi) {
4751
- if (tabDirection == 1)
4752
- gridApi.tabToNextCell();
4753
- if (tabDirection == -1)
4754
- gridApi.tabToPreviousCell();
4755
- });
4756
- }, [gridApiOp]);
4901
+ gridApi.stopEditing();
4902
+ }, [gridApi]);
4903
+ /**
4904
+ * This differs from stopEdit in that it will also invoke cellEditingCompleteCallback
4905
+ */
4906
+ var cancelEdit = useCallback(function () {
4907
+ stopEditing();
4908
+ cellEditingCompleteCallbackRef.current && cellEditingCompleteCallbackRef.current();
4909
+ }, [stopEditing]);
4910
+ var cellEditingCompleteCallbackRef = useRef();
4911
+ var setOnCellEditingComplete = useCallback(function (cellEditingCompleteCallback) {
4912
+ cellEditingCompleteCallbackRef.current = cellEditingCompleteCallback;
4913
+ }, []);
4914
+ /**
4915
+ * Returns true if an editable cell on same row was selected, else false.
4916
+ */
4917
+ var selectNextEditableCell = useCallback(function (tabDirection) {
4918
+ // Pretend it succeeded to prevent unwanted cellEditingCompleteCallback
4919
+ if (!gridApi)
4920
+ return true;
4921
+ var focusedCellIsEditable = function () {
4922
+ var _a, _b;
4923
+ var focusedCell = gridApi.getFocusedCell();
4924
+ var nextColumn = focusedCell === null || focusedCell === void 0 ? void 0 : focusedCell.column;
4925
+ var nextColDef = nextColumn === null || nextColumn === void 0 ? void 0 : nextColumn.getColDef();
4926
+ var rowNode = focusedCell && gridApi.getDisplayedRowAtIndex(focusedCell === null || focusedCell === void 0 ? void 0 : focusedCell.rowIndex);
4927
+ return (!!(rowNode && nextColumn && nextColDef) &&
4928
+ nextColumn.isCellEditable(rowNode) &&
4929
+ !((_a = nextColDef.cellEditorParams) === null || _a === void 0 ? void 0 : _a.preventAutoEdit) &&
4930
+ !((_b = nextColDef.cellRendererParams) === null || _b === void 0 ? void 0 : _b.editAction));
4931
+ };
4932
+ var foundEditableCell = false;
4933
+ // Just in case I've missed something, we don't want the loop to hang everything
4934
+ var maxIterations = 50;
4935
+ var preRow = null;
4936
+ var postRow = null;
4937
+ do {
4938
+ preRow = gridApi.getFocusedCell();
4939
+ tabDirection === 1 ? gridApi.tabToNextCell() : gridApi.tabToPreviousCell();
4940
+ postRow = gridApi.getFocusedCell();
4941
+ foundEditableCell = focusedCellIsEditable();
4942
+ } while ((preRow === null || preRow === void 0 ? void 0 : preRow.rowIndex) === (postRow === null || postRow === void 0 ? void 0 : postRow.rowIndex) &&
4943
+ (preRow === null || preRow === void 0 ? void 0 : preRow.column) !== (postRow === null || postRow === void 0 ? void 0 : postRow.column) &&
4944
+ !foundEditableCell &&
4945
+ maxIterations-- > 0);
4946
+ if (foundEditableCell) {
4947
+ prePopupOps();
4948
+ var focusedCell = gridApi === null || gridApi === void 0 ? void 0 : gridApi.getFocusedCell();
4949
+ if (focusedCell) {
4950
+ gridApi.startEditingCell({
4951
+ rowIndex: focusedCell.rowIndex,
4952
+ colKey: focusedCell.column.getColId()
4953
+ });
4954
+ return false;
4955
+ }
4956
+ }
4957
+ return true;
4958
+ }, [gridApi, prePopupOps]);
4757
4959
  var updatingCells = useCallback(function (props, fnUpdate, setSaving, tabDirection) { return __awaiter(void 0, void 0, void 0, function () {
4758
4960
  return __generator(this, function (_a) {
4759
4961
  switch (_a.label) {
@@ -4800,12 +5002,13 @@ var GridContextProvider = function (props) {
4800
5002
  setSaving && setSaving(false);
4801
5003
  }
4802
5004
  postPopupFocusedCell = gridApi.getFocusedCell();
4803
- if (tabDirection &&
4804
- prePopupFocusedCell.current &&
5005
+ if (prePopupFocusedCell.current &&
4805
5006
  postPopupFocusedCell &&
4806
5007
  prePopupFocusedCell.current.rowIndex == postPopupFocusedCell.rowIndex &&
4807
5008
  prePopupFocusedCell.current.column.getColId() == postPopupFocusedCell.column.getColId()) {
4808
- selectNextCell(tabDirection);
5009
+ if (!tabDirection || selectNextEditableCell(tabDirection)) {
5010
+ cellEditingCompleteCallbackRef.current && cellEditingCompleteCallbackRef.current();
5011
+ }
4809
5012
  }
4810
5013
  return [2 /*return*/, ok];
4811
5014
  }
@@ -4814,7 +5017,7 @@ var GridContextProvider = function (props) {
4814
5017
  case 1: return [2 /*return*/, _a.sent()];
4815
5018
  }
4816
5019
  });
4817
- }); }, [gridApiOp, modifyUpdating, selectNextCell]);
5020
+ }); }, [gridApiOp, modifyUpdating, selectNextEditableCell]);
4818
5021
  var redrawRows = useCallback(function (rowNodes) {
4819
5022
  gridApiOp(function (gridApi) {
4820
5023
  gridApi.redrawRows(rowNodes ? { rowNodes: rowNodes } : undefined);
@@ -4907,8 +5110,9 @@ var GridContextProvider = function (props) {
4907
5110
  ensureRowVisible: ensureRowVisible,
4908
5111
  ensureSelectedRowIsVisible: ensureSelectedRowIsVisible,
4909
5112
  sizeColumnsToFit: sizeColumnsToFit,
4910
- autoSizeAllColumns: autoSizeAllColumns,
5113
+ autoSizeColumns: autoSizeColumns,
4911
5114
  stopEditing: stopEditing,
5115
+ cancelEdit: cancelEdit,
4912
5116
  updatingCells: updatingCells,
4913
5117
  redrawRows: redrawRows,
4914
5118
  externallySelectedItemsAreInSync: externallySelectedItemsAreInSync,
@@ -4918,7 +5122,8 @@ var GridContextProvider = function (props) {
4918
5122
  removeExternalFilter: removeExternalFilter,
4919
5123
  isExternalFilterPresent: isExternalFilterPresent,
4920
5124
  doesExternalFilterPass: doesExternalFilterPass,
4921
- downloadCsv: downloadCsv
5125
+ downloadCsv: downloadCsv,
5126
+ setOnCellEditingComplete: setOnCellEditingComplete
4922
5127
  } }, { children: props.children })));
4923
5128
  };
4924
5129
  /**
@@ -4958,6 +5163,7 @@ var downloadCsvUseValueFormattersProcessCellCallback = function (params) {
4958
5163
  return encodeToString(params.value);
4959
5164
  }
4960
5165
  var result = valueFormatter(__assign(__assign({}, params), { data: (_b = params.node) === null || _b === void 0 ? void 0 : _b.data, colDef: colDef }));
5166
+ // type may not be string due to casting, leave the type check in
4961
5167
  if (params.value != null && typeof result !== "string") {
4962
5168
  console.error("downloadCsv: valueFormatter is returning non string values, colDef:\", colId: ".concat(colDef.colId));
4963
5169
  }
@@ -4972,11 +5178,15 @@ var GridUpdatingContextProvider = function (props) {
4972
5178
  var resetUpdating = function () {
4973
5179
  var mergedUpdatingBlocks = {};
4974
5180
  for (var key in updatingBlocks.current) {
4975
- mergedUpdatingBlocks[key] = flatten(updatingBlocks.current[key]);
5181
+ var arr = flatten(updatingBlocks.current[key]);
5182
+ if (arr.length) {
5183
+ mergedUpdatingBlocks[key] = arr;
5184
+ }
4976
5185
  }
4977
5186
  updating.current = mergedUpdatingBlocks;
4978
5187
  setUpdatedDep(function (updatedDep) { return updatedDep + 1; });
4979
5188
  };
5189
+ var isUpdating = function () { return !isEmpty(updating.current); };
4980
5190
  var modifyUpdating = function (fields, ids, fn) { return __awaiter(void 0, void 0, void 0, function () {
4981
5191
  var idRef;
4982
5192
  return __generator(this, function (_a) {
@@ -5004,7 +5214,7 @@ var GridUpdatingContextProvider = function (props) {
5004
5214
  var checkUpdating = function (fields, id) {
5005
5215
  return castArray(fields).some(function (f) { var _a; return (_a = updating.current[f]) === null || _a === void 0 ? void 0 : _a.includes(id); });
5006
5216
  };
5007
- return (jsx(GridUpdatingContext.Provider, __assign({ value: { modifyUpdating: modifyUpdating, checkUpdating: checkUpdating, updatedDep: updatedDep } }, { children: props.children })));
5217
+ return (jsx(GridUpdatingContext.Provider, __assign({ value: { modifyUpdating: modifyUpdating, checkUpdating: checkUpdating, isUpdating: isUpdating, updatedDep: updatedDep } }, { children: props.children })));
5008
5218
  };
5009
5219
 
5010
5220
  var css_248z = ".ActionButton{align-items:center;display:flex}.ActionButton-minimal.lui-button-lg.lui-button-icon-right{padding-right:38px}.ActionButton.lui-button-lg.lui-button-icon-right:not(.ActionButton-tight) .LuiIcon{margin:0 4px}.ActionButton.ActionButton-tight.lui-button-lg.lui-button-icon-right .LuiIcon{margin:0}.ActionButton-iconOnly.lui-button-lg.lui-button-icon-right:not(.ActionButton-tight){padding:8px 5px}.ActionButton-iconOnly.lui-button-lg.lui-button-icon-right.ActionButton-tight{padding:0}.ActionButton-minimalArea{position:relative}.ActionButton-minimalAreaDisplay{position:absolute}.ActionButton-minimalAreaExpand{visibility:hidden}.ActionButton-inProgress.lui-button-lg.lui-button-icon-right{background-color:#e2f3f7;color:#007198;cursor:progress}.ActionButton-inProgress.lui-button-lg.lui-button-icon-right svg *{fill:#0000}.ActionButton-fill{justify-content:center;width:100%}";