@linzjs/step-ag-grid 29.1.1 → 29.1.3

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.
Files changed (32) hide show
  1. package/dist/src/components/Grid.d.ts +1 -1
  2. package/dist/src/components/GridPopoverHook.d.ts +2 -1
  3. package/dist/src/contexts/GridContext.d.ts +2 -2
  4. package/dist/src/index.d.ts +1 -0
  5. package/dist/src/utils/waitForCondition.d.ts +1 -0
  6. package/dist/step-ag-grid.cjs +89 -65
  7. package/dist/step-ag-grid.cjs.map +1 -1
  8. package/dist/step-ag-grid.esm.js +88 -66
  9. package/dist/step-ag-grid.esm.js.map +1 -1
  10. package/package.json +1 -1
  11. package/src/components/Grid.tsx +1 -1
  12. package/src/components/GridCell.tsx +34 -14
  13. package/src/components/GridPopoverHook.tsx +16 -17
  14. package/src/components/gridForm/GridFormDropDown.tsx +10 -3
  15. package/src/components/gridForm/GridFormMultiSelect.tsx +12 -4
  16. package/src/components/gridPopoverEdit/GridPopoverMessage.ts +1 -0
  17. package/src/contexts/GridContext.tsx +2 -2
  18. package/src/contexts/GridContextProvider.tsx +41 -37
  19. package/src/index.ts +1 -0
  20. package/src/stories/grid/GridPopoutEditGeneric.stories.tsx +1 -1
  21. package/src/stories/grid/GridPopoverEditMultiSelect.stories.tsx +1 -1
  22. package/src/stories/grid/GridPopoverEditMultiSelectGrid.stories.tsx +1 -1
  23. package/src/stories/grid/gridFormInteraction/GridFormDropDownInteraction.stories.tsx +4 -12
  24. package/src/stories/grid/gridFormInteraction/GridFormEditBearingCorrectionInteraction.stories.tsx +5 -11
  25. package/src/stories/grid/gridFormInteraction/GridFormEditBearingInteraction.stories.tsx +4 -11
  26. package/src/stories/grid/gridFormInteraction/GridFormMultiSelectGridInteraction.stories.tsx +8 -10
  27. package/src/stories/grid/gridFormInteraction/GridFormMultiSelectInteraction.stories.tsx +5 -11
  28. package/src/stories/grid/gridFormInteraction/GridFormPopoverMenuInteraction.stories.tsx +5 -12
  29. package/src/stories/grid/gridFormInteraction/GridFormTextAreaInteraction.stories.tsx +4 -11
  30. package/src/stories/grid/gridFormInteraction/GridFormTextInputInteraction.stories.tsx +4 -11
  31. package/src/stories/grid/interactions/GridKeyboardInteractions.stories.tsx +56 -13
  32. package/src/utils/waitForCondition.tsx +17 -0
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.1",
5
+ "version": "29.1.3",
6
6
  "keywords": [
7
7
  "aggrid",
8
8
  "ag-grid",
@@ -101,7 +101,7 @@ export interface GridProps<TData extends GridBaseRow = GridBaseRow> {
101
101
  * When pressing tab whilst editing the grid will select and edit the next cell if available.
102
102
  * Once the last cell to edit closes this callback is called.
103
103
  */
104
- onBulkEditingComplete?: () => void;
104
+ onBulkEditingComplete?: () => Promise<void> | void;
105
105
 
106
106
  /**
107
107
  * Context menu definition if required.
@@ -11,7 +11,8 @@ import {
11
11
  ValueFormatterParams,
12
12
  ValueGetterFunc,
13
13
  } from 'ag-grid-community';
14
- import { forwardRef, ReactElement, useContext } from 'react';
14
+ import { defer } from 'lodash-es';
15
+ import { forwardRef, ReactElement, useContext, useEffect } from 'react';
15
16
 
16
17
  import { GridPopoverContextProvider } from '../contexts/GridPopoverContextProvider';
17
18
  import { GridUpdatingContext } from '../contexts/GridUpdatingContext';
@@ -153,20 +154,25 @@ export const GridCell = <TData extends GridBaseRow, TValue = any, Props extends
153
154
  sortable: true,
154
155
  resizable: true,
155
156
  valueSetter: custom?.editor ? blockValueSetter : undefined,
156
- editable: props.editable ?? false,
157
- ...(custom?.editor && {
158
- cellClassRules: GridCellMultiSelectClassRules,
159
- editable: props.editable ?? true,
160
- cellEditor: GenericCellEditorComponentWrapper(custom?.editor),
161
- }),
157
+ editable: props.editable ?? !!custom?.editor,
158
+ ...(custom?.editor
159
+ ? {
160
+ cellClassRules: GridCellMultiSelectClassRules,
161
+ cellEditor: GenericCellEditorComponentWrapper(custom?.editor),
162
+ }
163
+ : {
164
+ cellEditor: CellEditorToBlockEditing,
165
+ }),
162
166
  suppressKeyboardEvent: suppressCellKeyboardEvents,
163
- ...(custom?.editorParams && {
164
- cellEditorParams: {
165
- ...custom.editorParams,
166
- multiEdit: custom.multiEdit,
167
- preventAutoEdit: custom.preventAutoEdit ?? false,
168
- },
169
- }),
167
+ ...(custom?.editorParams
168
+ ? {
169
+ cellEditorParams: {
170
+ ...custom.editorParams,
171
+ multiEdit: custom.multiEdit,
172
+ preventAutoEdit: custom.preventAutoEdit ?? !custom?.editor,
173
+ },
174
+ }
175
+ : { cellEditorParams: { preventAutoEdit: !custom?.editor } }),
170
176
  // If there's a valueFormatter and no filterValueGetter then create a filterValueGetter
171
177
  getQuickFilterText: filterValueGetter as any,
172
178
  // Default value formatter, otherwise react freaks out on objects
@@ -184,6 +190,20 @@ export const GridCell = <TData extends GridBaseRow, TValue = any, Props extends
184
190
  };
185
191
  };
186
192
 
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
+
187
207
  export interface CellEditorCommon {
188
208
  className?: string | undefined;
189
209
  }
@@ -1,6 +1,5 @@
1
1
  import { ReactElement, useCallback, useEffect, useRef, useState } from 'react';
2
2
 
3
- import { useGridContext } from '../contexts/GridContext';
4
3
  import { useGridPopoverContext } from '../contexts/GridPopoverContext';
5
4
  import { ControlledMenu } from '../react-menu3';
6
5
  import { MenuCloseEvent } from '../react-menu3/types';
@@ -20,8 +19,14 @@ export interface GridPopoverHookProps<TData> {
20
19
  dontSaveOnExternalClick?: boolean;
21
20
  }
22
21
 
23
- export const useGridPopoverHook = <TData extends GridBaseRow>(props: GridPopoverHookProps<TData>) => {
24
- const { onBulkEditingComplete } = useGridContext<TData>();
22
+ export const CancelPromise = () => Promise.resolve(true);
23
+
24
+ export const useGridPopoverHook = <TData extends GridBaseRow>({
25
+ className,
26
+ save,
27
+ invalid,
28
+ dontSaveOnExternalClick,
29
+ }: GridPopoverHookProps<TData>) => {
25
30
  const { anchorRef, saving, updateValue, stopEditing } = useGridPopoverContext<TData>();
26
31
  const saveButtonRef = useRef<HTMLButtonElement>(null);
27
32
  const [isOpen, setOpen] = useState(false);
@@ -33,32 +38,26 @@ export const useGridPopoverHook = <TData extends GridBaseRow>(props: GridPopover
33
38
  const triggerSave = useCallback(
34
39
  async (reason?: string) => {
35
40
  if (reason == CloseReason.CANCEL) {
41
+ await updateValue(CancelPromise, 0);
36
42
  stopEditing();
37
- onBulkEditingComplete();
43
+
38
44
  return;
39
45
  }
40
- if (props?.invalid?.()) {
46
+ if (invalid?.()) {
41
47
  // Don't close, don't do anything it's invalid
42
48
  return;
43
49
  }
44
50
 
45
- if (!props.save) {
46
- // No save method so just close
47
- stopEditing();
48
- onBulkEditingComplete();
49
- return;
50
- }
51
-
52
51
  if (
53
52
  await updateValue(
54
- props.save,
53
+ save ?? (() => Promise.resolve(true)),
55
54
  reason === CloseReason.TAB_FORWARD ? 1 : reason === CloseReason.TAB_BACKWARD ? -1 : 0,
56
55
  )
57
56
  ) {
58
57
  stopEditing();
59
58
  }
60
59
  },
61
- [onBulkEditingComplete, props, stopEditing, updateValue],
60
+ [invalid, save, stopEditing, updateValue],
62
61
  );
63
62
 
64
63
  const popoverWrapper = useCallback(
@@ -82,7 +81,7 @@ export const useGridPopoverHook = <TData extends GridBaseRow>(props: GridPopover
82
81
  }}
83
82
  viewScroll={'auto'}
84
83
  dontShrinkIfDirectionIsTop={true}
85
- className={props.className}
84
+ className={className}
86
85
  >
87
86
  {saving && ( // This is the overlay that prevents editing when the editor is saving
88
87
  <div className={'ComponentLoadingWrapper-saveOverlay'} />
@@ -93,7 +92,7 @@ export const useGridPopoverHook = <TData extends GridBaseRow>(props: GridPopover
93
92
  data-reason={''}
94
93
  onClick={(e) => {
95
94
  let reason = e.currentTarget.getAttribute('data-reason') ?? undefined;
96
- if (props.dontSaveOnExternalClick && reason === CloseReason.BLUR) {
95
+ if (dontSaveOnExternalClick && reason === CloseReason.BLUR) {
97
96
  reason = CloseReason.CANCEL;
98
97
  }
99
98
  void triggerSave(reason);
@@ -105,7 +104,7 @@ export const useGridPopoverHook = <TData extends GridBaseRow>(props: GridPopover
105
104
  </>
106
105
  );
107
106
  },
108
- [anchorRef, isOpen, props.className, props.dontSaveOnExternalClick, saving, triggerSave],
107
+ [anchorRef, isOpen, className, dontSaveOnExternalClick, saving, triggerSave],
109
108
  );
110
109
 
111
110
  return {
@@ -32,7 +32,7 @@ interface FinalSelectOption<TOptionValue> {
32
32
  export const primitiveToSelectOption = <T,>(value: T): SelectOption<T> => {
33
33
  return {
34
34
  value: value,
35
- label: value ? String(value) : '',
35
+ label: value ? String(value) : '-',
36
36
  };
37
37
  };
38
38
 
@@ -178,7 +178,14 @@ export const GridFormDropDown = <TData extends GridBaseRow, TOptionValue>(
178
178
  if (selectedItem === null) {
179
179
  if (props.onSelectFilter) {
180
180
  const { onSelectFilter } = props;
181
- await onSelectFilter({ selectedRows, selectedRowIds: selectedRows.map((row) => row.id), value: filter as any });
181
+ if (!isEmpty(filter)) {
182
+ await onSelectFilter({
183
+ selectedRows,
184
+ selectedRowIds: selectedRows.map((row) => row.id),
185
+ value: filter as any,
186
+ });
187
+ }
188
+
182
189
  return true;
183
190
  } else {
184
191
  if (filteredValues && filteredValues.length === 1) {
@@ -230,7 +237,7 @@ export const GridFormDropDown = <TData extends GridBaseRow, TOptionValue>(
230
237
  !props.onSelectFilter &&
231
238
  !(filteredValues && filteredValues.length === 1 && !filteredValues[0].subComponent)
232
239
  }
233
- onChange={(e) => setFilter(e.target.value)}
240
+ onChange={(e) => setFilter(e.target.value.trim())}
234
241
  />
235
242
  {props.filterHelpText && isNotEmpty(filter) && (
236
243
  <FormError error={null} helpText={props.filterHelpText} />
@@ -98,10 +98,14 @@ export const GridFormMultiSelect = <TData extends GridBaseRow>(props: GridFormMu
98
98
 
99
99
  const save = useCallback(
100
100
  async (selectedRows: TData[]): Promise<boolean> => {
101
- if (!options || !props.onSave) return true;
101
+ if (!options || !props.onSave) {
102
+ return true;
103
+ }
102
104
 
103
105
  // Any changes to save?
104
- if (initialValues === JSON.stringify(options)) return true;
106
+ if (initialValues === JSON.stringify(options)) {
107
+ return true;
108
+ }
105
109
 
106
110
  return props.onSave({
107
111
  selectedRows,
@@ -278,7 +282,9 @@ const FilterInput = (props: {
278
282
  }, [filter, headerGroups, options, setOptions]);
279
283
 
280
284
  const addCustomFilterValue = useCallback(() => {
281
- if (!options || !onSelectFilter) return;
285
+ if (!options || !onSelectFilter) {
286
+ return;
287
+ }
282
288
 
283
289
  const filterTrimmed = filter.trim();
284
290
  if (isEmpty(filterTrimmed)) {
@@ -289,7 +295,9 @@ const FilterInput = (props: {
289
295
  const preFilterOptions = JSON.stringify(options);
290
296
  onSelectFilter({ filter: filterTrimmed, options });
291
297
  // Detect if options list changed and update
292
- if (preFilterOptions === JSON.stringify(options)) return;
298
+ if (preFilterOptions === JSON.stringify(options)) {
299
+ return;
300
+ }
293
301
 
294
302
  setOptions([...options]);
295
303
  setFilter('');
@@ -15,6 +15,7 @@ export const GridPopoverMessage = <TData extends GridBaseRow, TValue = any>(
15
15
  },
16
16
  {
17
17
  editor: GridFormMessage,
18
+ preventAutoEdit: true,
18
19
  ...props,
19
20
  },
20
21
  );
@@ -63,8 +63,8 @@ export interface GridContextType<TData extends GridBaseRow> {
63
63
  invisibleColumnIds: string[] | undefined;
64
64
  setInvisibleColumnIds: (colIds: string[]) => void;
65
65
  downloadCsv: (csvExportParams?: CsvExportParams) => void;
66
- onBulkEditingComplete: () => void;
67
- setOnBulkEditingComplete: (callback: (() => void) | undefined) => void;
66
+ onBulkEditingComplete: () => Promise<void> | void;
67
+ setOnBulkEditingComplete: (callback: (() => Promise<void> | void) | undefined) => void;
68
68
  showNoRowsOverlay: () => void;
69
69
  }
70
70
 
@@ -1,5 +1,12 @@
1
- import { CellPosition, ColDef, GridApi, IRowNode, RowNode } from 'ag-grid-community';
2
- import { CsvExportParams, ProcessCellForExportParams } from 'ag-grid-community';
1
+ import {
2
+ CellPosition,
3
+ ColDef,
4
+ CsvExportParams,
5
+ GridApi,
6
+ IRowNode,
7
+ ProcessCellForExportParams,
8
+ RowNode,
9
+ } from 'ag-grid-community';
3
10
  import debounce from 'debounce-promise';
4
11
  import { compact, defer, delay, difference, filter, isEmpty, last, pull, remove, sortBy, sumBy } from 'lodash-es';
5
12
  import { PropsWithChildren, ReactElement, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
@@ -8,6 +15,7 @@ import { ColDefT, GridBaseRow } from '../components';
8
15
  import { GridCellFillerColId, isGridCellFiller } from '../components/GridCellFiller';
9
16
  import { getColId, isFlexColumn } from '../components/gridUtil';
10
17
  import { fnOrVar, isNotEmpty, sanitiseFileName, wait } from '../utils/util';
18
+ import { waitForCondition } from '../utils/waitForCondition';
11
19
  import { AutoSizeColumnsProps, AutoSizeColumnsResult, GridContext, GridFilterExternal } from './GridContext';
12
20
  import { GridUpdatingContext } from './GridUpdatingContext';
13
21
 
@@ -494,8 +502,13 @@ export const GridContextProvider = <TData extends GridBaseRow>(props: PropsWithC
494
502
 
495
503
  try {
496
504
  // Edit in progress so don't edit until finished, timeout waiting after 5s
497
- if (!(await waitForCondition(() => !anyUpdating(), 5000))) {
498
- console.error("Could not start edit because previous edit hasn't finished after 5 seconds");
505
+ if (
506
+ !(await waitForCondition(
507
+ 'startCellEditing failed as update still in progress, waited for 15 seconds',
508
+ () => !anyUpdating(),
509
+ 15000,
510
+ ))
511
+ ) {
499
512
  return;
500
513
  }
501
514
 
@@ -521,11 +534,12 @@ export const GridContextProvider = <TData extends GridBaseRow>(props: PropsWithC
521
534
  const rowIndex = rowNode.rowIndex;
522
535
  if (rowIndex != null) {
523
536
  defer(() => {
524
- !gridApi.isDestroyed() &&
537
+ if (!gridApi.isDestroyed()) {
525
538
  gridApi.startEditingCell({
526
539
  rowIndex,
527
540
  colKey: colId,
528
541
  });
542
+ }
529
543
  });
530
544
  }
531
545
  } finally {
@@ -535,15 +549,18 @@ export const GridContextProvider = <TData extends GridBaseRow>(props: PropsWithC
535
549
  [anyUpdating, gridApi, prePopupOps, waitForExternallySelectedItemsToBeInSync],
536
550
  );
537
551
 
538
- const bulkEditingCompleteCallbackRef = useRef<() => void>();
539
- const onBulkEditingComplete = useCallback(() => {
552
+ const bulkEditingCompleteCallbackRef = useRef<() => Promise<void> | void>();
553
+ const onBulkEditingComplete = useCallback(async () => {
540
554
  resetFocusedCellAfterCellEditing();
541
- bulkEditingCompleteCallbackRef.current?.();
555
+ await bulkEditingCompleteCallbackRef.current?.();
542
556
  }, [resetFocusedCellAfterCellEditing]);
543
557
 
544
- const setOnBulkEditingComplete = useCallback((cellEditingCompleteCallback: (() => void) | undefined) => {
545
- bulkEditingCompleteCallbackRef.current = cellEditingCompleteCallback;
546
- }, []);
558
+ const setOnBulkEditingComplete = useCallback(
559
+ (cellEditingCompleteCallback: (() => Promise<void> | void) | undefined) => {
560
+ bulkEditingCompleteCallbackRef.current = cellEditingCompleteCallback;
561
+ },
562
+ [],
563
+ );
547
564
 
548
565
  /**
549
566
  * Returns true if an editable cell on same row was selected, else false.
@@ -577,8 +594,10 @@ export const GridContextProvider = <TData extends GridBaseRow>(props: PropsWithC
577
594
  prePopupFocusedCell.current = undefined;
578
595
 
579
596
  const preRow = gridApi.getFocusedCell();
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
+ // we are managing it ourselves
599
+ gridApi.stopEditing();
580
600
  if (tabDirection === 1) {
581
- gridApi.stopEditing();
582
601
  gridApi.tabToNextCell();
583
602
  } else {
584
603
  gridApi.tabToPreviousCell();
@@ -621,6 +640,7 @@ export const GridContextProvider = <TData extends GridBaseRow>(props: PropsWithC
621
640
  ): Promise<boolean> => {
622
641
  try {
623
642
  setSaving?.(true);
643
+
624
644
  return await gridApiOp(async (gridApi) => {
625
645
  const selectedRows = props.selectedRows;
626
646
 
@@ -630,10 +650,8 @@ export const GridContextProvider = <TData extends GridBaseRow>(props: PropsWithC
630
650
  props.field ?? '',
631
651
  selectedRows.map((data) => data.id),
632
652
  async () => {
633
- // MATT Disabled I don't believe these are needed anymore
634
- // I've left them here just in case they are
635
653
  // Need to refresh to get spinners to work on all rows
636
- // gridApi.refreshCells({ rowNodes: props.selectedRows as RowNode[], force: true });
654
+ gridApi.refreshCells({ rowNodes: props.selectedRows as RowNode[], force: true });
637
655
  ok = await fnUpdate(selectedRows).catch((ex) => {
638
656
  console.error('Exception during modifyUpdating', ex);
639
657
  return false;
@@ -641,23 +659,21 @@ export const GridContextProvider = <TData extends GridBaseRow>(props: PropsWithC
641
659
  },
642
660
  );
643
661
 
644
- // MATT Disabled I don't believe these are needed anymore
645
- // I've left them here just in case they are
646
662
  // async processes need to refresh their own rows
647
- // gridApi.refreshCells({ rowNodes: selectedRows as RowNode[], force: true });
663
+ gridApi.refreshCells({ rowNodes: selectedRows as RowNode[], force: true });
648
664
 
649
665
  if (gridApi.isDestroyed()) {
650
666
  return ok;
651
667
  }
652
668
 
653
669
  if (ok) {
654
- const cell = gridApi.getFocusedCell();
655
- if (cell && gridApi.getFocusedCell() == null) {
656
- !gridApi.isDestroyed && gridApi.setFocusedCell(cell.rowIndex, cell.column);
657
- }
670
+ //const cell = gridApi.getFocusedCell();
671
+ //if (cell && gridApi.getFocusedCell() == null) {
672
+ // !gridApi.isDestroyed && gridApi.setFocusedCell(cell.rowIndex, cell.column);
673
+ // }
658
674
 
659
675
  // This is needed to trigger postSortRowsHook
660
- gridApi.refreshClientSideRowModel();
676
+ !gridApi.isDestroyed && gridApi.refreshClientSideRowModel();
661
677
  }
662
678
 
663
679
  void (async () => {
@@ -670,10 +686,10 @@ export const GridContextProvider = <TData extends GridBaseRow>(props: PropsWithC
670
686
  prePopupFocusedCell.current.column.getColId() == postPopupFocusedCell.column.getColId()
671
687
  ) {
672
688
  if (!tabDirection || !(await selectNextEditableCell(tabDirection))) {
673
- onBulkEditingComplete();
689
+ await onBulkEditingComplete();
674
690
  }
675
691
  } else {
676
- onBulkEditingComplete();
692
+ await onBulkEditingComplete();
677
693
  }
678
694
  })();
679
695
 
@@ -909,15 +925,3 @@ export const downloadCsvUseValueFormattersProcessCellCallback = (params: Process
909
925
  // We add an extra encodeToString here just in case valueFormatter is returning non string values
910
926
  return encodeToString(result);
911
927
  };
912
-
913
- const waitForCondition = async (condition: () => boolean, timeoutMs: number): Promise<boolean> => {
914
- const endTime = Date.now() + timeoutMs;
915
- while (Date.now() < endTime) {
916
- if (condition()) {
917
- return true;
918
- }
919
- await wait(100);
920
- }
921
- console.warn('waitForCondition failed');
922
- return false;
923
- };
package/src/index.ts CHANGED
@@ -17,3 +17,4 @@ export * from './utils/deferredPromise';
17
17
  export * from './utils/textMatcher';
18
18
  export * from './utils/textValidator';
19
19
  export * from './utils/util';
20
+ export * from './utils/waitForCondition';
@@ -30,7 +30,7 @@ export default {
30
30
  ],
31
31
  } as Meta<typeof Grid>;
32
32
 
33
- const GridPopoutEditGenericTemplate: StoryFn<typeof Grid> = (props: GridProps) => {
33
+ const GridPopoutEditGenericTemplate: StoryFn<typeof Grid<IFormTestRow>> = (props: GridProps<IFormTestRow>) => {
34
34
  const [externalSelectedItems, setExternalSelectedItems] = useState<any[]>([]);
35
35
  const columnDefs: ColDefT<IFormTestRow>[] = useMemo(
36
36
  () => [
@@ -49,7 +49,7 @@ interface ITestRow {
49
49
  position3: string | null;
50
50
  }
51
51
 
52
- const GridEditMultiSelectTemplate: StoryFn<typeof Grid> = (props: GridProps) => {
52
+ const GridEditMultiSelectTemplate: StoryFn<typeof Grid<ITestRow>> = (props: GridProps<ITestRow>) => {
53
53
  const [externalSelectedItems, setExternalSelectedItems] = useState<any[]>([]);
54
54
 
55
55
  const columnDefs: ColDefT<ITestRow>[] = useMemo(() => {
@@ -39,7 +39,7 @@ interface ITestRow {
39
39
  position2: string | null;
40
40
  }
41
41
 
42
- const GridEditMultiSelectGridTemplate: StoryFn<typeof Grid> = (props: GridProps) => {
42
+ const GridEditMultiSelectGridTemplate: StoryFn<typeof Grid<ITestRow>> = (props: GridProps<ITestRow>) => {
43
43
  const [externalSelectedItems, setExternalSelectedItems] = useState<any[]>([]);
44
44
 
45
45
  const columnDefs: ColDefT<ITestRow>[] = useMemo(() => {
@@ -10,8 +10,7 @@ import { expect, fn, userEvent, within } from 'storybook/test';
10
10
 
11
11
  import {
12
12
  GridBaseRow,
13
- GridContext,
14
- GridContextType,
13
+ GridContextProvider,
15
14
  GridFormDropDown,
16
15
  GridFormDropDownProps,
17
16
  GridFormSubComponentTextInput,
@@ -51,14 +50,7 @@ const Template: StoryFn<typeof GridFormDropDown<GridBaseRow, number>> = (
51
50
 
52
51
  return (
53
52
  <div className={'react-menu-inline-test'}>
54
- <GridContext.Provider
55
- value={
56
- {
57
- onBulkEditingComplete: () => {},
58
- resetFocusedCellAfterCellEditing: () => {},
59
- } as unknown as GridContextType<GridBaseRow>
60
- }
61
- >
53
+ <GridContextProvider>
62
54
  <h6 ref={anchorRef}>Interaction test</h6>
63
55
  <GridPopoverContext.Provider
64
56
  value={{
@@ -77,7 +69,7 @@ const Template: StoryFn<typeof GridFormDropDown<GridBaseRow, number>> = (
77
69
  >
78
70
  <GridFormDropDown {...props} {...config} />
79
71
  </GridPopoverContext.Provider>
80
- </GridContext.Provider>
72
+ </GridContextProvider>
81
73
  </div>
82
74
  );
83
75
  };
@@ -131,7 +123,7 @@ GridFormDropDownInteractions_.play = async ({ canvasElement }) => {
131
123
  // Test escape to not save
132
124
  updateValue.mockClear();
133
125
  await userEvent.type(textInput, '{Escape}');
134
- expect(updateValue).not.toHaveBeenCalled();
126
+ expect(updateValue).toHaveBeenCalledWith(expect.anything(), 0);
135
127
 
136
128
  // Test invalid value doesn't save
137
129
  updateValue.mockClear();
@@ -9,7 +9,8 @@ import { useRef } from 'react';
9
9
  import { expect, fn, userEvent, within } from 'storybook/test';
10
10
 
11
11
  import {
12
- GridContext,
12
+ CancelPromise,
13
+ GridContextProvider,
13
14
  GridFormEditBearing,
14
15
  GridFormEditBearingProps,
15
16
  GridPopoverEditBearingCorrectionEditorParams,
@@ -28,14 +29,7 @@ const Template: StoryFn<typeof GridFormEditBearing> = (props: GridFormEditBearin
28
29
 
29
30
  return (
30
31
  <div className={'react-menu-inline-test'}>
31
- <GridContext.Provider
32
- value={
33
- {
34
- onBulkEditingComplete: () => {},
35
- resetFocusedCellAfterCellEditing: () => {},
36
- } as any
37
- }
38
- >
32
+ <GridContextProvider>
39
33
  <h6 ref={anchorRef}>Interaction Test</h6>
40
34
  <GridPopoverContext.Provider
41
35
  value={{
@@ -54,7 +48,7 @@ const Template: StoryFn<typeof GridFormEditBearing> = (props: GridFormEditBearin
54
48
  >
55
49
  <GridFormEditBearing {...props} {...GridPopoverEditBearingCorrectionEditorParams} />
56
50
  </GridPopoverContext.Provider>
57
- </GridContext.Provider>
51
+ </GridContextProvider>
58
52
  </div>
59
53
  );
60
54
  };
@@ -93,7 +87,7 @@ GridFormEditBearingCorrectionInteractions_.play = async ({ canvasElement }) => {
93
87
  // Test escape not to save
94
88
  updateValue.mockClear();
95
89
  await userEvent.type(inputField, '{Escape}');
96
- expect(updateValue).not.toHaveBeenCalled();
90
+ expect(updateValue).toHaveBeenCalledWith(expect.anything(), 0);
97
91
 
98
92
  // Test invalid value doesn't save
99
93
  updateValue.mockClear();
@@ -9,7 +9,7 @@ import { useRef } from 'react';
9
9
  import { expect, fn, userEvent, within } from 'storybook/test';
10
10
 
11
11
  import {
12
- GridContext,
12
+ GridContextProvider,
13
13
  GridFormEditBearing,
14
14
  GridFormEditBearingProps,
15
15
  GridPopoverEditBearingEditorParams,
@@ -28,14 +28,7 @@ const Template: StoryFn<typeof GridFormEditBearing> = (props: GridFormEditBearin
28
28
 
29
29
  return (
30
30
  <div className={'react-menu-inline-test'}>
31
- <GridContext.Provider
32
- value={
33
- {
34
- onBulkEditingComplete: () => {},
35
- resetFocusedCellAfterCellEditing: () => {},
36
- } as any
37
- }
38
- >
31
+ <GridContextProvider>
39
32
  <h6 ref={anchorRef}>Interaction Test</h6>
40
33
  <GridPopoverContext.Provider
41
34
  value={{
@@ -54,7 +47,7 @@ const Template: StoryFn<typeof GridFormEditBearing> = (props: GridFormEditBearin
54
47
  >
55
48
  <GridFormEditBearing {...props} {...GridPopoverEditBearingEditorParams} />
56
49
  </GridPopoverContext.Provider>
57
- </GridContext.Provider>
50
+ </GridContextProvider>
58
51
  </div>
59
52
  );
60
53
  };
@@ -93,7 +86,7 @@ GridFormEditBearingInteractions_.play = async ({ canvasElement }) => {
93
86
  // Test escape not to save
94
87
  updateValue.mockClear();
95
88
  await userEvent.type(inputField, '{Escape}');
96
- expect(updateValue).not.toHaveBeenCalled();
89
+ expect(updateValue).toHaveBeenCalledWith(expect.anything(), 0);
97
90
 
98
91
  // Test invalid value doesn't save
99
92
  updateValue.mockClear();
@@ -8,7 +8,12 @@ import { GridPopoverContext } from 'contexts/GridPopoverContext';
8
8
  import { useRef } from 'react';
9
9
  import { expect, fn, userEvent, waitFor, within } from 'storybook/test';
10
10
 
11
- import { GridContext, GridFormMultiSelectGrid, GridFormMultiSelectGridProps, MultiSelectGridOption } from '../../..';
11
+ import {
12
+ GridContextProvider,
13
+ GridFormMultiSelectGrid,
14
+ GridFormMultiSelectGridProps,
15
+ MultiSelectGridOption,
16
+ } from '../../..';
12
17
 
13
18
  export default {
14
19
  title: 'GridForm / Interactions',
@@ -42,14 +47,7 @@ const Template: StoryFn<typeof GridFormMultiSelectGrid> = (props: GridFormMultiS
42
47
 
43
48
  return (
44
49
  <div className={'react-menu-inline-test'}>
45
- <GridContext.Provider
46
- value={
47
- {
48
- onBulkEditingComplete: () => {},
49
- resetFocusedCellAfterCellEditing: () => {},
50
- } as any
51
- }
52
- >
50
+ <GridContextProvider>
53
51
  <h6 ref={anchorRef}>Interaction test</h6>
54
52
  <GridPopoverContext.Provider
55
53
  value={{
@@ -68,7 +66,7 @@ const Template: StoryFn<typeof GridFormMultiSelectGrid> = (props: GridFormMultiS
68
66
  >
69
67
  <GridFormMultiSelectGrid {...props} {...config} />
70
68
  </GridPopoverContext.Provider>
71
- </GridContext.Provider>
69
+ </GridContextProvider>
72
70
  </div>
73
71
  );
74
72
  };