@linzjs/step-ag-grid 29.1.5 → 29.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.
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": "29.1.5",
5
+ "version": "29.2.0",
6
6
  "keywords": [
7
7
  "aggrid",
8
8
  "ag-grid",
@@ -142,6 +142,7 @@ export const Grid = <TData extends GridBaseRow = GridBaseRow>({
142
142
  rowData,
143
143
  rowHeight = theme === 'ag-theme-step-default' ? 40 : theme === 'ag-theme-step-compact' ? 36 : 40,
144
144
  selectable,
145
+ onCellFocused: paramsOnCellFocused,
145
146
  ...params
146
147
  }: GridProps<TData>): ReactElement => {
147
148
  const {
@@ -237,11 +238,29 @@ export const Grid = <TData extends GridBaseRow = GridBaseRow>({
237
238
  }, [autoSizeColumns, gridRenderState, params, rowData, sizeColumns, sizeColumnsToFit]);
238
239
 
239
240
  const lastOwnerDocumentRef = useRef<Document>();
241
+ const wasVisibleRef = useRef(false);
240
242
 
241
243
  /**
242
244
  * Auto-size windows that had deferred auto-size
245
+ * Reset focus if panel went from invisible to visible.
243
246
  */
244
247
  useInterval(() => {
248
+ // If grid has become visible after previously being hidden, then refocus the last focused cell.
249
+ const visible = !!gridDivRef.current?.checkVisibility();
250
+ if (visible && !wasVisibleRef.current) {
251
+ wasVisibleRef.current = true;
252
+ const el = (window as any).__stepaggrid_lastfocuseventtarget;
253
+ if (el) {
254
+ // Setting this to null will cause a new refocus event
255
+ (window as any).__stepaggrid_lastfocuseventtarget = null;
256
+ // Check element is still part of document
257
+ if (el.checkVisibility()) {
258
+ el.focus();
259
+ }
260
+ }
261
+ }
262
+ wasVisibleRef.current = visible;
263
+
245
264
  // Check if window has been popped out and needs resize
246
265
  const currentDocument = gridDivRef.current?.ownerDocument;
247
266
  if (currentDocument !== lastOwnerDocumentRef.current) {
@@ -450,7 +469,6 @@ export const Grid = <TData extends GridBaseRow = GridBaseRow>({
450
469
  const invokeEditAction = (e: CellDoubleClickedEvent | CellKeyDownEvent): boolean => {
451
470
  const editAction = e.colDef?.cellRendererParams?.editAction;
452
471
  if (!editAction) return false;
453
-
454
472
  const editable = fnOrVar(e.colDef?.editable, e);
455
473
  if (editable) {
456
474
  if (!e.node.isSelected()) {
@@ -625,7 +643,7 @@ export const Grid = <TData extends GridBaseRow = GridBaseRow>({
625
643
 
626
644
  const onCellFocused = useCallback(
627
645
  (event: CellFocusedEvent<TData>) => {
628
- if (!params.onCellFocused || event.rowIndex == null) {
646
+ if (event.rowIndex == null) {
629
647
  return;
630
648
  }
631
649
  const api = event.api;
@@ -639,9 +657,19 @@ export const Grid = <TData extends GridBaseRow = GridBaseRow>({
639
657
  if (!colDef || typeof colDef === 'string') {
640
658
  return;
641
659
  }
642
- params.onCellFocused({ colDef, data });
660
+ // Prevent repeated callbacks to cell focus when focus didn't change
661
+ const { sourceEvent } = event;
662
+ if (sourceEvent) {
663
+ const cell = (sourceEvent.target as unknown as Element).closest('.ag-cell');
664
+ if ((window as any).__stepaggrid_lastfocuseventtarget === cell) {
665
+ return;
666
+ }
667
+ (window as any).__stepaggrid_lastfocuseventtarget = cell;
668
+ }
669
+
670
+ paramsOnCellFocused?.({ colDef, data });
643
671
  },
644
- [params],
672
+ [paramsOnCellFocused],
645
673
  );
646
674
 
647
675
  const onRowDragEnd = useCallback(
@@ -812,6 +840,7 @@ export const Grid = <TData extends GridBaseRow = GridBaseRow>({
812
840
  pinnedBottomRowData={params.pinnedBottomRowData}
813
841
  onRowClicked={params.onRowClicked}
814
842
  onRowDoubleClicked={params.onRowDoubleClicked}
843
+ suppressStartEditOnTab={true}
815
844
  />
816
845
  </div>
817
846
  </div>
@@ -11,8 +11,7 @@ import {
11
11
  ValueFormatterParams,
12
12
  ValueGetterFunc,
13
13
  } from 'ag-grid-community';
14
- import { defer } from 'lodash-es';
15
- import { forwardRef, ReactElement, useContext, useEffect } from 'react';
14
+ import { forwardRef, ReactElement, useContext } from 'react';
16
15
 
17
16
  import { GridPopoverContextProvider } from '../contexts/GridPopoverContextProvider';
18
17
  import { GridUpdatingContext } from '../contexts/GridUpdatingContext';
@@ -155,14 +154,10 @@ export const GridCell = <TData extends GridBaseRow, TValue = any, Props extends
155
154
  resizable: true,
156
155
  valueSetter: custom?.editor ? blockValueSetter : undefined,
157
156
  editable: props.editable ?? !!custom?.editor,
158
- ...(custom?.editor
159
- ? {
160
- cellClassRules: GridCellMultiSelectClassRules,
161
- cellEditor: GenericCellEditorComponentWrapper(custom?.editor),
162
- }
163
- : {
164
- cellEditor: CellEditorToBlockEditing,
165
- }),
157
+ ...(custom?.editor && {
158
+ cellClassRules: GridCellMultiSelectClassRules,
159
+ cellEditor: GenericCellEditorComponentWrapper(custom?.editor),
160
+ }),
166
161
  suppressKeyboardEvent: suppressCellKeyboardEvents,
167
162
  ...(custom?.editorParams
168
163
  ? {
@@ -190,20 +185,6 @@ export const GridCell = <TData extends GridBaseRow, TValue = any, Props extends
190
185
  };
191
186
  };
192
187
 
193
- /**
194
- * Ag-grid will start its own editor if editable is true and there is no cell editor
195
- * like in the case of a cell that is editable because it triggers a modal.
196
- * This will block that editor.
197
- */
198
- const CellEditorToBlockEditing = ({ stopEditing }: { stopEditing: () => void }) => {
199
- useEffect(() => {
200
- defer(() => {
201
- stopEditing();
202
- });
203
- }, [stopEditing]);
204
- return <></>;
205
- };
206
-
207
188
  export interface CellEditorCommon {
208
189
  className?: string | undefined;
209
190
  }
@@ -15,6 +15,11 @@ export interface AutoSizeColumnsProps {
15
15
 
16
16
  export type AutoSizeColumnsResult = { width: number } | null;
17
17
 
18
+ export interface StartCellEditingProps {
19
+ rowId: number;
20
+ colId: string;
21
+ }
22
+
18
23
  export interface GridContextType<TData extends GridBaseRow> {
19
24
  gridReady: boolean;
20
25
  gridRenderState: () => null | 'empty' | 'rows-visible';
@@ -43,7 +48,7 @@ export interface GridContextType<TData extends GridBaseRow> {
43
48
  getFirstRowId: () => number;
44
49
  autoSizeColumns: (props?: AutoSizeColumnsProps) => AutoSizeColumnsResult;
45
50
  sizeColumnsToFit: () => void;
46
- startCellEditing: ({ rowId, colId }: { rowId: number; colId: string }) => Promise<void>;
51
+ startCellEditing: ({ rowId, colId }: StartCellEditingProps) => Promise<void>;
47
52
  // Restores the previous focus after cell editing
48
53
  resetFocusedCellAfterCellEditing: () => void;
49
54
  updatingCells: (
@@ -596,11 +596,9 @@ export const GridContextProvider = <TData extends GridBaseRow>(props: PropsWithC
596
596
  const preRow = gridApi.getFocusedCell();
597
597
  // If we don't do this ag-grid will do its own continuation of an edit on tab, we don't want that as
598
598
  // we are managing it ourselves
599
- gridApi.stopEditing();
600
- if (tabDirection === 1) {
601
- gridApi.tabToNextCell();
602
- } else {
603
- gridApi.tabToPreviousCell();
599
+ const didTab = tabDirection === 1 ? gridApi.tabToNextCell() : gridApi.tabToPreviousCell();
600
+ if (!didTab) {
601
+ break;
604
602
  }
605
603
 
606
604
  if (gridApi.isDestroyed()) {
@@ -275,13 +275,11 @@ GridKeyboardInteractions.play = async ({ canvasElement }) => {
275
275
  await test(() => userEvent.keyboard('{Enter}'), '8', '2');
276
276
  expect(multiEditAction).toHaveBeenCalled();
277
277
 
278
- console.log('Open 2nd to last popup menu, tab to next disabled popup');
279
- await test(() => userEvent.tab(), '9', '2');
278
+ console.log('Open 2nd to last popup menu, tab to next disabled popup should fail');
279
+ await test(() => userEvent.tab(), '8', '2');
280
280
  expect(bulkEditingCallback).toHaveBeenCalled();
281
281
  bulkEditingCallback.mockClear();
282
282
 
283
- console.log('Fail to edit last popup menu, tab back to 2nd to last popup menu');
284
- await userEvent.tab({ shift: true });
285
283
  console.log('Open 2nd to last popup menu, tab to desc cell');
286
284
  await test(() => userEvent.tab({ shift: true }), '5', '2');
287
285
  console.log('Cancel edit');
@@ -312,9 +310,9 @@ GridKeyboardInteractions.play = async ({ canvasElement }) => {
312
310
  await userEvent.tab();
313
311
 
314
312
  expect(eAction).not.toHaveBeenCalled();
315
- /*await userEvent.keyboard('{Enter}');
313
+ await userEvent.keyboard('{Enter}');
316
314
  await userEvent.keyboard('e');
317
315
  await waitFor(() => {
318
316
  expect(eAction).toHaveBeenCalled();
319
- });*/
317
+ });
320
318
  };