@linzjs/step-ag-grid 28.5.1 → 29.0.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/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 +272 -250
- package/dist/step-ag-grid.cjs.map +1 -1
- package/dist/step-ag-grid.esm.js +273 -251
- 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/GridCell.tsx +6 -2
- package/src/components/GridPopoverHook.tsx +25 -20
- package/src/components/gridFilter/useGridFilter.ts +3 -3
- package/src/components/gridForm/GridFormTextInput.tsx +6 -2
- 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 +3 -3
- 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.1",
|
|
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
|
+
};
|
|
@@ -120,6 +120,11 @@ export const defaultValueFormatter = ({ value }: ValueFormatterParams) => {
|
|
|
120
120
|
: JSON.stringify(value);
|
|
121
121
|
};
|
|
122
122
|
|
|
123
|
+
// ag-grid doesn't understand the custom editor, when it stops editing it thinks
|
|
124
|
+
// that _it_ was editing and overwrites the user updated data
|
|
125
|
+
// _but_, it only does this if the initial value of the cell was null!?
|
|
126
|
+
const blockValueSetter = () => true;
|
|
127
|
+
|
|
123
128
|
/*
|
|
124
129
|
* All cells should use this.
|
|
125
130
|
*/
|
|
@@ -132,12 +137,10 @@ export const GridCell = <TData extends GridBaseRow, TValue = any, Props extends
|
|
|
132
137
|
editorParams?: Props;
|
|
133
138
|
},
|
|
134
139
|
): ColDefT<TData, TValue> => {
|
|
135
|
-
// props.field = ;
|
|
136
140
|
// Generate a default filter value getter which uses the formatted value plus
|
|
137
141
|
// the editable value if it's a string and different from the formatted value.
|
|
138
142
|
// This is so that e.g. bearings can be searched for by DMS or raw number.
|
|
139
143
|
const valueFormatter = props.valueFormatter ?? defaultValueFormatter;
|
|
140
|
-
// FIXME
|
|
141
144
|
const filterValueGetter = props.filterValueGetter ?? generateFilterGetter(valueFormatter as any);
|
|
142
145
|
const exportable = props.exportable;
|
|
143
146
|
// Can't leave this here ag-grid will complain
|
|
@@ -149,6 +152,7 @@ export const GridCell = <TData extends GridBaseRow, TValue = any, Props extends
|
|
|
149
152
|
headerTooltip: props.headerName,
|
|
150
153
|
sortable: true,
|
|
151
154
|
resizable: true,
|
|
155
|
+
valueSetter: custom?.editor ? blockValueSetter : undefined,
|
|
152
156
|
editable: props.editable ?? false,
|
|
153
157
|
...(custom?.editor && {
|
|
154
158
|
cellClassRules: GridCellMultiSelectClassRules,
|
|
@@ -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;
|
|
@@ -29,11 +29,15 @@ export const GridFormTextInput = <TData extends GridBaseRow>(props: GridFormText
|
|
|
29
29
|
|
|
30
30
|
const save = useCallback(
|
|
31
31
|
async (selectedRows: TData[]): Promise<boolean> => {
|
|
32
|
-
if (invalid())
|
|
32
|
+
if (invalid()) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
33
35
|
|
|
34
36
|
const trimmedValue = value.trim();
|
|
35
37
|
// No change, so don't save
|
|
36
|
-
if (initValue === trimmedValue)
|
|
38
|
+
if (initValue === trimmedValue) {
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
37
41
|
|
|
38
42
|
if (props.onSave) {
|
|
39
43
|
return await props.onSave({ selectedRows, value: trimmedValue });
|
|
@@ -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) => {
|