@linzjs/step-ag-grid 8.2.1 → 8.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/dist/src/contexts/GridContext.d.ts +1 -0
- package/dist/step-ag-grid.esm.js +69 -36
- package/dist/step-ag-grid.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/components/Grid.tsx +21 -9
- package/src/components/GridCell.tsx +2 -1
- package/src/components/gridForm/GridFormDropDown.tsx +20 -11
- package/src/components/gridPopoverEdit/GridPopoverMenu.tsx +2 -2
- package/src/contexts/GridContext.tsx +4 -0
- package/src/contexts/GridContextProvider.tsx +21 -8
- package/src/stories/grid/GridNonEditableRow.stories.tsx +1 -3
package/package.json
CHANGED
package/src/components/Grid.tsx
CHANGED
|
@@ -10,7 +10,7 @@ import { usePostSortRowsHook } from "./PostSortRowsHook";
|
|
|
10
10
|
import { fnOrVar, isNotEmpty } from "../utils/util";
|
|
11
11
|
import { GridHeaderSelect } from "./gridHeader/GridHeaderSelect";
|
|
12
12
|
import { GridUpdatingContext } from "../contexts/GridUpdatingContext";
|
|
13
|
-
import { CellClassParams } from "ag-grid-community/dist/lib/entities/colDef";
|
|
13
|
+
import { CellClassParams, EditableCallback, EditableCallbackParams } from "ag-grid-community/dist/lib/entities/colDef";
|
|
14
14
|
|
|
15
15
|
export interface GridBaseRow {
|
|
16
16
|
id: string | number;
|
|
@@ -46,6 +46,7 @@ export const Grid = (params: GridProps): JSX.Element => {
|
|
|
46
46
|
const {
|
|
47
47
|
gridReady,
|
|
48
48
|
setGridApi,
|
|
49
|
+
prePopupOps,
|
|
49
50
|
setQuickFilter,
|
|
50
51
|
ensureRowVisible,
|
|
51
52
|
selectRowsById,
|
|
@@ -161,6 +162,16 @@ export const Grid = (params: GridProps): JSX.Element => {
|
|
|
161
162
|
updateQuickFilter();
|
|
162
163
|
}, [updateQuickFilter]);
|
|
163
164
|
|
|
165
|
+
const combineEditables =
|
|
166
|
+
(...editables: (boolean | EditableCallback | undefined)[]) =>
|
|
167
|
+
(params: EditableCallbackParams): boolean => {
|
|
168
|
+
const results = editables.map((editable) => fnOrVar(editable, params));
|
|
169
|
+
// If editable is not set anywhere then it's non-editable
|
|
170
|
+
if (results.every((v) => v == null)) return false;
|
|
171
|
+
// If any editable value is or returns false then it's non-editable
|
|
172
|
+
return !results.some((v) => v == false);
|
|
173
|
+
};
|
|
174
|
+
|
|
164
175
|
/**
|
|
165
176
|
* Synchronise externally selected items to grid on externalSelectedItems change
|
|
166
177
|
*/
|
|
@@ -170,14 +181,14 @@ export const Grid = (params: GridProps): JSX.Element => {
|
|
|
170
181
|
|
|
171
182
|
const columnDefs = useMemo((): ColDef[] => {
|
|
172
183
|
const adjustColDefs = params.columnDefs.map((colDef) => {
|
|
184
|
+
const colDefEditable = colDef.editable;
|
|
185
|
+
const editable = combineEditables(params.readOnly !== false, params.defaultColDef?.editable, colDefEditable);
|
|
173
186
|
return {
|
|
174
187
|
...colDef,
|
|
175
|
-
editable
|
|
188
|
+
editable,
|
|
176
189
|
cellClassRules: {
|
|
177
190
|
...colDef.cellClassRules,
|
|
178
|
-
"GridCell-readonly": (ccp: CellClassParams) =>
|
|
179
|
-
(params.readOnly != null || !params.readOnly) &&
|
|
180
|
-
!fnOrVar(params.defaultColDef?.editable ?? colDef.editable, ccp),
|
|
191
|
+
"GridCell-readonly": (ccp: CellClassParams) => !editable(ccp as any as EditableCallbackParams),
|
|
181
192
|
},
|
|
182
193
|
};
|
|
183
194
|
});
|
|
@@ -186,9 +197,8 @@ export const Grid = (params: GridProps): JSX.Element => {
|
|
|
186
197
|
{
|
|
187
198
|
colId: "selection",
|
|
188
199
|
editable: false,
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
maxWidth: 35,
|
|
200
|
+
minWidth: 42,
|
|
201
|
+
maxWidth: 42,
|
|
192
202
|
suppressSizeToFit: true,
|
|
193
203
|
checkboxSelection: true,
|
|
194
204
|
headerComponent: GridHeaderSelect,
|
|
@@ -241,6 +251,7 @@ export const Grid = (params: GridProps): JSX.Element => {
|
|
|
241
251
|
|
|
242
252
|
const startCellEditing = useCallback(
|
|
243
253
|
(event: CellEvent) => {
|
|
254
|
+
prePopupOps();
|
|
244
255
|
if (!event.node.isSelected()) {
|
|
245
256
|
event.node.setSelected(true, true);
|
|
246
257
|
}
|
|
@@ -256,7 +267,7 @@ export const Grid = (params: GridProps): JSX.Element => {
|
|
|
256
267
|
});
|
|
257
268
|
}
|
|
258
269
|
},
|
|
259
|
-
[checkUpdating],
|
|
270
|
+
[checkUpdating, prePopupOps],
|
|
260
271
|
);
|
|
261
272
|
|
|
262
273
|
const onCellDoubleClick = useCallback(
|
|
@@ -278,6 +289,7 @@ export const Grid = (params: GridProps): JSX.Element => {
|
|
|
278
289
|
const invokeEditAction = (e: CellEvent): boolean => {
|
|
279
290
|
const editAction = e.colDef?.cellRendererParams?.editAction;
|
|
280
291
|
if (!editAction) return false;
|
|
292
|
+
|
|
281
293
|
const editable = fnOrVar(e.colDef?.editable, e);
|
|
282
294
|
if (editable) {
|
|
283
295
|
if (!e.node.isSelected()) {
|
|
@@ -67,7 +67,7 @@ export const suppressCellKeyboardEvents = (e: SuppressKeyboardEventParams) => {
|
|
|
67
67
|
};
|
|
68
68
|
|
|
69
69
|
/*
|
|
70
|
-
* All cells should use this
|
|
70
|
+
* All cells should use this.
|
|
71
71
|
*/
|
|
72
72
|
export const GridCell = <RowType extends GridBaseRow, Props extends CellEditorCommon>(
|
|
73
73
|
props: GenericCellColDef<RowType>,
|
|
@@ -81,6 +81,7 @@ export const GridCell = <RowType extends GridBaseRow, Props extends CellEditorCo
|
|
|
81
81
|
colId: props.field,
|
|
82
82
|
sortable: !!(props?.field || props?.valueGetter),
|
|
83
83
|
resizable: true,
|
|
84
|
+
editable: props.editable ?? false,
|
|
84
85
|
...(custom?.editor && {
|
|
85
86
|
cellClassRules: GridCellMultiSelectClassRules,
|
|
86
87
|
editable: props.editable ?? true,
|
|
@@ -188,6 +188,23 @@ export const GridFormDropDown = <RowType extends GridBaseRow>(props: GridFormDro
|
|
|
188
188
|
return true;
|
|
189
189
|
}, [filter, filteredValues, options, props, selectItemHandler, selectedItem, selectedRows, subSelectedValue]);
|
|
190
190
|
|
|
191
|
+
const onMouseEnterFocus = useCallback((item: FinalSelectOption) => {
|
|
192
|
+
setSelectedItem(item);
|
|
193
|
+
if (item.subComponent) {
|
|
194
|
+
subComponentIsValid.current = true;
|
|
195
|
+
subComponentInitialValue.current = null;
|
|
196
|
+
} else {
|
|
197
|
+
setSubSelectedValue(null);
|
|
198
|
+
subComponentIsValid.current = true;
|
|
199
|
+
}
|
|
200
|
+
}, []);
|
|
201
|
+
|
|
202
|
+
const onMouseLeaveFocus = useCallback(() => {
|
|
203
|
+
setSelectedItem(null);
|
|
204
|
+
setSubSelectedValue(null);
|
|
205
|
+
subComponentIsValid.current = true;
|
|
206
|
+
}, []);
|
|
207
|
+
|
|
191
208
|
const { popoverWrapper } = useGridPopoverHook({
|
|
192
209
|
className: props.className,
|
|
193
210
|
invalid: () => !!(selectedItem && !subComponentIsValid.current),
|
|
@@ -268,17 +285,9 @@ export const GridFormDropDown = <RowType extends GridBaseRow>(props: GridFormDro
|
|
|
268
285
|
disabled={!!item.disabled}
|
|
269
286
|
title={item.disabled && typeof item.disabled !== "boolean" ? item.disabled : ""}
|
|
270
287
|
value={item.value}
|
|
271
|
-
onFocus={() =>
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
setSelectedItem(item);
|
|
275
|
-
subComponentIsValid.current = true;
|
|
276
|
-
subComponentInitialValue.current = null;
|
|
277
|
-
} else {
|
|
278
|
-
setSubSelectedValue(null);
|
|
279
|
-
subComponentIsValid.current = true;
|
|
280
|
-
}
|
|
281
|
-
}}
|
|
288
|
+
onFocus={() => onMouseEnterFocus(item)}
|
|
289
|
+
onMouseEnter={() => onMouseEnterFocus(item)}
|
|
290
|
+
onMouseLeave={onMouseLeaveFocus}
|
|
282
291
|
onClick={(e: ClickEvent) => {
|
|
283
292
|
if (item.subComponent) {
|
|
284
293
|
e.keepOpen = true;
|
|
@@ -13,8 +13,8 @@ export const GridPopoverMenu = <RowType extends GridBaseRow>(
|
|
|
13
13
|
): ColDefT<RowType> =>
|
|
14
14
|
GridCell<RowType, GridFormPopoverMenuProps<RowType>>(
|
|
15
15
|
{
|
|
16
|
-
minWidth:
|
|
17
|
-
maxWidth:
|
|
16
|
+
minWidth: 48,
|
|
17
|
+
maxWidth: 48,
|
|
18
18
|
width: 40,
|
|
19
19
|
editable: colDef.editable != null ? colDef.editable : true,
|
|
20
20
|
cellStyle: { justifyContent: "center" },
|
|
@@ -5,6 +5,7 @@ import { GridBaseRow } from "../components/Grid";
|
|
|
5
5
|
export interface GridContextType {
|
|
6
6
|
gridReady: boolean;
|
|
7
7
|
setGridApi: (gridApi: GridApi | undefined) => void;
|
|
8
|
+
prePopupOps: () => void;
|
|
8
9
|
setQuickFilter: (quickFilter: string) => void;
|
|
9
10
|
editingCells: () => boolean;
|
|
10
11
|
getSelectedRows: <T extends GridBaseRow>() => T[];
|
|
@@ -34,6 +35,9 @@ export interface GridContextType {
|
|
|
34
35
|
|
|
35
36
|
export const GridContext = createContext<GridContextType>({
|
|
36
37
|
gridReady: false,
|
|
38
|
+
prePopupOps: () => {
|
|
39
|
+
console.error("no context provider for prePopupOps");
|
|
40
|
+
},
|
|
37
41
|
externallySelectedItemsAreInSync: false,
|
|
38
42
|
setGridApi: () => {
|
|
39
43
|
console.error("no context provider for setGridApi");
|
|
@@ -5,6 +5,7 @@ import { defer, delay, difference, isEmpty, last, sortBy } from "lodash-es";
|
|
|
5
5
|
import { isNotEmpty, wait } from "../utils/util";
|
|
6
6
|
import { GridUpdatingContext } from "./GridUpdatingContext";
|
|
7
7
|
import { GridBaseRow } from "../components/Grid";
|
|
8
|
+
import { CellPosition } from "ag-grid-community/dist/lib/entities/cellPosition";
|
|
8
9
|
|
|
9
10
|
interface GridContextProps {
|
|
10
11
|
children: ReactNode;
|
|
@@ -20,6 +21,7 @@ export const GridContextProvider = (props: GridContextProps): ReactElement => {
|
|
|
20
21
|
const [gridApi, _setGridApi] = useState<GridApi>();
|
|
21
22
|
const [gridReady, setGridReady] = useState(false);
|
|
22
23
|
const idsBeforeUpdate = useRef<number[]>([]);
|
|
24
|
+
const prePopupFocusedCell = useRef<CellPosition>();
|
|
23
25
|
const [externallySelectedItemsAreInSync, setExternallySelectedItemsAreInSync] = useState(false);
|
|
24
26
|
|
|
25
27
|
const setGridApi = useCallback((gridApi: GridApi | undefined) => {
|
|
@@ -43,6 +45,13 @@ export const GridContextProvider = (props: GridContextProps): ReactElement => {
|
|
|
43
45
|
[gridApi],
|
|
44
46
|
);
|
|
45
47
|
|
|
48
|
+
/**
|
|
49
|
+
* Before a popup record the currently focused cell.
|
|
50
|
+
*/
|
|
51
|
+
const prePopupOps = useCallback(() => {
|
|
52
|
+
prePopupFocusedCell.current = gridApi?.getFocusedCell() ?? undefined;
|
|
53
|
+
}, [gridApi]);
|
|
54
|
+
|
|
46
55
|
/**
|
|
47
56
|
* Set the quick filter value to grid.
|
|
48
57
|
*/
|
|
@@ -276,7 +285,12 @@ export const GridContextProvider = (props: GridContextProps): ReactElement => {
|
|
|
276
285
|
});
|
|
277
286
|
}, [gridApiOp]);
|
|
278
287
|
|
|
279
|
-
const stopEditing = useCallback((): void =>
|
|
288
|
+
const stopEditing = useCallback((): void => {
|
|
289
|
+
if (prePopupFocusedCell.current) {
|
|
290
|
+
gridApi?.setFocusedCell(prePopupFocusedCell.current.rowIndex, prePopupFocusedCell.current.column);
|
|
291
|
+
}
|
|
292
|
+
gridApiOp((gridApi) => gridApi.stopEditing());
|
|
293
|
+
}, [gridApi, gridApiOp]);
|
|
280
294
|
|
|
281
295
|
const selectNextCell = useCallback(
|
|
282
296
|
(tabDirection: -1 | 0 | 1 = 0) => {
|
|
@@ -297,8 +311,6 @@ export const GridContextProvider = (props: GridContextProps): ReactElement => {
|
|
|
297
311
|
): Promise<boolean> => {
|
|
298
312
|
setSaving && setSaving(true);
|
|
299
313
|
return await gridApiOp(async (gridApi) => {
|
|
300
|
-
const preOpCell = gridApi.getFocusedCell();
|
|
301
|
-
|
|
302
314
|
const selectedRows = props.selectedRows;
|
|
303
315
|
|
|
304
316
|
let ok = false;
|
|
@@ -331,13 +343,13 @@ export const GridContextProvider = (props: GridContextProps): ReactElement => {
|
|
|
331
343
|
}
|
|
332
344
|
|
|
333
345
|
// Only focus next cell if user hasn't already manually changed focus
|
|
334
|
-
const
|
|
346
|
+
const postPopupFocusedCell = gridApi.getFocusedCell();
|
|
335
347
|
if (
|
|
336
348
|
tabDirection &&
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
349
|
+
prePopupFocusedCell.current &&
|
|
350
|
+
postPopupFocusedCell &&
|
|
351
|
+
prePopupFocusedCell.current.rowIndex == postPopupFocusedCell.rowIndex &&
|
|
352
|
+
prePopupFocusedCell.current.column.getColId() == postPopupFocusedCell.column.getColId()
|
|
341
353
|
) {
|
|
342
354
|
selectNextCell(tabDirection);
|
|
343
355
|
}
|
|
@@ -368,6 +380,7 @@ export const GridContextProvider = (props: GridContextProps): ReactElement => {
|
|
|
368
380
|
<GridContext.Provider
|
|
369
381
|
value={{
|
|
370
382
|
gridReady,
|
|
383
|
+
prePopupOps,
|
|
371
384
|
setGridApi,
|
|
372
385
|
setQuickFilter,
|
|
373
386
|
selectRowsById,
|
|
@@ -168,17 +168,15 @@ const GridNonEditableRowTemplate: ComponentStory<typeof Grid> = (props: GridProp
|
|
|
168
168
|
return (
|
|
169
169
|
<Grid
|
|
170
170
|
{...props}
|
|
171
|
-
selectable={true}
|
|
172
171
|
externalSelectedItems={externalSelectedItems}
|
|
173
172
|
setExternalSelectedItems={setExternalSelectedItems}
|
|
174
173
|
defaultColDef={defaultColDef}
|
|
175
174
|
columnDefs={columnDefs}
|
|
176
175
|
rowData={rowData}
|
|
177
176
|
domLayout={"autoHeight"}
|
|
178
|
-
autoSelectFirstRow={true}
|
|
179
|
-
readOnly={false}
|
|
180
177
|
/>
|
|
181
178
|
);
|
|
182
179
|
};
|
|
183
180
|
|
|
184
181
|
export const NonEditableRow = GridNonEditableRowTemplate.bind({});
|
|
182
|
+
NonEditableRow.args = { autoSelectFirstRow: true, selectable: true };
|