@linzjs/step-ag-grid 27.1.0 → 27.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@linzjs/step-ag-grid",
3
3
  "repository": "github:linz/step-ag-grid.git",
4
4
  "license": "MIT",
5
- "version": "27.1.0",
5
+ "version": "27.2.1",
6
6
  "keywords": [
7
7
  "aggrid",
8
8
  "ag-grid",
@@ -14,21 +14,28 @@ import { GridBaseRow } from '../Grid';
14
14
  import { CellEditorCommon } from '../GridCell';
15
15
  import { useGridPopoverHook } from '../GridPopoverHook';
16
16
 
17
- export interface GridPopoutEditDropDownSelectedItem<TData extends GridBaseRow, TValue> {
17
+ export interface GridPopoutEditDropDownSelectedItem<TData extends GridBaseRow, TOption> {
18
18
  // Note the row that was clicked on will be first
19
19
  selectedRows: TData[];
20
20
  selectedRowIds: TData['id'][];
21
- value: TValue;
21
+ value: TOption;
22
22
  subComponentValue?: any;
23
23
  }
24
24
 
25
- interface FinalSelectOption {
26
- value: any;
25
+ interface FinalSelectOption<TOptionValue> {
26
+ value: TOptionValue;
27
27
  label?: ReactElement | string;
28
28
  disabled?: boolean | string;
29
29
  subComponent?: (props: any, ref: any) => any;
30
30
  }
31
31
 
32
+ export const primitiveToSelectOption = <T,>(value: T): SelectOption<T> => {
33
+ return {
34
+ value: value,
35
+ label: value ? String(value) : '',
36
+ };
37
+ };
38
+
32
39
  export const MenuSeparatorString = '_____MENU_SEPARATOR_____';
33
40
  export const MenuSeparator = Object.freeze({ value: MenuSeparatorString });
34
41
 
@@ -37,9 +44,11 @@ export const MenuHeaderItem = (title: string) => {
37
44
  return { label: title, value: MenuHeaderString };
38
45
  };
39
46
 
40
- export type SelectOption = null | string | FinalSelectOption;
47
+ export type SelectOption<TOptionValue = any> = FinalSelectOption<TOptionValue>;
41
48
 
42
- export interface GridFormDropDownProps<TData extends GridBaseRow, TValue = any> extends CellEditorCommon {
49
+ export type MaybePromise<T> = T | Promise<T>;
50
+
51
+ export interface GridFormDropDownProps<TData extends GridBaseRow, TOptionValue> extends CellEditorCommon {
43
52
  // This overrides CellEditorCommon to provide some common class options
44
53
  className?: // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
45
54
  | 'GridPopoverEditDropDown-containerSmall'
@@ -59,11 +68,11 @@ export interface GridFormDropDownProps<TData extends GridBaseRow, TValue = any>
59
68
  filterPlaceholder?: string;
60
69
  filterHelpText?: string;
61
70
  noOptionsMessage?: string;
62
- onSelectedItem?: (props: GridPopoutEditDropDownSelectedItem<TData, TValue>) => Promise<void> | void;
63
- onSelectFilter?: (props: GridPopoutEditDropDownSelectedItem<TData, TValue>) => Promise<void> | void;
71
+ onSelectedItem?: (props: GridPopoutEditDropDownSelectedItem<TData, TOptionValue>) => Promise<void> | void;
72
+ onSelectFilter?: (props: GridPopoutEditDropDownSelectedItem<TData, TOptionValue>) => Promise<void> | void;
64
73
  options:
65
- | SelectOption[]
66
- | ((selectedRows: TData[], filter?: string) => Promise<SelectOption[] | undefined> | SelectOption[] | undefined)
74
+ | FinalSelectOption<TOptionValue>[]
75
+ | ((selectedRows: TData[], filter?: string) => MaybePromise<FinalSelectOption<TOptionValue>[] | undefined>)
67
76
  | undefined;
68
77
  }
69
78
 
@@ -71,18 +80,20 @@ const fieldToString = (field: any) => {
71
80
  return typeof field === 'symbol' ? field.toString() : `${field}`;
72
81
  };
73
82
 
74
- export const GridFormDropDown = <TData extends GridBaseRow, TValue>(props: GridFormDropDownProps<TData, TValue>) => {
83
+ export const GridFormDropDown = <TData extends GridBaseRow, TOptionValue>(
84
+ props: GridFormDropDownProps<TData, TOptionValue>,
85
+ ) => {
75
86
  const { selectedRows, field, data } = useGridPopoverContext<TData>();
76
87
 
77
88
  // Save triggers during async action processing which triggers another selectItem(), this ref blocks that
78
89
  const [filter, setFilter] = useState(props.filterDefaultValue ?? '');
79
90
  const [filteredValues, setFilteredValues] = useState<any[]>();
80
- const [options, setOptions] = useState<FinalSelectOption[] | null>(null);
91
+ const [options, setOptions] = useState<FinalSelectOption<TOptionValue>[] | null>(null);
81
92
  const subComponentIsValid = useRef(false);
82
93
  const subComponentInitialValue = useRef<string | null>(null);
83
94
  const [subSelectedValue, setSubSelectedValue] = useState<any>(null);
84
95
  // Note: null is assumed to be the filter
85
- const [selectedItem, setSelectedItem] = useState<FinalSelectOption | null>(null);
96
+ const [selectedItem, setSelectedItem] = useState<FinalSelectOption<TOptionValue> | null>(null);
86
97
 
87
98
  const selectItemHandler = useCallback(
88
99
  async (value: any, subComponentValue?: any): Promise<boolean> => {
@@ -116,17 +127,7 @@ export const GridFormDropDown = <TData extends GridBaseRow, TValue>(props: GridF
116
127
  optionsConf = await optionsConf(selectedRows, filter);
117
128
  }
118
129
  if (optionsConf !== undefined) {
119
- const optionsList = optionsConf?.map((item) =>
120
- item == null || typeof item === 'string'
121
- ? ({
122
- value: item,
123
- label: item,
124
- disabled: false,
125
- } as FinalSelectOption)
126
- : item,
127
- );
128
-
129
- setOptions(optionsList);
130
+ setOptions(optionsConf);
130
131
  }
131
132
  })();
132
133
  }, [filter, options, props, selectedRows]);
@@ -251,7 +252,7 @@ export const GridFormDropDown = <TData extends GridBaseRow, TValue>(props: GridF
251
252
  {props.noOptionsMessage ?? 'No Options'}
252
253
  </MenuItem>
253
254
  )}
254
- {options?.map((item: FinalSelectOption, index) => {
255
+ {options?.map((item: FinalSelectOption<TOptionValue>, index) => {
255
256
  showHeader = null;
256
257
  if (item.value === MenuSeparatorString) {
257
258
  return <MenuDivider key={`$$divider_${index}`} />;
@@ -288,7 +289,7 @@ export const GridFormDropDown = <TData extends GridBaseRow, TValue>(props: GridF
288
289
  e.keepOpen = !!item.subComponent;
289
290
  }}
290
291
  >
291
- {item.label ?? (item.value == null ? `<${item.value}>` : `${item.value}`)}
292
+ {item.label ?? (item.value == null ? `<${String(item.value)}>` : `${String(item.value)}`)}
292
293
  {item.subComponent ? '...' : ''}
293
294
  </MenuItem>
294
295
 
@@ -5,15 +5,15 @@ import { ColDefT, GenericCellEditorProps, GridCell } from '../GridCell';
5
5
  import { GridFormDropDown, GridFormDropDownProps } from '../gridForm/GridFormDropDown';
6
6
  import { GenericCellColDef } from '../gridRender/GridRenderGenericCell';
7
7
 
8
- export const GridPopoverEditDropDown = <TData extends GridBaseRow, TValue = any>(
8
+ export const GridPopoverEditDropDown = <TData extends GridBaseRow, TValue = any, TOptionValue = any>(
9
9
  colDef: GenericCellColDef<TData, TValue>,
10
- props: GenericCellEditorProps<GridFormDropDownProps<TData, TValue>>,
10
+ props: GenericCellEditorProps<GridFormDropDownProps<TData, TOptionValue>>,
11
11
  ): ColDefT<TData, TValue> =>
12
- GridCell<TData, TValue, GridFormDropDownProps<TData, TValue>>(colDef, {
12
+ GridCell<TData, TValue, GridFormDropDownProps<TData, TOptionValue>>(colDef, {
13
13
  editor: GridFormDropDown,
14
14
  ...props,
15
15
  editorParams: {
16
- ...(props.editorParams as GridFormDropDownProps<TData, TValue>),
16
+ ...(props.editorParams as GridFormDropDownProps<TData, TOptionValue>),
17
17
  className: clsx(
18
18
  {
19
19
  'GridPopoverEditDropDown-containerLarge': !props.editorParams?.className?.includes(
@@ -62,7 +62,7 @@ export const GridContextProvider = <TData extends GridBaseRow>(props: PropsWithC
62
62
  if (!noApiFn) {
63
63
  noApiFn = (() => {}) as () => R;
64
64
  }
65
- return gridApi ? hasApiFn(gridApi) : noApiFn();
65
+ return gridApi && !gridApi.isDestroyed() ? hasApiFn(gridApi) : noApiFn();
66
66
  },
67
67
  [gridApi],
68
68
  );
@@ -290,9 +290,9 @@ export const GridContextProvider = <TData extends GridBaseRow>(props: PropsWithC
290
290
  colId &&
291
291
  delay(() => {
292
292
  if (
293
+ !gridApi.isDestroyed() &&
293
294
  isEmpty(gridApi.getEditingCells()) &&
294
- (!ifNoCellFocused || gridApi.getFocusedCell() == null) &&
295
- !gridApi.isDestroyed()
295
+ (!ifNoCellFocused || gridApi.getFocusedCell() == null)
296
296
  ) {
297
297
  gridApi.setFocusedCell(rowIndex, colId);
298
298
  // It may be that the first cell is the selection cell, this doesn't exist as a colDef
@@ -456,7 +456,9 @@ export const GridContextProvider = <TData extends GridBaseRow>(props: PropsWithC
456
456
  * Resize columns to fit container
457
457
  */
458
458
  const sizeColumnsToFit = useCallback((): void => {
459
- gridApi?.sizeColumnsToFit();
459
+ if (gridApi && !gridApi?.isDestroyed()) {
460
+ gridApi.sizeColumnsToFit();
461
+ }
460
462
  }, [gridApi]);
461
463
 
462
464
  const stopEditing = useCallback((): void => {
@@ -640,6 +642,10 @@ export const GridContextProvider = <TData extends GridBaseRow>(props: PropsWithC
640
642
  // async processes need to refresh their own rows
641
643
  // gridApi.refreshCells({ rowNodes: selectedRows as RowNode[], force: true });
642
644
 
645
+ if (gridApi.isDestroyed()) {
646
+ return ok;
647
+ }
648
+
643
649
  if (ok) {
644
650
  const cell = gridApi.getFocusedCell();
645
651
  if (cell && gridApi.getFocusedCell() == null) {
@@ -331,7 +331,6 @@ export const ControlledMenuFr = (
331
331
  externalRef={externalRef}
332
332
  containerRef={containerRef}
333
333
  onClose={onClose}
334
- onBlur={() => console.log('blur')}
335
334
  />
336
335
  </EventHandlersContext.Provider>
337
336
  </ItemSettingsContext.Provider>
@@ -25,6 +25,7 @@ import {
25
25
  MenuHeaderItem,
26
26
  MenuSeparator,
27
27
  MenuSeparatorString,
28
+ primitiveToSelectOption,
28
29
  wait,
29
30
  } from '../..';
30
31
  import { waitForGridReady } from '../../utils/__tests__/storybookTestUtil';
@@ -72,16 +73,9 @@ const GridEditDropDownTemplate: StoryFn<typeof Grid> = (props: GridProps) => {
72
73
  console.log('optionsFn selected rows', selectedRows, filter);
73
74
  filter = filter?.toLowerCase();
74
75
  await wait(1000);
75
- return [
76
- null,
77
- 'Architect',
78
- 'Developer',
79
- 'Product Owner',
80
- 'Scrum Master',
81
- 'Tester',
82
- MenuSeparatorString,
83
- 'Custom',
84
- ].filter((v) => (filter != null ? v != null && v.toLowerCase().indexOf(filter) === 0 : true));
76
+ return [null, 'Architect', 'Developer', 'Product Owner', 'Scrum Master', 'Tester', MenuSeparatorString, 'Custom']
77
+ .filter((v) => (filter != null ? v != null && v.toLowerCase().indexOf(filter) === 0 : true))
78
+ .map(primitiveToSelectOption);
85
79
  }, []);
86
80
 
87
81
  const optionsObjects = useMemo(
@@ -121,7 +115,7 @@ const GridEditDropDownTemplate: StoryFn<typeof Grid> = (props: GridProps) => {
121
115
  },
122
116
  },
123
117
  ),
124
- GridPopoverEditDropDown(
118
+ GridPopoverEditDropDown<ITestRow, ITestRow['position3'], string | null>(
125
119
  {
126
120
  field: 'position3',
127
121
  headerName: 'Custom callback',
@@ -129,7 +123,9 @@ const GridEditDropDownTemplate: StoryFn<typeof Grid> = (props: GridProps) => {
129
123
  {
130
124
  multiEdit: true,
131
125
  editorParams: {
132
- options: [null, 'Architect', 'Developer', 'Product Owner', 'Scrum Master', 'Tester'],
126
+ options: [null, 'Architect', 'Developer', 'Product Owner', 'Scrum Master', 'Tester'].map(
127
+ primitiveToSelectOption,
128
+ ),
133
129
  onSelectedItem: async (selected) => {
134
130
  await wait(2000);
135
131
  selected.selectedRows.forEach((row) => {
@@ -139,7 +135,7 @@ const GridEditDropDownTemplate: StoryFn<typeof Grid> = (props: GridProps) => {
139
135
  },
140
136
  },
141
137
  ),
142
- GridPopoverEditDropDown(
138
+ GridPopoverEditDropDown<ITestRow, ITestRow['position3'], string | null>(
143
139
  {
144
140
  field: 'position',
145
141
  headerName: 'Options Fn',
@@ -165,7 +161,9 @@ const GridEditDropDownTemplate: StoryFn<typeof Grid> = (props: GridProps) => {
165
161
  editorParams: {
166
162
  filtered: 'local',
167
163
  filterPlaceholder: 'Filter this',
168
- options: [null, 'Architect', 'Developer', 'Product Owner', 'Scrum Master', 'Tester'],
164
+ options: [null, 'Architect', 'Developer', 'Product Owner', 'Scrum Master', 'Tester'].map(
165
+ primitiveToSelectOption,
166
+ ),
169
167
  },
170
168
  },
171
169
  ),
@@ -186,7 +184,7 @@ const GridEditDropDownTemplate: StoryFn<typeof Grid> = (props: GridProps) => {
186
184
  },
187
185
  },
188
186
  ),
189
- GridPopoverEditDropDown(
187
+ GridPopoverEditDropDown<ITestRow, ITestRow['code'], string | null>(
190
188
  {
191
189
  field: 'code',
192
190
  headerName: 'Filter Selectable',
@@ -198,17 +196,21 @@ const GridEditDropDownTemplate: StoryFn<typeof Grid> = (props: GridProps) => {
198
196
  filterPlaceholder: 'Filter this',
199
197
  filterHelpText: 'Press enter to save custom value',
200
198
  options: optionsObjects.map((o) => {
201
- return { value: o, label: o.desc, disabled: false };
199
+ return { value: o.code, label: o.desc, disabled: false };
202
200
  }),
203
201
  onSelectedItem: (selected) => {
204
202
  // eslint-disable-next-line no-console
205
203
  console.log('onSelectedItem selected', selected);
206
- selected.selectedRows.forEach((row) => (row.code = selected.value.code));
204
+ selected.selectedRows.forEach((row) => {
205
+ row.code = selected.value;
206
+ });
207
207
  },
208
208
  onSelectFilter: (selected) => {
209
209
  // eslint-disable-next-line no-console
210
210
  console.log('onSelectFilter selected', selected);
211
- selected.selectedRows.forEach((row) => (row.code = selected.value));
211
+ selected.selectedRows.forEach((row) => {
212
+ row.code = selected.value;
213
+ });
212
214
  },
213
215
  },
214
216
  },