@linzjs/step-ag-grid 14.1.2 → 14.3.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/README.md +9 -0
- package/dist/src/components/Grid.d.ts +10 -1
- package/dist/src/components/GridCell.d.ts +1 -0
- package/dist/src/contexts/GridContext.d.ts +11 -5
- package/dist/src/contexts/GridUpdatingContext.d.ts +1 -0
- package/dist/src/lui/timeoutHook.d.ts +6 -0
- package/dist/step-ag-grid.esm.js +371 -134
- package/dist/step-ag-grid.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/components/Grid.tsx +219 -34
- package/src/components/GridCell.tsx +6 -2
- package/src/components/GridPopoverHook.tsx +4 -4
- package/src/components/gridForm/GridFormDropDown.tsx +1 -8
- package/src/components/gridPopoverEdit/GridPopoverMenu.tsx +1 -0
- package/src/contexts/GridContext.tsx +19 -3
- package/src/contexts/GridContextProvider.tsx +107 -43
- package/src/contexts/GridUpdatingContext.tsx +5 -0
- package/src/contexts/GridUpdatingContextProvider.tsx +8 -3
- package/src/lui/timeoutHook.tsx +13 -0
- package/src/react-menu3/components/MenuList.tsx +21 -1
- package/src/stories/grid/GridPopoutEditGenericTextArea.stories.tsx +7 -1
- package/src/stories/grid/GridPopoverEditDropDown.stories.tsx +5 -0
- package/src/stories/grid/interactions/GridKeyboardInteractions.stories.tsx +3 -1
package/package.json
CHANGED
package/src/components/Grid.tsx
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
|
-
import { CellClickedEvent, ColDef, ModelUpdatedEvent } from "ag-grid-community";
|
|
1
|
+
import { CellClickedEvent, ColDef, ColumnResizedEvent, ModelUpdatedEvent } from "ag-grid-community";
|
|
2
2
|
import { CellClassParams, EditableCallback, EditableCallbackParams } from "ag-grid-community/dist/lib/entities/colDef";
|
|
3
3
|
import { GridOptions } from "ag-grid-community/dist/lib/entities/gridOptions";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
CellEditingStoppedEvent,
|
|
6
|
+
CellEvent,
|
|
7
|
+
GridReadyEvent,
|
|
8
|
+
SelectionChangedEvent,
|
|
9
|
+
} from "ag-grid-community/dist/lib/events";
|
|
5
10
|
import { AgGridReact } from "ag-grid-react";
|
|
6
11
|
import clsx from "clsx";
|
|
7
|
-
import { difference, isEmpty, last, xorBy } from "lodash-es";
|
|
12
|
+
import { difference, isEmpty, last, omit, xorBy } from "lodash-es";
|
|
8
13
|
import { useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
|
9
14
|
|
|
10
15
|
import { GridContext } from "../contexts/GridContext";
|
|
11
16
|
import { GridUpdatingContext } from "../contexts/GridUpdatingContext";
|
|
17
|
+
import { useIntervalHook } from "../lui/timeoutHook";
|
|
12
18
|
import { fnOrVar, isNotEmpty } from "../utils/util";
|
|
13
19
|
import { GridNoRowsOverlay } from "./GridNoRowsOverlay";
|
|
14
20
|
import { usePostSortRowsHook } from "./PostSortRowsHook";
|
|
@@ -29,6 +35,10 @@ export interface GridProps {
|
|
|
29
35
|
defaultColDef?: GridOptions["defaultColDef"];
|
|
30
36
|
columnDefs: ColDef[];
|
|
31
37
|
rowData: GridOptions["rowData"];
|
|
38
|
+
/**
|
|
39
|
+
* Whether select column is pinned. Defaults to "left".
|
|
40
|
+
*/
|
|
41
|
+
selectColumnPinned?: ColDef["pinned"];
|
|
32
42
|
noRowsOverlayText?: string;
|
|
33
43
|
postSortRows?: GridOptions["postSortRows"];
|
|
34
44
|
animateRows?: boolean;
|
|
@@ -56,6 +66,11 @@ export interface GridProps {
|
|
|
56
66
|
* If you want to stretch to container width if width is greater than the container add a flex column.
|
|
57
67
|
*/
|
|
58
68
|
sizeColumns?: "fit" | "auto" | "auto-skip-headers" | "none";
|
|
69
|
+
/**
|
|
70
|
+
* When pressing tab whilst editing the grid will select and edit the next cell if available.
|
|
71
|
+
* Once the last cell to edit closes this callback is called.
|
|
72
|
+
*/
|
|
73
|
+
onCellEditingComplete?: () => void;
|
|
59
74
|
}
|
|
60
75
|
|
|
61
76
|
/**
|
|
@@ -66,7 +81,8 @@ export const Grid = ({
|
|
|
66
81
|
rowSelection = "multiple",
|
|
67
82
|
suppressColumnVirtualization = true,
|
|
68
83
|
theme = "ag-theme-alpine",
|
|
69
|
-
sizeColumns = "auto
|
|
84
|
+
sizeColumns = "auto",
|
|
85
|
+
selectColumnPinned = "left",
|
|
70
86
|
...params
|
|
71
87
|
}: GridProps): JSX.Element => {
|
|
72
88
|
const {
|
|
@@ -78,47 +94,78 @@ export const Grid = ({
|
|
|
78
94
|
selectRowsById,
|
|
79
95
|
focusByRowById,
|
|
80
96
|
ensureSelectedRowIsVisible,
|
|
81
|
-
|
|
97
|
+
autoSizeColumns,
|
|
82
98
|
sizeColumnsToFit,
|
|
83
99
|
externallySelectedItemsAreInSync,
|
|
84
100
|
setExternallySelectedItemsAreInSync,
|
|
85
101
|
isExternalFilterPresent,
|
|
86
102
|
doesExternalFilterPass,
|
|
103
|
+
setOnCellEditingComplete,
|
|
87
104
|
} = useContext(GridContext);
|
|
88
|
-
const { checkUpdating } = useContext(GridUpdatingContext);
|
|
105
|
+
const { checkUpdating, updatedDep, isUpdating } = useContext(GridUpdatingContext);
|
|
106
|
+
|
|
107
|
+
const gridDivRef = useRef<HTMLDivElement>(null);
|
|
89
108
|
|
|
90
109
|
const lastSelectedIds = useRef<number[]>([]);
|
|
91
110
|
const [staleGrid, setStaleGrid] = useState(false);
|
|
92
111
|
const postSortRows = usePostSortRowsHook({ setStaleGrid });
|
|
93
112
|
|
|
113
|
+
/**
|
|
114
|
+
* onContentSize should only be called at maximum twice.
|
|
115
|
+
* Once when an empty grid is loaded.
|
|
116
|
+
* And again when the grid has content.
|
|
117
|
+
*/
|
|
94
118
|
const hasSetContentSize = useRef(false);
|
|
95
119
|
const hasSetContentSizeEmpty = useRef(false);
|
|
120
|
+
const needsAutoSize = useRef(false);
|
|
96
121
|
|
|
97
122
|
const setInitialContentSize = useCallback(() => {
|
|
98
|
-
if (
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
123
|
+
if (!gridDivRef.current?.clientWidth) {
|
|
124
|
+
// Don't resize grids if they are offscreen as it doesn't work.
|
|
125
|
+
needsAutoSize.current = true;
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
const skipHeader = sizeColumns === "auto-skip-headers" && !isEmpty(params.rowData);
|
|
129
|
+
if (sizeColumns === "auto" || skipHeader) {
|
|
130
|
+
const result = autoSizeColumns({ skipHeader, userSizedColIds: userSizedColIds.current });
|
|
131
|
+
if (isEmpty(params.rowData)) {
|
|
132
|
+
if (!hasSetContentSizeEmpty.current && result && !hasSetContentSize.current) {
|
|
107
133
|
hasSetContentSizeEmpty.current = true;
|
|
108
|
-
|
|
134
|
+
params.onContentSize && params.onContentSize(result);
|
|
135
|
+
}
|
|
136
|
+
} else {
|
|
137
|
+
if (result && !hasSetContentSize.current) {
|
|
109
138
|
hasSetContentSize.current = true;
|
|
139
|
+
params.onContentSize && params.onContentSize(result);
|
|
110
140
|
}
|
|
111
|
-
params.onContentSize && result && params.onContentSize(result);
|
|
112
141
|
}
|
|
113
142
|
}
|
|
114
143
|
|
|
115
144
|
if (sizeColumns !== "none") {
|
|
116
145
|
sizeColumnsToFit();
|
|
117
146
|
}
|
|
118
|
-
|
|
147
|
+
needsAutoSize.current = false;
|
|
148
|
+
}, [autoSizeColumns, params, sizeColumns, sizeColumnsToFit]);
|
|
119
149
|
|
|
150
|
+
/**
|
|
151
|
+
* Auto-size windows that had deferred auto-size
|
|
152
|
+
*/
|
|
153
|
+
useIntervalHook({
|
|
154
|
+
callback: () => {
|
|
155
|
+
if (needsAutoSize.current) {
|
|
156
|
+
needsAutoSize.current = false;
|
|
157
|
+
setInitialContentSize();
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
timeoutMs: 1000,
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
const previousGridReady = useRef(gridReady);
|
|
120
164
|
useEffect(() => {
|
|
121
|
-
|
|
165
|
+
if (!previousGridReady.current && gridReady) {
|
|
166
|
+
previousGridReady.current = true;
|
|
167
|
+
setInitialContentSize();
|
|
168
|
+
}
|
|
122
169
|
}, [gridReady, setInitialContentSize]);
|
|
123
170
|
|
|
124
171
|
/**
|
|
@@ -195,12 +242,17 @@ export const Grid = ({
|
|
|
195
242
|
|
|
196
243
|
const selectedIds = params.externalSelectedItems.map((row) => row.id) as number[];
|
|
197
244
|
const lastNewId = last(difference(selectedIds, lastSelectedIds.current));
|
|
198
|
-
if (lastNewId != null)
|
|
245
|
+
if (lastNewId != null) {
|
|
246
|
+
ensureRowVisible(lastNewId);
|
|
247
|
+
}
|
|
199
248
|
lastSelectedIds.current = selectedIds;
|
|
200
249
|
selectRowsById(selectedIds);
|
|
201
250
|
setExternallySelectedItemsAreInSync(true);
|
|
202
251
|
}, [gridReady, params.externalSelectedItems, ensureRowVisible, selectRowsById, setExternallySelectedItemsAreInSync]);
|
|
203
252
|
|
|
253
|
+
/**
|
|
254
|
+
* Combine grid and cell editable into one function
|
|
255
|
+
*/
|
|
204
256
|
const combineEditables =
|
|
205
257
|
(...editables: (boolean | EditableCallback | undefined)[]) =>
|
|
206
258
|
(params: EditableCallbackParams): boolean => {
|
|
@@ -214,10 +266,11 @@ export const Grid = ({
|
|
|
214
266
|
/**
|
|
215
267
|
* Synchronise externally selected items to grid on externalSelectedItems change
|
|
216
268
|
*/
|
|
217
|
-
useEffect(
|
|
218
|
-
synchroniseExternallySelectedItemsToGrid();
|
|
219
|
-
}, [synchroniseExternallySelectedItemsToGrid]);
|
|
269
|
+
useEffect(synchroniseExternallySelectedItemsToGrid, [synchroniseExternallySelectedItemsToGrid]);
|
|
220
270
|
|
|
271
|
+
/**
|
|
272
|
+
* Add selectable column to colDefs. Adjust column defs to block fit for auto sized columns.
|
|
273
|
+
*/
|
|
221
274
|
const columnDefs = useMemo((): ColDef[] => {
|
|
222
275
|
const adjustColDefs = params.columnDefs.map((colDef) => {
|
|
223
276
|
const colDefEditable = colDef.editable;
|
|
@@ -238,6 +291,7 @@ export const Grid = ({
|
|
|
238
291
|
editable: false,
|
|
239
292
|
minWidth: 42,
|
|
240
293
|
maxWidth: 42,
|
|
294
|
+
pinned: selectColumnPinned,
|
|
241
295
|
headerComponentParams: {
|
|
242
296
|
exportable: false,
|
|
243
297
|
},
|
|
@@ -264,10 +318,14 @@ export const Grid = ({
|
|
|
264
318
|
params.selectable,
|
|
265
319
|
params.readOnly,
|
|
266
320
|
params.defaultColDef?.editable,
|
|
321
|
+
selectColumnPinned,
|
|
267
322
|
rowSelection,
|
|
268
323
|
clickSelectorCheckboxWhenContainingCellClicked,
|
|
269
324
|
]);
|
|
270
325
|
|
|
326
|
+
/**
|
|
327
|
+
* When grid is ready set the apis to the grid context and sync selected items to grid.
|
|
328
|
+
*/
|
|
271
329
|
const onGridReady = useCallback(
|
|
272
330
|
(event: GridReadyEvent) => {
|
|
273
331
|
setApis(event.api, event.columnApi, dataTestId);
|
|
@@ -281,30 +339,56 @@ export const Grid = ({
|
|
|
281
339
|
* This will resize columns when we have at least one row.
|
|
282
340
|
*/
|
|
283
341
|
const previousRowDataLength = useRef(0);
|
|
284
|
-
useEffect(() => {
|
|
285
|
-
if (!gridReady) return;
|
|
286
342
|
|
|
343
|
+
const onRowDataChanged = useCallback(() => {
|
|
287
344
|
const length = params.rowData?.length ?? 0;
|
|
288
345
|
if (previousRowDataLength.current !== length) {
|
|
289
|
-
|
|
290
|
-
setInitialContentSize();
|
|
291
|
-
}
|
|
346
|
+
setInitialContentSize();
|
|
292
347
|
previousRowDataLength.current = length;
|
|
293
348
|
}
|
|
294
|
-
}, [gridReady, params.rowData?.length, setInitialContentSize]);
|
|
295
349
|
|
|
350
|
+
if (lastUpdatedDep.current === updatedDep || isEmpty(colIdsEdited.current)) return;
|
|
351
|
+
lastUpdatedDep.current = updatedDep;
|
|
352
|
+
|
|
353
|
+
// Don't update while there are spinners
|
|
354
|
+
if (isUpdating()) return;
|
|
355
|
+
|
|
356
|
+
const skipHeader = sizeColumns === "auto-skip-headers";
|
|
357
|
+
autoSizeColumns({ skipHeader, userSizedColIds: userSizedColIds.current, colIds: colIdsEdited.current });
|
|
358
|
+
colIdsEdited.current.clear();
|
|
359
|
+
}, [autoSizeColumns, isUpdating, params.rowData?.length, setInitialContentSize, sizeColumns, updatedDep]);
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Show/hide no rows overlay when model changes.
|
|
363
|
+
*/
|
|
364
|
+
const isShowingNoRowsOverlay = useRef(false);
|
|
296
365
|
const onModelUpdated = useCallback((event: ModelUpdatedEvent) => {
|
|
297
|
-
event.api.getDisplayedRowCount() === 0
|
|
366
|
+
if (event.api.getDisplayedRowCount() === 0) {
|
|
367
|
+
if (!isShowingNoRowsOverlay.current) {
|
|
368
|
+
event.api.showNoRowsOverlay();
|
|
369
|
+
isShowingNoRowsOverlay.current = true;
|
|
370
|
+
}
|
|
371
|
+
} else {
|
|
372
|
+
if (isShowingNoRowsOverlay.current) {
|
|
373
|
+
event.api.hideOverlay();
|
|
374
|
+
isShowingNoRowsOverlay.current = false;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
298
377
|
}, []);
|
|
299
378
|
|
|
379
|
+
/**
|
|
380
|
+
* Force-refresh all selected rows to re-run class function, to update selection highlighting
|
|
381
|
+
*/
|
|
300
382
|
const refreshSelectedRows = useCallback((event: CellEvent): void => {
|
|
301
|
-
// Force-refresh all selected rows to re-run class function, to update selection highlighting
|
|
302
383
|
event.api.refreshCells({
|
|
303
384
|
force: true,
|
|
304
385
|
rowNodes: event.api.getSelectedNodes(),
|
|
305
386
|
});
|
|
306
387
|
}, []);
|
|
307
388
|
|
|
389
|
+
/**
|
|
390
|
+
* Make sure node is selected for editing and start edit
|
|
391
|
+
*/
|
|
308
392
|
const startCellEditing = useCallback(
|
|
309
393
|
(event: CellEvent) => {
|
|
310
394
|
prePopupOps();
|
|
@@ -326,6 +410,9 @@ export const Grid = ({
|
|
|
326
410
|
[checkUpdating, prePopupOps],
|
|
327
411
|
);
|
|
328
412
|
|
|
413
|
+
/**
|
|
414
|
+
* Handle double click edit
|
|
415
|
+
*/
|
|
329
416
|
const onCellDoubleClick = useCallback(
|
|
330
417
|
(event: CellEvent) => {
|
|
331
418
|
if (!invokeEditAction(event)) startCellEditing(event);
|
|
@@ -333,6 +420,9 @@ export const Grid = ({
|
|
|
333
420
|
[startCellEditing],
|
|
334
421
|
);
|
|
335
422
|
|
|
423
|
+
/**
|
|
424
|
+
* Handle single click edits
|
|
425
|
+
*/
|
|
336
426
|
const onCellClicked = useCallback(
|
|
337
427
|
(event: CellEvent) => {
|
|
338
428
|
if (event.colDef?.cellRendererParams?.singleClickEdit) {
|
|
@@ -342,6 +432,9 @@ export const Grid = ({
|
|
|
342
432
|
[startCellEditing],
|
|
343
433
|
);
|
|
344
434
|
|
|
435
|
+
/**
|
|
436
|
+
* If cell has an edit action invoke it (if editable)
|
|
437
|
+
*/
|
|
345
438
|
const invokeEditAction = (e: CellEvent): boolean => {
|
|
346
439
|
const editAction = e.colDef?.cellRendererParams?.editAction;
|
|
347
440
|
if (!editAction) return false;
|
|
@@ -356,6 +449,9 @@ export const Grid = ({
|
|
|
356
449
|
return true;
|
|
357
450
|
};
|
|
358
451
|
|
|
452
|
+
/**
|
|
453
|
+
* Start editing on pressing Enter
|
|
454
|
+
*/
|
|
359
455
|
const onCellKeyPress = useCallback(
|
|
360
456
|
(e: CellEvent) => {
|
|
361
457
|
if ((e.event as KeyboardEvent).key === "Enter") {
|
|
@@ -378,6 +474,85 @@ export const Grid = ({
|
|
|
378
474
|
[columnDefs, sizeColumns],
|
|
379
475
|
);
|
|
380
476
|
|
|
477
|
+
/**
|
|
478
|
+
* Set of colIds that need auto-sizing.
|
|
479
|
+
*/
|
|
480
|
+
const colIdsEdited = useRef(new Set<string>());
|
|
481
|
+
|
|
482
|
+
/**
|
|
483
|
+
* When cell editing has completed tag the colId as needing auto-sizing
|
|
484
|
+
*/
|
|
485
|
+
const onCellEditingStopped = useCallback(
|
|
486
|
+
(e: CellEditingStoppedEvent) => {
|
|
487
|
+
const skipHeader = sizeColumns === "auto-skip-headers";
|
|
488
|
+
if (sizeColumns === "auto" || skipHeader) {
|
|
489
|
+
// This may be wrong as the cell update hasn't completed?
|
|
490
|
+
const colId = e.colDef.colId;
|
|
491
|
+
if (colId && !e.colDef.flex) {
|
|
492
|
+
// This auto-sizes based on updatingContext completing
|
|
493
|
+
colIdsEdited.current.add(colId);
|
|
494
|
+
// This auto-sizes immediately in case it was an in place update
|
|
495
|
+
!isUpdating() &&
|
|
496
|
+
autoSizeColumns({
|
|
497
|
+
skipHeader,
|
|
498
|
+
userSizedColIds: userSizedColIds.current,
|
|
499
|
+
colIds: [colId],
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
},
|
|
504
|
+
[autoSizeColumns, isUpdating, sizeColumns],
|
|
505
|
+
);
|
|
506
|
+
|
|
507
|
+
const lastUpdatedDep = useRef(updatedDep);
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* If columns are edited, wait for the updating context to complete then auto-size them.
|
|
511
|
+
*/
|
|
512
|
+
useEffect(() => {
|
|
513
|
+
if (lastUpdatedDep.current === updatedDep || isEmpty(colIdsEdited.current)) return;
|
|
514
|
+
lastUpdatedDep.current = updatedDep;
|
|
515
|
+
|
|
516
|
+
// Don't update while there are spinners
|
|
517
|
+
if (isUpdating()) return;
|
|
518
|
+
|
|
519
|
+
const skipHeader = sizeColumns === "auto-skip-headers";
|
|
520
|
+
autoSizeColumns({ skipHeader, userSizedColIds: userSizedColIds.current, colIds: colIdsEdited.current });
|
|
521
|
+
colIdsEdited.current.clear();
|
|
522
|
+
}, [autoSizeColumns, updatedDep, sizeColumns, isUpdating]);
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* Resize columns to fit if required on window/container resize
|
|
526
|
+
*/
|
|
527
|
+
const onGridSizeChanged = useCallback(() => {
|
|
528
|
+
if (sizeColumns !== "none") {
|
|
529
|
+
sizeColumnsToFit();
|
|
530
|
+
}
|
|
531
|
+
}, [sizeColumns, sizeColumnsToFit]);
|
|
532
|
+
|
|
533
|
+
/**
|
|
534
|
+
* Set of column Id's that are prevented from auto-sizing as they are user set
|
|
535
|
+
*/
|
|
536
|
+
const userSizedColIds = useRef(new Set<string>());
|
|
537
|
+
|
|
538
|
+
/**
|
|
539
|
+
* Lock/unlock column width on user edit/reset.
|
|
540
|
+
*/
|
|
541
|
+
const onColumnResized = useCallback((e: ColumnResizedEvent) => {
|
|
542
|
+
const colId = e.column?.getColId();
|
|
543
|
+
if (colId == null) return;
|
|
544
|
+
switch (e.source) {
|
|
545
|
+
case "uiColumnDragged":
|
|
546
|
+
userSizedColIds.current.add(colId);
|
|
547
|
+
break;
|
|
548
|
+
case "autosizeColumns":
|
|
549
|
+
userSizedColIds.current.delete(colId);
|
|
550
|
+
break;
|
|
551
|
+
}
|
|
552
|
+
}, []);
|
|
553
|
+
|
|
554
|
+
setOnCellEditingComplete(params.onCellEditingComplete);
|
|
555
|
+
|
|
381
556
|
return (
|
|
382
557
|
<div
|
|
383
558
|
data-testid={dataTestId}
|
|
@@ -388,7 +563,7 @@ export const Grid = ({
|
|
|
388
563
|
gridReady && params.rowData && "Grid-ready",
|
|
389
564
|
)}
|
|
390
565
|
>
|
|
391
|
-
<div style={{ flex: 1 }}>
|
|
566
|
+
<div style={{ flex: 1 }} ref={gridDivRef}>
|
|
392
567
|
<AgGridReact
|
|
393
568
|
animateRows={params.animateRows}
|
|
394
569
|
rowClassRules={params.rowClassRules}
|
|
@@ -396,18 +571,28 @@ export const Grid = ({
|
|
|
396
571
|
suppressRowClickSelection={true}
|
|
397
572
|
rowSelection={rowSelection}
|
|
398
573
|
suppressBrowserResizeObserver={true}
|
|
399
|
-
onGridSizeChanged={
|
|
574
|
+
onGridSizeChanged={onGridSizeChanged}
|
|
400
575
|
suppressColumnVirtualisation={suppressColumnVirtualization}
|
|
401
576
|
suppressClickEdit={true}
|
|
577
|
+
onColumnVisible={() => {
|
|
578
|
+
setInitialContentSize();
|
|
579
|
+
}}
|
|
580
|
+
onRowDataChanged={onRowDataChanged}
|
|
402
581
|
onCellKeyPress={onCellKeyPress}
|
|
403
582
|
onCellClicked={onCellClicked}
|
|
404
583
|
onCellDoubleClicked={onCellDoubleClick}
|
|
405
584
|
onCellEditingStarted={refreshSelectedRows}
|
|
406
585
|
domLayout={params.domLayout}
|
|
586
|
+
onCellEditingStopped={onCellEditingStopped}
|
|
587
|
+
onColumnResized={onColumnResized}
|
|
588
|
+
defaultColDef={{ minWidth: 48, ...omit(params.defaultColDef, ["editable"]) }}
|
|
407
589
|
columnDefs={columnDefsAdjusted}
|
|
408
590
|
rowData={params.rowData}
|
|
409
591
|
noRowsOverlayComponent={GridNoRowsOverlay}
|
|
410
|
-
noRowsOverlayComponentParams={{
|
|
592
|
+
noRowsOverlayComponentParams={{
|
|
593
|
+
rowData: params.rowData,
|
|
594
|
+
noRowsOverlayText: params.noRowsOverlayText,
|
|
595
|
+
}}
|
|
411
596
|
onModelUpdated={onModelUpdated}
|
|
412
597
|
onGridReady={onGridReady}
|
|
413
598
|
onSortChanged={ensureSelectedRowIsVisible}
|
|
@@ -105,6 +105,7 @@ export const GridCell = <RowType extends GridBaseRow, Props extends CellEditorCo
|
|
|
105
105
|
props: GenericCellColDef<RowType>,
|
|
106
106
|
custom?: {
|
|
107
107
|
multiEdit?: boolean;
|
|
108
|
+
preventAutoEdit?: boolean;
|
|
108
109
|
editor?: (editorProps: Props) => JSX.Element;
|
|
109
110
|
editorParams?: Props;
|
|
110
111
|
},
|
|
@@ -123,7 +124,6 @@ export const GridCell = <RowType extends GridBaseRow, Props extends CellEditorCo
|
|
|
123
124
|
headerTooltip: props.headerName,
|
|
124
125
|
sortable: !!(props?.field || props?.valueGetter),
|
|
125
126
|
resizable: true,
|
|
126
|
-
minWidth: props.flex ? 150 : 48,
|
|
127
127
|
editable: props.editable ?? false,
|
|
128
128
|
...(custom?.editor && {
|
|
129
129
|
cellClassRules: GridCellMultiSelectClassRules,
|
|
@@ -132,7 +132,11 @@ export const GridCell = <RowType extends GridBaseRow, Props extends CellEditorCo
|
|
|
132
132
|
}),
|
|
133
133
|
suppressKeyboardEvent: suppressCellKeyboardEvents,
|
|
134
134
|
...(custom?.editorParams && {
|
|
135
|
-
cellEditorParams: {
|
|
135
|
+
cellEditorParams: {
|
|
136
|
+
...custom.editorParams,
|
|
137
|
+
multiEdit: custom.multiEdit,
|
|
138
|
+
preventAutoEdit: custom.preventAutoEdit ?? false,
|
|
139
|
+
},
|
|
136
140
|
}),
|
|
137
141
|
// If there's a valueFormatter and no filterValueGetter then create a filterValueGetter
|
|
138
142
|
filterValueGetter,
|
|
@@ -21,7 +21,7 @@ export interface GridPopoverHookProps<RowType> {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
export const useGridPopoverHook = <RowType extends GridBaseRow>(props: GridPopoverHookProps<RowType>) => {
|
|
24
|
-
const { stopEditing } = useContext(GridContext);
|
|
24
|
+
const { stopEditing, cancelEdit } = useContext(GridContext);
|
|
25
25
|
const { anchorRef, saving, updateValue } = useGridPopoverContext<RowType>();
|
|
26
26
|
const saveButtonRef = useRef<HTMLButtonElement>(null);
|
|
27
27
|
const [isOpen, setOpen] = useState(false);
|
|
@@ -33,7 +33,7 @@ export const useGridPopoverHook = <RowType extends GridBaseRow>(props: GridPopov
|
|
|
33
33
|
const triggerSave = useCallback(
|
|
34
34
|
async (reason?: string) => {
|
|
35
35
|
if (reason == CloseReason.CANCEL) {
|
|
36
|
-
|
|
36
|
+
cancelEdit();
|
|
37
37
|
return;
|
|
38
38
|
}
|
|
39
39
|
if (props.invalid && props.invalid()) {
|
|
@@ -41,7 +41,7 @@ export const useGridPopoverHook = <RowType extends GridBaseRow>(props: GridPopov
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
if (!props.save) {
|
|
44
|
-
|
|
44
|
+
cancelEdit();
|
|
45
45
|
} else if (props.save) {
|
|
46
46
|
// forms that don't provide an invalid fn must wait until they have saved to close
|
|
47
47
|
if (props.invalid) stopEditing();
|
|
@@ -55,7 +55,7 @@ export const useGridPopoverHook = <RowType extends GridBaseRow>(props: GridPopov
|
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
},
|
|
58
|
-
[props, stopEditing, updateValue],
|
|
58
|
+
[cancelEdit, props, stopEditing, updateValue],
|
|
59
59
|
);
|
|
60
60
|
|
|
61
61
|
const popoverWrapper = useCallback(
|
|
@@ -115,14 +115,7 @@ export const GridFormDropDown = <RowType extends GridBaseRow>(props: GridFormDro
|
|
|
115
115
|
: item,
|
|
116
116
|
);
|
|
117
117
|
|
|
118
|
-
|
|
119
|
-
// This is needed otherwise when filter input is rendered and sets autofocus
|
|
120
|
-
// the mouse up of the double click edit triggers the cell to cancel editing
|
|
121
|
-
setOptions(optionsList);
|
|
122
|
-
//delay(() => setOptions(optionsList), 100);
|
|
123
|
-
} else {
|
|
124
|
-
setOptions(optionsList);
|
|
125
|
-
}
|
|
118
|
+
setOptions(optionsList);
|
|
126
119
|
}
|
|
127
120
|
})();
|
|
128
121
|
}, [filter, options, props, selectedRows]);
|
|
@@ -6,6 +6,14 @@ import { ColDefT, GridBaseRow } from "../components";
|
|
|
6
6
|
|
|
7
7
|
export type GridFilterExternal<RowType extends GridBaseRow> = (data: RowType, rowNode: RowNode) => boolean;
|
|
8
8
|
|
|
9
|
+
export interface AutoSizeColumnsProps {
|
|
10
|
+
skipHeader?: boolean;
|
|
11
|
+
colIds?: Set<string> | string[];
|
|
12
|
+
userSizedColIds?: Set<string>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type AutoSizeColumnsResult = { width: number } | null;
|
|
16
|
+
|
|
9
17
|
export interface GridContextType<RowType extends GridBaseRow> {
|
|
10
18
|
gridReady: boolean;
|
|
11
19
|
setApis: (gridApi: GridApi | undefined, columnApi: ColumnApi | undefined, dataTestId?: string) => void;
|
|
@@ -26,8 +34,9 @@ export interface GridContextType<RowType extends GridBaseRow> {
|
|
|
26
34
|
ensureRowVisible: (id: number | string) => boolean;
|
|
27
35
|
ensureSelectedRowIsVisible: () => void;
|
|
28
36
|
getFirstRowId: () => number;
|
|
29
|
-
|
|
37
|
+
autoSizeColumns: (props?: AutoSizeColumnsProps) => AutoSizeColumnsResult;
|
|
30
38
|
sizeColumnsToFit: () => void;
|
|
39
|
+
cancelEdit: () => void;
|
|
31
40
|
stopEditing: () => void;
|
|
32
41
|
updatingCells: (
|
|
33
42
|
props: { selectedRows: GridBaseRow[]; field?: string },
|
|
@@ -47,6 +56,7 @@ export interface GridContextType<RowType extends GridBaseRow> {
|
|
|
47
56
|
invisibleColumnIds: string[];
|
|
48
57
|
setInvisibleColumnIds: (colIds: string[]) => void;
|
|
49
58
|
downloadCsv: (csvExportParams?: CsvExportParams) => void;
|
|
59
|
+
setOnCellEditingComplete: (callback: (() => void) | undefined) => void;
|
|
50
60
|
}
|
|
51
61
|
|
|
52
62
|
export const GridContext = createContext<GridContextType<any>>({
|
|
@@ -117,8 +127,8 @@ export const GridContext = createContext<GridContextType<any>>({
|
|
|
117
127
|
console.error("no context provider for getFirstRowId");
|
|
118
128
|
return -1;
|
|
119
129
|
},
|
|
120
|
-
|
|
121
|
-
console.error("no context provider for
|
|
130
|
+
autoSizeColumns: () => {
|
|
131
|
+
console.error("no context provider for autoSizeColumns");
|
|
122
132
|
return null;
|
|
123
133
|
},
|
|
124
134
|
sizeColumnsToFit: () => {
|
|
@@ -129,6 +139,9 @@ export const GridContext = createContext<GridContextType<any>>({
|
|
|
129
139
|
console.error("no context provider for editingCells");
|
|
130
140
|
return false;
|
|
131
141
|
},
|
|
142
|
+
cancelEdit: () => {
|
|
143
|
+
console.error("no context provider for cancelEdit");
|
|
144
|
+
},
|
|
132
145
|
stopEditing: () => {
|
|
133
146
|
console.error("no context provider for stopEditing");
|
|
134
147
|
},
|
|
@@ -162,6 +175,9 @@ export const GridContext = createContext<GridContextType<any>>({
|
|
|
162
175
|
downloadCsv: () => {
|
|
163
176
|
console.error("no context provider for downloadCsv");
|
|
164
177
|
},
|
|
178
|
+
setOnCellEditingComplete: () => {
|
|
179
|
+
console.error("no context provider for setOnCellEditingComplete");
|
|
180
|
+
},
|
|
165
181
|
});
|
|
166
182
|
|
|
167
183
|
export const useGridContext = <RowType extends GridBaseRow>() => useContext<GridContextType<RowType>>(GridContext);
|