@linzjs/step-ag-grid 28.5.1 → 29.0.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/dist/index.css +11 -7
- package/dist/src/components/Grid.d.ts +5 -1
- package/dist/src/contexts/GridContext.d.ts +3 -4
- package/dist/src/contexts/GridPopoverContext.d.ts +1 -0
- package/dist/src/contexts/GridUpdatingContext.d.ts +1 -0
- package/dist/src/lui/reactUtils.d.ts +4 -0
- package/dist/step-ag-grid.cjs +263 -246
- package/dist/step-ag-grid.cjs.map +1 -1
- package/dist/step-ag-grid.esm.js +264 -247
- package/dist/step-ag-grid.esm.js.map +1 -1
- package/package.json +21 -22
- package/src/components/Grid.tsx +114 -112
- package/src/components/GridPopoverHook.tsx +25 -20
- package/src/components/gridFilter/useGridFilter.ts +3 -3
- package/src/components/gridHook/useGridContextMenu.tsx +3 -3
- package/src/contexts/GridContext.tsx +11 -14
- package/src/contexts/GridContextProvider.tsx +164 -137
- package/src/contexts/GridPopoverContext.tsx +2 -0
- package/src/contexts/GridPopoverContextProvider.tsx +9 -5
- package/src/contexts/GridUpdatingContext.tsx +5 -0
- package/src/contexts/GridUpdatingContextProvider.tsx +35 -28
- package/src/lui/reactUtils.tsx +24 -0
- package/src/react-menu3/components/MenuList.tsx +3 -0
- package/src/stories/grid/GridFilterButtons.stories.tsx +1 -1
- package/src/stories/grid/GridNonEditableRow.stories.tsx +1 -1
- package/src/stories/grid/GridPinnedRow.stories.tsx +1 -1
- package/src/stories/grid/GridPopoutContextMenu.stories.tsx +3 -3
- package/src/stories/grid/GridPopoutEditGenericTextArea.stories.tsx +2 -2
- package/src/stories/grid/GridPopoverEditDropDown.stories.tsx +8 -4
- package/src/stories/grid/GridPopoverEditMultiSelect.stories.tsx +1 -0
- package/src/stories/grid/GridReadOnly.stories.tsx +1 -1
- package/src/stories/grid/GridViewList.stories.tsx +1 -1
- package/src/stories/grid/gridFormInteraction/GridFormDropDownInteraction.stories.tsx +5 -3
- package/src/stories/grid/gridFormInteraction/GridFormEditBearingCorrectionInteraction.stories.tsx +3 -2
- package/src/stories/grid/gridFormInteraction/GridFormEditBearingInteraction.stories.tsx +3 -2
- package/src/stories/grid/gridFormInteraction/GridFormMultiSelectGridInteraction.stories.tsx +3 -2
- package/src/stories/grid/gridFormInteraction/GridFormMultiSelectInteraction.stories.tsx +3 -2
- package/src/stories/grid/gridFormInteraction/GridFormPopoverMenuInteraction.stories.tsx +3 -2
- package/src/stories/grid/gridFormInteraction/GridFormTextAreaInteraction.stories.tsx +3 -2
- package/src/stories/grid/gridFormInteraction/GridFormTextInputInteraction.stories.tsx +3 -2
- package/src/stories/grid/gridFormStatic/GridFormDropDown.stories.tsx +2 -2
- package/src/stories/grid/interactions/GridKeyboardInteractions.stories.tsx +2 -2
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": "
|
|
5
|
+
"version": "29.0.0",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"aggrid",
|
|
8
8
|
"ag-grid",
|
|
@@ -28,8 +28,8 @@
|
|
|
28
28
|
},
|
|
29
29
|
"peerDependencies": {
|
|
30
30
|
"@linzjs/lui": ">=21",
|
|
31
|
-
"ag-grid-community": "^34.
|
|
32
|
-
"ag-grid-react": "^34.
|
|
31
|
+
"ag-grid-community": "^34.2.0",
|
|
32
|
+
"ag-grid-react": "^34.2.0",
|
|
33
33
|
"lodash-es": ">=4",
|
|
34
34
|
"react": ">=18",
|
|
35
35
|
"react-dom": ">=18"
|
|
@@ -76,21 +76,21 @@
|
|
|
76
76
|
]
|
|
77
77
|
},
|
|
78
78
|
"optionalDependencies": {
|
|
79
|
-
"@rollup/rollup-linux-x64-gnu": "^4.
|
|
80
|
-
"@swc/core-linux-x64-gnu": "^1.13.
|
|
79
|
+
"@rollup/rollup-linux-x64-gnu": "^4.52.3",
|
|
80
|
+
"@swc/core-linux-x64-gnu": "^1.13.20"
|
|
81
81
|
},
|
|
82
82
|
"devDependencies": {
|
|
83
|
-
"@chromatic-com/storybook": "^4.
|
|
83
|
+
"@chromatic-com/storybook": "^4.1.1",
|
|
84
84
|
"@linzjs/lui": "^23.11.1",
|
|
85
85
|
"@linzjs/style": "^5.4.0",
|
|
86
86
|
"@rollup/plugin-commonjs": "^28.0.6",
|
|
87
87
|
"@rollup/plugin-json": "^6.1.0",
|
|
88
88
|
"@rollup/plugin-node-resolve": "^16.0.1",
|
|
89
89
|
"@semantic-release/git": "^10.0.1",
|
|
90
|
-
"@storybook/addon-docs": "^9.1.
|
|
91
|
-
"@storybook/addon-links": "^9.1.
|
|
92
|
-
"@storybook/react": "^9.1.
|
|
93
|
-
"@storybook/react-vite": "^9.1.
|
|
90
|
+
"@storybook/addon-docs": "^9.1.8",
|
|
91
|
+
"@storybook/addon-links": "^9.1.8",
|
|
92
|
+
"@storybook/react": "^9.1.8",
|
|
93
|
+
"@storybook/react-vite": "^9.1.8",
|
|
94
94
|
"@testing-library/dom": "^10.4.1",
|
|
95
95
|
"@testing-library/react": "^16.3.0",
|
|
96
96
|
"@testing-library/user-event": "^14.6.1",
|
|
@@ -100,42 +100,41 @@
|
|
|
100
100
|
"@types/node": "^22.17.0",
|
|
101
101
|
"@types/react": "^18.3.23",
|
|
102
102
|
"@types/react-dom": "^18.3.7",
|
|
103
|
-
"@types/uuid": "^10.0.0",
|
|
104
103
|
"@vitejs/plugin-react-swc": "^3.11.0",
|
|
105
104
|
"@vitest/ui": "^3.2.4",
|
|
106
|
-
"ag-grid-community": "^34.
|
|
107
|
-
"ag-grid-react": "^34.
|
|
105
|
+
"ag-grid-community": "^34.2.0",
|
|
106
|
+
"ag-grid-react": "^34.2.0",
|
|
108
107
|
"babel-preset-react-app": "^10.1.0",
|
|
109
108
|
"canvas": "^3.2.0",
|
|
110
|
-
"chromatic": "^13.
|
|
111
|
-
"cross-env": "^10.
|
|
109
|
+
"chromatic": "^13.3.0",
|
|
110
|
+
"cross-env": "^10.1.0",
|
|
112
111
|
"css-loader": "^7.1.2",
|
|
113
112
|
"eslint-plugin-react": "^7.37.5",
|
|
114
|
-
"eslint-plugin-storybook": "^9.1.
|
|
113
|
+
"eslint-plugin-storybook": "^9.1.8",
|
|
115
114
|
"jsdom": "^26.1.0",
|
|
116
115
|
"lodash-es": "^4.17.21",
|
|
117
116
|
"mkdirp": "^3.0.1",
|
|
118
117
|
"npm-run-all": "^4.1.5",
|
|
119
118
|
"postcss": "^8.5.6",
|
|
120
|
-
"postcss-loader": "^8.
|
|
119
|
+
"postcss-loader": "^8.2.0",
|
|
121
120
|
"postcss-scss": "^4.0.9",
|
|
122
121
|
"react": ">=18",
|
|
123
122
|
"react-app-polyfill": "^3.0.0",
|
|
124
123
|
"react-dom": "^18.3.1",
|
|
125
124
|
"rimraf": "^6.0.1",
|
|
126
|
-
"rollup": "^4.
|
|
125
|
+
"rollup": "^4.52.3",
|
|
127
126
|
"rollup-plugin-copy": "^3.5.0",
|
|
128
127
|
"rollup-plugin-peer-deps-external": "^2.2.4",
|
|
129
128
|
"rollup-plugin-postcss": "^4.0.2",
|
|
130
129
|
"rollup-plugin-typescript2": "^0.36.0",
|
|
131
|
-
"sass": "^1.
|
|
130
|
+
"sass": "^1.93.2",
|
|
132
131
|
"sass-loader": "^16.0.5",
|
|
133
|
-
"semantic-release": "^24.2.
|
|
134
|
-
"storybook": "^9.1.
|
|
132
|
+
"semantic-release": "^24.2.9",
|
|
133
|
+
"storybook": "^9.1.8",
|
|
135
134
|
"storybook-css-modules-preset": "^1.1.1",
|
|
136
135
|
"style-loader": "^4.0.0",
|
|
137
136
|
"typescript": "^5.9.2",
|
|
138
|
-
"vite": "^
|
|
137
|
+
"vite": "^7.1.7",
|
|
139
138
|
"vite-plugin-html": "^3.2.2",
|
|
140
139
|
"vite-tsconfig-paths": "^5.1.4",
|
|
141
140
|
"vitest": "^3.2.4"
|
package/src/components/Grid.tsx
CHANGED
|
@@ -4,13 +4,14 @@ import {
|
|
|
4
4
|
CellClassParams,
|
|
5
5
|
CellClickedEvent,
|
|
6
6
|
CellDoubleClickedEvent,
|
|
7
|
-
|
|
7
|
+
CellFocusedEvent,
|
|
8
8
|
CellKeyDownEvent,
|
|
9
9
|
ColDef,
|
|
10
10
|
ColGroupDef,
|
|
11
11
|
ColumnResizedEvent,
|
|
12
12
|
EditableCallback,
|
|
13
13
|
EditableCallbackParams,
|
|
14
|
+
GetRowIdParams,
|
|
14
15
|
GridOptions,
|
|
15
16
|
GridReadyEvent,
|
|
16
17
|
ModelUpdatedEvent,
|
|
@@ -18,6 +19,7 @@ import {
|
|
|
18
19
|
RowDragEndEvent,
|
|
19
20
|
RowDragMoveEvent,
|
|
20
21
|
SelectionChangedEvent,
|
|
22
|
+
SelectionColumnDef,
|
|
21
23
|
} from 'ag-grid-community';
|
|
22
24
|
import { AgGridReact } from 'ag-grid-react';
|
|
23
25
|
import clsx from 'clsx';
|
|
@@ -25,7 +27,7 @@ import { defer, difference, isEmpty, last, omit, xorBy } from 'lodash-es';
|
|
|
25
27
|
import { ReactElement, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
|
|
26
28
|
import { useInterval } from 'usehooks-ts';
|
|
27
29
|
|
|
28
|
-
import {
|
|
30
|
+
import { useGridContext } from '../contexts/GridContext';
|
|
29
31
|
import { GridUpdatingContext } from '../contexts/GridUpdatingContext';
|
|
30
32
|
import { fnOrVar, isNotEmpty } from '../utils/util';
|
|
31
33
|
import { clickInputWhenContainingCellClicked } from './clickInputWhenContainingCellClicked';
|
|
@@ -36,36 +38,6 @@ import { usePostSortRowsHook } from './PostSortRowsHook';
|
|
|
36
38
|
|
|
37
39
|
ModuleRegistry.registerModules([AllCommunityModule]);
|
|
38
40
|
|
|
39
|
-
let timeOfLastSingleClick = 0;
|
|
40
|
-
let lastClickColId: unknown;
|
|
41
|
-
let lastClickRowIndex: unknown;
|
|
42
|
-
|
|
43
|
-
const resetClickDebounce = () => {
|
|
44
|
-
timeOfLastSingleClick = 0;
|
|
45
|
-
lastClickColId = '';
|
|
46
|
-
lastClickRowIndex = -1;
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* If click is more than 200ms since last click return true.
|
|
51
|
-
*/
|
|
52
|
-
const clickDebounceSkipClick = (colId: unknown, rowIndex: unknown): boolean => {
|
|
53
|
-
const doubleClickMs = 200;
|
|
54
|
-
|
|
55
|
-
if (
|
|
56
|
-
Date.now() - timeOfLastSingleClick < doubleClickMs &&
|
|
57
|
-
lastClickColId === colId &&
|
|
58
|
-
lastClickRowIndex === rowIndex
|
|
59
|
-
) {
|
|
60
|
-
// Skipping double click due to single click edit
|
|
61
|
-
return true;
|
|
62
|
-
}
|
|
63
|
-
timeOfLastSingleClick = Date.now();
|
|
64
|
-
lastClickColId = colId;
|
|
65
|
-
lastClickRowIndex = rowIndex;
|
|
66
|
-
return false;
|
|
67
|
-
};
|
|
68
|
-
|
|
69
41
|
export interface GridBaseRow {
|
|
70
42
|
id: string | number;
|
|
71
43
|
}
|
|
@@ -99,6 +71,7 @@ export interface GridProps<TData extends GridBaseRow = GridBaseRow> {
|
|
|
99
71
|
rowClassRules?: GridOptions['rowClassRules'];
|
|
100
72
|
rowSelection?: 'single' | 'multiple';
|
|
101
73
|
autoSelectFirstRow?: boolean;
|
|
74
|
+
onCellFocused?: (props: { colDef: ColDef<TData>; data: TData }) => void;
|
|
102
75
|
onColumnMoved?: GridOptions['onColumnMoved'];
|
|
103
76
|
rowDragText?: GridOptions['rowDragText'];
|
|
104
77
|
onRowDragEnd?: (props: GridOnRowDragEndProps<TData>) => Promise<void> | void;
|
|
@@ -126,7 +99,7 @@ export interface GridProps<TData extends GridBaseRow = GridBaseRow> {
|
|
|
126
99
|
* When pressing tab whilst editing the grid will select and edit the next cell if available.
|
|
127
100
|
* Once the last cell to edit closes this callback is called.
|
|
128
101
|
*/
|
|
129
|
-
|
|
102
|
+
onBulkEditingComplete?: () => void;
|
|
130
103
|
|
|
131
104
|
/**
|
|
132
105
|
* Context menu definition if required.
|
|
@@ -182,13 +155,13 @@ export const Grid = <TData extends GridBaseRow = GridBaseRow>({
|
|
|
182
155
|
setExternallySelectedItemsAreInSync,
|
|
183
156
|
isExternalFilterPresent,
|
|
184
157
|
doesExternalFilterPass,
|
|
185
|
-
|
|
158
|
+
setOnBulkEditingComplete,
|
|
186
159
|
getColDef,
|
|
187
160
|
showNoRowsOverlay,
|
|
188
161
|
prePopupOps,
|
|
189
|
-
|
|
190
|
-
} =
|
|
191
|
-
|
|
162
|
+
startCellEditing,
|
|
163
|
+
} = useGridContext<TData>();
|
|
164
|
+
|
|
192
165
|
const { updatedDep, updatingCols } = useContext(GridUpdatingContext);
|
|
193
166
|
|
|
194
167
|
const gridDivRef = useRef<HTMLDivElement>(null);
|
|
@@ -441,28 +414,11 @@ export const Grid = <TData extends GridBaseRow = GridBaseRow>({
|
|
|
441
414
|
event.api.showNoRowsOverlay();
|
|
442
415
|
}, []);
|
|
443
416
|
|
|
444
|
-
/**
|
|
445
|
-
* Force-refresh all selected rows to re-run class function, to update selection highlighting
|
|
446
|
-
*/
|
|
447
|
-
const refreshSelectedRows = useCallback((_event: CellEditingStartedEvent): void => {
|
|
448
|
-
// MATT Disabled I don't believe these are needed anymore
|
|
449
|
-
// I've left them here just in case they are
|
|
450
|
-
/*event.api.refreshCells({
|
|
451
|
-
force: true,
|
|
452
|
-
rowNodes: event.api.getSelectedNodes(),
|
|
453
|
-
});*/
|
|
454
|
-
}, []);
|
|
455
|
-
|
|
456
417
|
/**
|
|
457
418
|
* Handle double click edit
|
|
458
419
|
*/
|
|
459
420
|
const onCellDoubleClick = useCallback(
|
|
460
421
|
(event: CellDoubleClickedEvent) => {
|
|
461
|
-
if (clickDebounceSkipClick(event.colDef.colId, event.rowIndex)) {
|
|
462
|
-
// the next click will be a single click, we want it to pass
|
|
463
|
-
resetClickDebounce();
|
|
464
|
-
return;
|
|
465
|
-
}
|
|
466
422
|
const editable = fnOrVar(event.colDef?.editable, event);
|
|
467
423
|
if (editable && !invokeEditAction(event)) {
|
|
468
424
|
void startCellEditing({ rowId: event.data.id, colId: event.column.getColId() });
|
|
@@ -478,9 +434,6 @@ export const Grid = <TData extends GridBaseRow = GridBaseRow>({
|
|
|
478
434
|
(event: CellClickedEvent) => {
|
|
479
435
|
const editable = fnOrVar(event.colDef?.editable, event);
|
|
480
436
|
if ((editable && event.colDef.singleClickEdit) ?? singleClickEdit) {
|
|
481
|
-
if (clickDebounceSkipClick(event.colDef.colId, event.rowIndex)) {
|
|
482
|
-
return;
|
|
483
|
-
}
|
|
484
437
|
void startCellEditing({ rowId: event.data.id, colId: event.column.getColId() });
|
|
485
438
|
}
|
|
486
439
|
},
|
|
@@ -590,11 +543,10 @@ export const Grid = <TData extends GridBaseRow = GridBaseRow>({
|
|
|
590
543
|
useEffect(() => {
|
|
591
544
|
const newLoading = !rowData || params.loading === true;
|
|
592
545
|
if (newLoading && !prevLoading.current) {
|
|
593
|
-
stopEditing();
|
|
594
546
|
showNoRowsOverlay();
|
|
595
547
|
}
|
|
596
548
|
prevLoading.current = newLoading;
|
|
597
|
-
}, [params.loading, rowData, showNoRowsOverlay
|
|
549
|
+
}, [params.loading, rowData, showNoRowsOverlay]);
|
|
598
550
|
|
|
599
551
|
/**
|
|
600
552
|
* Resize columns to fit if required on window/container resize
|
|
@@ -667,6 +619,27 @@ export const Grid = <TData extends GridBaseRow = GridBaseRow>({
|
|
|
667
619
|
[clearHighlightRowClasses],
|
|
668
620
|
);
|
|
669
621
|
|
|
622
|
+
const onCellFocused = useCallback(
|
|
623
|
+
(event: CellFocusedEvent<TData>) => {
|
|
624
|
+
if (!params.onCellFocused || event.rowIndex == null) {
|
|
625
|
+
return;
|
|
626
|
+
}
|
|
627
|
+
const api = event.api;
|
|
628
|
+
const rowNode = api.getDisplayedRowAtIndex(event.rowIndex);
|
|
629
|
+
const data = rowNode?.data;
|
|
630
|
+
const column = event.column;
|
|
631
|
+
if (!data || !column || typeof column === 'string') {
|
|
632
|
+
return;
|
|
633
|
+
}
|
|
634
|
+
const colDef = column.getColDef();
|
|
635
|
+
if (!colDef || typeof colDef === 'string') {
|
|
636
|
+
return;
|
|
637
|
+
}
|
|
638
|
+
params.onCellFocused({ colDef, data });
|
|
639
|
+
},
|
|
640
|
+
[params],
|
|
641
|
+
);
|
|
642
|
+
|
|
670
643
|
const onRowDragEnd = useCallback(
|
|
671
644
|
(event: RowDragEndEvent<TData>) => {
|
|
672
645
|
clearHighlightRowClasses();
|
|
@@ -698,10 +671,77 @@ export const Grid = <TData extends GridBaseRow = GridBaseRow>({
|
|
|
698
671
|
}, [params.setExternalSelectedItems, selectable]);
|
|
699
672
|
|
|
700
673
|
// This is setting a ref in the GridContext so won't be triggering an update loop
|
|
701
|
-
|
|
674
|
+
setOnBulkEditingComplete(params.onBulkEditingComplete);
|
|
675
|
+
|
|
676
|
+
const getRowId = useCallback((params: GetRowIdParams<TData, unknown>) => `${params.data.id}`, []);
|
|
677
|
+
const defaultColDef = useMemo(
|
|
678
|
+
(): ColDef<TData, unknown> => ({
|
|
679
|
+
minWidth: 48,
|
|
680
|
+
...omit(params.defaultColDef, ['editable', 'field', 'colId', 'tooltipField']),
|
|
681
|
+
}),
|
|
682
|
+
[params.defaultColDef],
|
|
683
|
+
);
|
|
684
|
+
|
|
685
|
+
const noRowsOverlayComponent = useCallback(
|
|
686
|
+
(event: AgGridEvent) => {
|
|
687
|
+
const headerRowCount = columnDefs.some((c) => (c as any).children) ? 2 : 1;
|
|
688
|
+
|
|
689
|
+
let rowCount = 0;
|
|
690
|
+
event.api.forEachNode(() => rowCount++);
|
|
691
|
+
return (
|
|
692
|
+
<GridNoRowsOverlay
|
|
693
|
+
loading={!rowData || params.loading === true}
|
|
694
|
+
rowCount={rowCount}
|
|
695
|
+
headerRowHeight={headerRowCount * rowHeight}
|
|
696
|
+
filteredRowCount={event.api.getDisplayedRowCount()}
|
|
697
|
+
noRowsOverlayText={params.noRowsOverlayText}
|
|
698
|
+
noRowsMatchingOverlayText={params.noRowsMatchingOverlayText}
|
|
699
|
+
/>
|
|
700
|
+
);
|
|
701
|
+
},
|
|
702
|
+
[columnDefs, params.loading, params.noRowsMatchingOverlayText, params.noRowsOverlayText, rowData, rowHeight],
|
|
703
|
+
);
|
|
704
|
+
|
|
705
|
+
const selectionColumnDef = useMemo((): SelectionColumnDef => {
|
|
706
|
+
const selectWidth = params.hideSelectColumn ? 0 : selectable && params.onRowDragEnd ? 76 : 48;
|
|
707
|
+
return {
|
|
708
|
+
suppressNavigable: params.hideSelectColumn,
|
|
709
|
+
rowDrag: !!params.onRowDragEnd,
|
|
710
|
+
minWidth: selectWidth,
|
|
711
|
+
maxWidth: selectWidth,
|
|
712
|
+
pinned: selectColumnPinned,
|
|
713
|
+
headerComponentParams: {
|
|
714
|
+
exportable: false,
|
|
715
|
+
},
|
|
716
|
+
headerClass: clsx('ag-header-hide-default-select', params.onRowDragEnd && 'ag-header-select-draggable'),
|
|
717
|
+
headerComponent: rowSelection == 'multiple' ? GridHeaderSelect : undefined,
|
|
718
|
+
suppressHeaderKeyboardEvent: (e) => {
|
|
719
|
+
if (!selectable) return false;
|
|
720
|
+
if ((e.event.key === 'Enter' || e.event.key === ' ') && !e.event.repeat) {
|
|
721
|
+
if (isEmpty(e.api.getSelectedRows())) {
|
|
722
|
+
e.api.selectAll('filtered');
|
|
723
|
+
} else {
|
|
724
|
+
e.api.deselectAll();
|
|
725
|
+
}
|
|
726
|
+
return true;
|
|
727
|
+
}
|
|
728
|
+
return false;
|
|
729
|
+
},
|
|
730
|
+
onCellClicked:
|
|
731
|
+
params.enableSelectionWithoutKeys || params.enableClickSelection
|
|
732
|
+
? undefined
|
|
733
|
+
: clickInputWhenContainingCellClicked,
|
|
734
|
+
};
|
|
735
|
+
}, [
|
|
736
|
+
params.enableClickSelection,
|
|
737
|
+
params.enableSelectionWithoutKeys,
|
|
738
|
+
params.hideSelectColumn,
|
|
739
|
+
params.onRowDragEnd,
|
|
740
|
+
rowSelection,
|
|
741
|
+
selectColumnPinned,
|
|
742
|
+
selectable,
|
|
743
|
+
]);
|
|
702
744
|
|
|
703
|
-
const selectWidth = params.hideSelectColumn ? 0 : selectable && params.onRowDragEnd ? 76 : 48;
|
|
704
|
-
const headerRowCount = columnDefs.some((c) => (c as any).children) ? 2 : 1;
|
|
705
745
|
return (
|
|
706
746
|
<div
|
|
707
747
|
data-testid={dataTestId}
|
|
@@ -729,45 +769,30 @@ export const Grid = <TData extends GridBaseRow = GridBaseRow>({
|
|
|
729
769
|
rowHeight={rowHeight}
|
|
730
770
|
animateRows={params.animateRows ?? false}
|
|
731
771
|
rowClassRules={params.rowClassRules}
|
|
732
|
-
getRowId={
|
|
772
|
+
getRowId={getRowId}
|
|
733
773
|
onGridSizeChanged={onGridSizeChanged}
|
|
734
774
|
suppressColumnVirtualisation={suppressColumnVirtualization}
|
|
735
775
|
suppressClickEdit={true}
|
|
736
776
|
onColumnVisible={setInitialContentSize}
|
|
737
777
|
onRowDataUpdated={onRowDataChanged}
|
|
778
|
+
onCellFocused={onCellFocused}
|
|
738
779
|
onCellKeyDown={onCellKeyPress}
|
|
739
780
|
onCellClicked={onCellClicked}
|
|
740
781
|
onCellDoubleClicked={onCellDoubleClick}
|
|
741
|
-
onCellEditingStarted={refreshSelectedRows}
|
|
742
782
|
domLayout={params.domLayout}
|
|
743
783
|
onColumnResized={onColumnResized}
|
|
744
|
-
defaultColDef={
|
|
784
|
+
defaultColDef={defaultColDef}
|
|
745
785
|
columnDefs={columnDefsAdjusted}
|
|
786
|
+
selectionColumnDef={selectionColumnDef}
|
|
746
787
|
rowData={rowData}
|
|
747
|
-
|
|
748
|
-
let rowCount = 0;
|
|
749
|
-
event.api.forEachNode(() => rowCount++);
|
|
750
|
-
return (
|
|
751
|
-
<GridNoRowsOverlay
|
|
752
|
-
loading={!rowData || params.loading === true}
|
|
753
|
-
rowCount={rowCount}
|
|
754
|
-
headerRowHeight={headerRowCount * rowHeight}
|
|
755
|
-
filteredRowCount={event.api.getDisplayedRowCount()}
|
|
756
|
-
noRowsOverlayText={params.noRowsOverlayText}
|
|
757
|
-
noRowsMatchingOverlayText={params.noRowsMatchingOverlayText}
|
|
758
|
-
/>
|
|
759
|
-
);
|
|
760
|
-
}}
|
|
761
|
-
quickFilterParser={(filterStr) => {
|
|
762
|
-
// filter is exact matches exactly groups separated by commas
|
|
763
|
-
return filterStr.split(',').map((str) => str.trim());
|
|
764
|
-
}}
|
|
788
|
+
postSortRows={params.onRowDragEnd || !defaultPostSort ? undefined : postSortRows}
|
|
765
789
|
onModelUpdated={onModelUpdated}
|
|
766
790
|
onGridReady={onGridReady}
|
|
767
791
|
onSortChanged={ensureSelectedRowIsVisible}
|
|
768
|
-
|
|
792
|
+
quickFilterParser={quickFilterParser}
|
|
769
793
|
onSelectionChanged={synchroniseExternalStateToGridSelection}
|
|
770
794
|
onColumnMoved={params.onColumnMoved}
|
|
795
|
+
noRowsOverlayComponent={noRowsOverlayComponent}
|
|
771
796
|
alwaysShowVerticalScroll={params.alwaysShowVerticalScroll}
|
|
772
797
|
isExternalFilterPresent={isExternalFilterPresent}
|
|
773
798
|
doesExternalFilterPass={doesExternalFilterPass}
|
|
@@ -781,36 +806,13 @@ export const Grid = <TData extends GridBaseRow = GridBaseRow>({
|
|
|
781
806
|
suppressCellFocus={params.suppressCellFocus}
|
|
782
807
|
pinnedTopRowData={params.pinnedTopRowData}
|
|
783
808
|
pinnedBottomRowData={params.pinnedBottomRowData}
|
|
784
|
-
selectionColumnDef={{
|
|
785
|
-
suppressNavigable: params.hideSelectColumn,
|
|
786
|
-
rowDrag: !!params.onRowDragEnd,
|
|
787
|
-
minWidth: selectWidth,
|
|
788
|
-
maxWidth: selectWidth,
|
|
789
|
-
pinned: selectColumnPinned,
|
|
790
|
-
headerComponentParams: {
|
|
791
|
-
exportable: false,
|
|
792
|
-
},
|
|
793
|
-
headerClass: clsx('ag-header-hide-default-select', params.onRowDragEnd && 'ag-header-select-draggable'),
|
|
794
|
-
headerComponent: rowSelection == 'multiple' ? GridHeaderSelect : undefined,
|
|
795
|
-
suppressHeaderKeyboardEvent: (e) => {
|
|
796
|
-
if (!selectable) return false;
|
|
797
|
-
if ((e.event.key === 'Enter' || e.event.key === ' ') && !e.event.repeat) {
|
|
798
|
-
if (isEmpty(e.api.getSelectedRows())) {
|
|
799
|
-
e.api.selectAll('filtered');
|
|
800
|
-
} else {
|
|
801
|
-
e.api.deselectAll();
|
|
802
|
-
}
|
|
803
|
-
return true;
|
|
804
|
-
}
|
|
805
|
-
return false;
|
|
806
|
-
},
|
|
807
|
-
onCellClicked:
|
|
808
|
-
params.enableSelectionWithoutKeys || params.enableClickSelection
|
|
809
|
-
? undefined
|
|
810
|
-
: clickInputWhenContainingCellClicked,
|
|
811
|
-
}}
|
|
812
809
|
/>
|
|
813
810
|
</div>
|
|
814
811
|
</div>
|
|
815
812
|
);
|
|
816
813
|
};
|
|
814
|
+
|
|
815
|
+
const quickFilterParser = (filterStr: string) => {
|
|
816
|
+
// filter is exact matches exactly groups separated by commas
|
|
817
|
+
return filterStr.split(',').map((str) => str.trim());
|
|
818
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { ReactElement, useCallback,
|
|
1
|
+
import { ReactElement, useCallback, useEffect, useRef, useState } from 'react';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { useGridContext } from '../contexts/GridContext';
|
|
4
4
|
import { useGridPopoverContext } from '../contexts/GridPopoverContext';
|
|
5
5
|
import { ControlledMenu } from '../react-menu3';
|
|
6
6
|
import { MenuCloseEvent } from '../react-menu3/types';
|
|
@@ -21,8 +21,8 @@ export interface GridPopoverHookProps<TData> {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
export const useGridPopoverHook = <TData extends GridBaseRow>(props: GridPopoverHookProps<TData>) => {
|
|
24
|
-
const {
|
|
25
|
-
const { anchorRef, saving, updateValue } = useGridPopoverContext<TData>();
|
|
24
|
+
const { onBulkEditingComplete } = useGridContext<TData>();
|
|
25
|
+
const { anchorRef, saving, updateValue, stopEditing } = useGridPopoverContext<TData>();
|
|
26
26
|
const saveButtonRef = useRef<HTMLButtonElement>(null);
|
|
27
27
|
const [isOpen, setOpen] = useState(false);
|
|
28
28
|
|
|
@@ -33,29 +33,32 @@ export const useGridPopoverHook = <TData extends GridBaseRow>(props: GridPopover
|
|
|
33
33
|
const triggerSave = useCallback(
|
|
34
34
|
async (reason?: string) => {
|
|
35
35
|
if (reason == CloseReason.CANCEL) {
|
|
36
|
-
|
|
36
|
+
stopEditing();
|
|
37
|
+
onBulkEditingComplete();
|
|
37
38
|
return;
|
|
38
39
|
}
|
|
39
|
-
if (props
|
|
40
|
+
if (props?.invalid?.()) {
|
|
41
|
+
// Don't close, don't do anything it's invalid
|
|
40
42
|
return;
|
|
41
43
|
}
|
|
42
44
|
|
|
43
45
|
if (!props.save) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
46
|
+
// No save method so just close
|
|
47
|
+
stopEditing();
|
|
48
|
+
onBulkEditingComplete();
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (
|
|
53
|
+
await updateValue(
|
|
54
|
+
props.save,
|
|
55
|
+
reason === CloseReason.TAB_FORWARD ? 1 : reason === CloseReason.TAB_BACKWARD ? -1 : 0,
|
|
56
|
+
)
|
|
57
|
+
) {
|
|
58
|
+
stopEditing();
|
|
56
59
|
}
|
|
57
60
|
},
|
|
58
|
-
[
|
|
61
|
+
[onBulkEditingComplete, props, stopEditing, updateValue],
|
|
59
62
|
);
|
|
60
63
|
|
|
61
64
|
const popoverWrapper = useCallback(
|
|
@@ -72,7 +75,9 @@ export const useGridPopoverHook = <TData extends GridBaseRow>(props: GridPopover
|
|
|
72
75
|
menuClassName={'step-ag-grid-react-menu'}
|
|
73
76
|
onClose={(event: MenuCloseEvent) => {
|
|
74
77
|
// Prevent menu from closing when modals are invoked
|
|
75
|
-
if (event.reason === CloseReason.BLUR)
|
|
78
|
+
if (event.reason === CloseReason.BLUR) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
76
81
|
void triggerSave(event.reason);
|
|
77
82
|
}}
|
|
78
83
|
viewScroll={'auto'}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useEffect } from 'react';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { GridFilterExternal, useGridContext } from '../../contexts/GridContext';
|
|
4
4
|
import { GridBaseRow } from '../Grid';
|
|
5
5
|
|
|
6
6
|
export const useGridFilter = <TData extends GridBaseRow>(filter: GridFilterExternal<TData> | undefined) => {
|
|
7
|
-
const { addExternalFilter, removeExternalFilter } =
|
|
7
|
+
const { addExternalFilter, removeExternalFilter } = useGridContext<TData>();
|
|
8
8
|
|
|
9
9
|
useEffect(() => {
|
|
10
10
|
const thisFilter = filter;
|
|
@@ -24,7 +24,7 @@ export const useGridContextMenu = <TData extends GridBaseRow>({
|
|
|
24
24
|
contextMenuSelectRow: boolean;
|
|
25
25
|
contextMenu?: GridContextMenuComponent<TData>;
|
|
26
26
|
}) => {
|
|
27
|
-
const { redrawRows, prePopupOps,
|
|
27
|
+
const { redrawRows, prePopupOps, resetFocusedCellAfterCellEditing, getSelectedRows } = useContext(GridContext);
|
|
28
28
|
|
|
29
29
|
const [isOpen, setOpen] = useState(false);
|
|
30
30
|
const [anchorPoint, setAnchorPoint] = useState({ x: 0, y: 0 });
|
|
@@ -47,8 +47,8 @@ export const useGridContextMenu = <TData extends GridBaseRow>({
|
|
|
47
47
|
const closeMenu = useCallback(() => {
|
|
48
48
|
setOpen(false);
|
|
49
49
|
redrawRows();
|
|
50
|
-
|
|
51
|
-
}, [
|
|
50
|
+
resetFocusedCellAfterCellEditing();
|
|
51
|
+
}, [resetFocusedCellAfterCellEditing, redrawRows]);
|
|
52
52
|
|
|
53
53
|
const cellContextMenu = useCallback(
|
|
54
54
|
(event: CellContextMenuEvent) => {
|
|
@@ -25,7 +25,6 @@ export interface GridContextType<TData extends GridBaseRow> {
|
|
|
25
25
|
getColumnIds: (filter?: keyof ColDef | ((r: ColDef) => boolean | undefined | null | number | string)) => string[];
|
|
26
26
|
setApis: (gridApi: GridApi | undefined, hasExternallySelectedItems: boolean, dataTestId?: string) => void;
|
|
27
27
|
prePopupOps: () => void;
|
|
28
|
-
postPopupOps: () => void;
|
|
29
28
|
setQuickFilter: (quickFilter: string) => void;
|
|
30
29
|
editingCells: () => boolean;
|
|
31
30
|
getSelectedRows: <T extends GridBaseRow>() => T[];
|
|
@@ -44,9 +43,9 @@ export interface GridContextType<TData extends GridBaseRow> {
|
|
|
44
43
|
getFirstRowId: () => number;
|
|
45
44
|
autoSizeColumns: (props?: AutoSizeColumnsProps) => AutoSizeColumnsResult;
|
|
46
45
|
sizeColumnsToFit: () => void;
|
|
47
|
-
cancelEdit: () => void;
|
|
48
46
|
startCellEditing: ({ rowId, colId }: { rowId: number; colId: string }) => Promise<void>;
|
|
49
|
-
|
|
47
|
+
// Restores the previous focus after cell editing
|
|
48
|
+
resetFocusedCellAfterCellEditing: () => void;
|
|
50
49
|
updatingCells: (
|
|
51
50
|
props: { selectedRows: GridBaseRow[]; field?: string },
|
|
52
51
|
fnUpdate: (selectedRows: any[]) => Promise<boolean>,
|
|
@@ -64,7 +63,8 @@ export interface GridContextType<TData extends GridBaseRow> {
|
|
|
64
63
|
invisibleColumnIds: string[] | undefined;
|
|
65
64
|
setInvisibleColumnIds: (colIds: string[]) => void;
|
|
66
65
|
downloadCsv: (csvExportParams?: CsvExportParams) => void;
|
|
67
|
-
|
|
66
|
+
onBulkEditingComplete: () => void;
|
|
67
|
+
setOnBulkEditingComplete: (callback: (() => void) | undefined) => void;
|
|
68
68
|
showNoRowsOverlay: () => void;
|
|
69
69
|
}
|
|
70
70
|
|
|
@@ -90,9 +90,6 @@ export const GridContext = createContext<GridContextType<any>>({
|
|
|
90
90
|
prePopupOps: () => {
|
|
91
91
|
console.error('no context provider for prePopupOps');
|
|
92
92
|
},
|
|
93
|
-
postPopupOps: () => {
|
|
94
|
-
console.error('no context provider for prePopupOps');
|
|
95
|
-
},
|
|
96
93
|
externallySelectedItemsAreInSync: false,
|
|
97
94
|
setApis: () => {
|
|
98
95
|
console.error('no context provider for setApis');
|
|
@@ -164,15 +161,12 @@ export const GridContext = createContext<GridContextType<any>>({
|
|
|
164
161
|
console.error('no context provider for editingCells');
|
|
165
162
|
return false;
|
|
166
163
|
},
|
|
167
|
-
cancelEdit: () => {
|
|
168
|
-
console.error('no context provider for cancelEdit');
|
|
169
|
-
},
|
|
170
164
|
// eslint-disable-next-line @typescript-eslint/require-await
|
|
171
165
|
startCellEditing: async () => {
|
|
172
166
|
console.error('no context provider for startCellEditing');
|
|
173
167
|
},
|
|
174
|
-
|
|
175
|
-
console.error('no context provider for
|
|
168
|
+
resetFocusedCellAfterCellEditing: () => {
|
|
169
|
+
console.error('no context provider for resetFocusedCellAfterCellEditing');
|
|
176
170
|
},
|
|
177
171
|
// eslint-disable-next-line @typescript-eslint/require-await
|
|
178
172
|
updatingCells: async () => {
|
|
@@ -206,8 +200,11 @@ export const GridContext = createContext<GridContextType<any>>({
|
|
|
206
200
|
downloadCsv: () => {
|
|
207
201
|
console.error('no context provider for downloadCsv');
|
|
208
202
|
},
|
|
209
|
-
|
|
210
|
-
console.error('no context provider for
|
|
203
|
+
onBulkEditingComplete: () => {
|
|
204
|
+
console.error('no context provider for onBulkEditingComplete');
|
|
205
|
+
},
|
|
206
|
+
setOnBulkEditingComplete: () => {
|
|
207
|
+
console.error('no context provider for setOnBulkEditingComplete');
|
|
211
208
|
},
|
|
212
209
|
showNoRowsOverlay: () => {
|
|
213
210
|
console.error('no context provider for showLoadingOverlay');
|