@mui/x-data-grid 8.27.0 → 8.27.3

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.
Files changed (84) hide show
  1. package/CHANGELOG.md +158 -0
  2. package/DataGrid/DataGrid.js +7 -0
  3. package/DataGrid/index.js +0 -1
  4. package/components/GridColumnSortButton.js +2 -2
  5. package/components/GridScrollArea.js +2 -2
  6. package/components/GridScrollShadows.js +2 -2
  7. package/components/GridSkeletonLoadingOverlay.js +2 -2
  8. package/components/base/GridOverlays.js +3 -3
  9. package/components/columnHeaders/GridColumnHeaderItem.js +31 -1
  10. package/components/columnHeaders/GridColumnHeaderTitle.js +2 -2
  11. package/components/columnHeaders/GridIconButtonContainer.js +2 -2
  12. package/components/containers/GridRootStyles.js +23 -217
  13. package/components/menu/columnMenu/GridColumnMenu.d.ts +2 -2
  14. package/components/menu/columnMenu/GridColumnMenu.js +2 -0
  15. package/components/menu/columnMenu/GridColumnMenuProps.d.ts +9 -1
  16. package/components/menu/columnMenu/index.d.ts +1 -1
  17. package/components/menu/columnMenu/index.js +0 -12
  18. package/components/toolbar/GridToolbarQuickFilter.js +4 -4
  19. package/components/toolbarV8/GridToolbar.js +3 -3
  20. package/components/toolbarV8/Toolbar.d.ts +1 -1
  21. package/components/toolbarV8/Toolbar.js +2 -2
  22. package/components/virtualization/GridBottomContainer.js +2 -2
  23. package/components/virtualization/GridMainContainer.js +3 -3
  24. package/components/virtualization/GridTopContainer.js +2 -2
  25. package/components/virtualization/GridVirtualScrollbar.d.ts +1 -1
  26. package/components/virtualization/GridVirtualScrollbar.js +5 -5
  27. package/components/virtualization/GridVirtualScroller.js +2 -2
  28. package/components/virtualization/GridVirtualScrollerFiller.js +6 -6
  29. package/constants/dataGridPropsDefaultValues.js +1 -0
  30. package/esm/DataGrid/DataGrid.js +7 -0
  31. package/esm/DataGrid/index.js +0 -1
  32. package/esm/components/GridColumnSortButton.js +1 -1
  33. package/esm/components/GridScrollArea.js +1 -1
  34. package/esm/components/GridScrollShadows.js +1 -1
  35. package/esm/components/GridSkeletonLoadingOverlay.js +1 -1
  36. package/esm/components/base/GridOverlays.js +1 -1
  37. package/esm/components/columnHeaders/GridColumnHeaderItem.js +31 -1
  38. package/esm/components/columnHeaders/GridColumnHeaderTitle.js +1 -1
  39. package/esm/components/columnHeaders/GridIconButtonContainer.js +1 -1
  40. package/esm/components/containers/GridRootStyles.js +23 -217
  41. package/esm/components/menu/columnMenu/GridColumnMenu.d.ts +2 -2
  42. package/esm/components/menu/columnMenu/GridColumnMenu.js +2 -0
  43. package/esm/components/menu/columnMenu/GridColumnMenuProps.d.ts +9 -1
  44. package/esm/components/menu/columnMenu/index.d.ts +1 -1
  45. package/esm/components/menu/columnMenu/index.js +0 -1
  46. package/esm/components/toolbar/GridToolbarQuickFilter.js +1 -1
  47. package/esm/components/toolbarV8/GridToolbar.js +1 -1
  48. package/esm/components/toolbarV8/Toolbar.d.ts +1 -1
  49. package/esm/components/toolbarV8/Toolbar.js +1 -1
  50. package/esm/components/virtualization/GridBottomContainer.js +1 -1
  51. package/esm/components/virtualization/GridMainContainer.js +1 -1
  52. package/esm/components/virtualization/GridTopContainer.js +1 -1
  53. package/esm/components/virtualization/GridVirtualScrollbar.d.ts +1 -1
  54. package/esm/components/virtualization/GridVirtualScrollbar.js +1 -1
  55. package/esm/components/virtualization/GridVirtualScroller.js +1 -1
  56. package/esm/components/virtualization/GridVirtualScrollerFiller.js +1 -1
  57. package/esm/constants/dataGridPropsDefaultValues.js +1 -0
  58. package/esm/hooks/features/columnMenu/getColumnMenuItemKeys.d.ts +17 -0
  59. package/esm/hooks/features/columnMenu/getColumnMenuItemKeys.js +36 -0
  60. package/esm/hooks/features/columnMenu/useGridColumnMenuSlots.js +11 -16
  61. package/esm/hooks/features/dataSource/models.d.ts +4 -1
  62. package/esm/hooks/features/dataSource/useGridDataSourceBase.d.ts +5 -2
  63. package/esm/hooks/features/dataSource/useGridDataSourceBase.js +93 -6
  64. package/esm/hooks/features/editing/useGridRowEditing.js +14 -4
  65. package/esm/index.js +1 -1
  66. package/esm/internals/index.d.ts +1 -0
  67. package/esm/models/api/gridEditingApi.d.ts +0 -1
  68. package/esm/models/params/gridRowParams.d.ts +0 -1
  69. package/esm/models/props/DataGridProps.d.ts +7 -0
  70. package/hooks/features/columnMenu/getColumnMenuItemKeys.d.ts +17 -0
  71. package/hooks/features/columnMenu/getColumnMenuItemKeys.js +43 -0
  72. package/hooks/features/columnMenu/useGridColumnMenuSlots.js +11 -16
  73. package/hooks/features/dataSource/models.d.ts +4 -1
  74. package/hooks/features/dataSource/useGridDataSourceBase.d.ts +5 -2
  75. package/hooks/features/dataSource/useGridDataSourceBase.js +92 -5
  76. package/hooks/features/editing/useGridRowEditing.js +14 -4
  77. package/index.js +1 -1
  78. package/internals/index.d.ts +1 -0
  79. package/models/api/gridEditingApi.d.ts +0 -1
  80. package/models/params/gridRowParams.d.ts +0 -1
  81. package/models/props/DataGridProps.d.ts +7 -0
  82. package/package.json +1 -1
  83. package/esm/index.css +0 -5
  84. package/index.css +0 -5
@@ -5,6 +5,7 @@ import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWith
5
5
  const _excluded = ["skipCache", "keepChildrenExpanded"];
6
6
  import * as React from 'react';
7
7
  import useLazyRef from '@mui/utils/useLazyRef';
8
+ import useEventCallback from '@mui/utils/useEventCallback';
8
9
  import debounce from '@mui/utils/debounce';
9
10
  import { warnOnce } from '@mui/x-internals/warning';
10
11
  import { isDeepEqual } from '@mui/x-internals/isDeepEqual';
@@ -12,7 +13,8 @@ import { GRID_ROOT_GROUP_ID } from "../rows/gridRowsUtils.js";
12
13
  import { runIf } from "../../../utils/utils.js";
13
14
  import { GridStrategyGroup } from "../../core/strategyProcessing/index.js";
14
15
  import { useGridSelector } from "../../utils/useGridSelector.js";
15
- import { gridPaginationModelSelector } from "../pagination/gridPaginationSelector.js";
16
+ import { gridPaginationModelSelector, gridVisibleRowsSelector } from "../pagination/gridPaginationSelector.js";
17
+ import { gridRowTreeSelector } from "../rows/gridRowsSelector.js";
16
18
  import { gridGetRowsParamsSelector } from "./gridDataSourceSelector.js";
17
19
  import { CacheChunkManager, DataSourceRowsUpdateStrategy } from "./utils.js";
18
20
  import { GridDataSourceCacheDefault } from "./cache.js";
@@ -38,7 +40,9 @@ export const useGridDataSourceBase = (apiRef, props, options = {}) => {
38
40
  }, [currentStrategy]);
39
41
  const paginationModel = useGridSelector(apiRef, gridPaginationModelSelector);
40
42
  const lastRequestId = React.useRef(0);
43
+ const pollingIntervalRef = React.useRef(null);
41
44
  const onDataSourceErrorProp = props.onDataSourceError;
45
+ const revalidateMs = props.dataSourceRevalidateMs;
42
46
  const cacheChunkManager = useLazyRef(() => {
43
47
  if (!props.pagination) {
44
48
  return new CacheChunkManager(paginationModel.pageSize);
@@ -128,6 +132,69 @@ export const useGridDataSourceBase = (apiRef, props, options = {}) => {
128
132
  const handleStrategyActivityChange = React.useCallback(() => {
129
133
  setCurrentStrategy(apiRef.current.getActiveStrategy(GridStrategyGroup.DataSource));
130
134
  }, [apiRef]);
135
+ const fetchRowChildrenOption = options.fetchRowChildren;
136
+ const revalidate = useEventCallback(async () => {
137
+ const getRows = props.dataSource?.getRows;
138
+ if (!getRows || !standardRowsUpdateStrategyActive) {
139
+ return;
140
+ }
141
+ const revalidateExpandedGroups = () => {
142
+ if (currentStrategy !== DataSourceRowsUpdateStrategy.GroupedData || !fetchRowChildrenOption) {
143
+ return;
144
+ }
145
+ const rowTree = gridRowTreeSelector(apiRef);
146
+ const visibleRows = gridVisibleRowsSelector(apiRef).rows;
147
+ const expandedGroupIds = visibleRows.reduce((acc, row) => {
148
+ const node = rowTree[row.id];
149
+ if (node.type === 'group' && node.id !== GRID_ROOT_GROUP_ID && node.childrenExpanded === true) {
150
+ acc.push(row.id);
151
+ }
152
+ return acc;
153
+ }, []);
154
+ if (expandedGroupIds.length > 0) {
155
+ fetchRowChildrenOption(expandedGroupIds, {
156
+ showChildrenLoading: false
157
+ });
158
+ }
159
+ };
160
+ const fetchParams = _extends({}, gridGetRowsParamsSelector(apiRef), apiRef.current.unstable_applyPipeProcessors('getRowsParams', {}));
161
+ const cacheKeys = cacheChunkManager.getCacheKeys(fetchParams);
162
+ const responses = cacheKeys.map(cacheKey => cache.get(cacheKey));
163
+ if (responses.every(response => response !== undefined)) {
164
+ revalidateExpandedGroups();
165
+ return;
166
+ }
167
+ try {
168
+ const response = await getRows(fetchParams);
169
+ const currentParams = _extends({}, gridGetRowsParamsSelector(apiRef), apiRef.current.unstable_applyPipeProcessors('getRowsParams', {}));
170
+ if (!isDeepEqual(fetchParams, currentParams)) {
171
+ return;
172
+ }
173
+ const cacheResponses = cacheChunkManager.splitResponse(fetchParams, response);
174
+ cacheResponses.forEach((cacheResponse, key) => cache.set(key, cacheResponse));
175
+ apiRef.current.applyStrategyProcessor('dataSourceRowsUpdate', {
176
+ response,
177
+ fetchParams,
178
+ options: {}
179
+ });
180
+ revalidateExpandedGroups();
181
+ } catch {
182
+ // Ignore background revalidation errors.
183
+ }
184
+ });
185
+ const stopPolling = React.useCallback(() => {
186
+ if (pollingIntervalRef.current !== null) {
187
+ clearInterval(pollingIntervalRef.current);
188
+ pollingIntervalRef.current = null;
189
+ }
190
+ }, []);
191
+ const startPolling = useEventCallback(() => {
192
+ stopPolling();
193
+ if (revalidateMs <= 0 || !standardRowsUpdateStrategyActive) {
194
+ return;
195
+ }
196
+ pollingIntervalRef.current = setInterval(revalidate, revalidateMs);
197
+ });
131
198
  const handleDataUpdate = React.useCallback(params => {
132
199
  if ('error' in params) {
133
200
  apiRef.current.setRows([]);
@@ -144,7 +211,8 @@ export const useGridDataSourceBase = (apiRef, props, options = {}) => {
144
211
  params: params.fetchParams,
145
212
  response
146
213
  }, true);
147
- }, [apiRef]);
214
+ startPolling();
215
+ }, [apiRef, startPolling]);
148
216
  const dataSourceUpdateRow = props.dataSource?.updateRow;
149
217
  const handleEditRowOption = options.handleEditRow;
150
218
  const editRow = React.useCallback(async params => {
@@ -184,6 +252,10 @@ export const useGridDataSourceBase = (apiRef, props, options = {}) => {
184
252
  }
185
253
  };
186
254
  const debouncedFetchRows = React.useMemo(() => debounce(fetchRows, 0), [fetchRows]);
255
+ const handleFetchRowsOnParamsChange = React.useCallback(() => {
256
+ stopPolling();
257
+ debouncedFetchRows();
258
+ }, [stopPolling, debouncedFetchRows]);
187
259
  const isFirstRender = React.useRef(true);
188
260
  React.useEffect(() => {
189
261
  if (isFirstRender.current) {
@@ -196,6 +268,17 @@ export const useGridDataSourceBase = (apiRef, props, options = {}) => {
196
268
  const newCache = getCache(props.dataSourceCache, options.cacheOptions);
197
269
  setCache(prevCache => prevCache !== newCache ? newCache : prevCache);
198
270
  }, [props.dataSourceCache, options.cacheOptions]);
271
+ React.useEffect(() => {
272
+ if (!standardRowsUpdateStrategyActive) {
273
+ stopPolling();
274
+ }
275
+ }, [standardRowsUpdateStrategyActive, stopPolling]);
276
+ React.useEffect(() => {
277
+ if (revalidateMs <= 0) {
278
+ stopPolling();
279
+ }
280
+ }, [revalidateMs, stopPolling]);
281
+ React.useEffect(() => stopPolling, [stopPolling]);
199
282
  React.useEffect(() => {
200
283
  // Return early if the proper strategy isn't set yet
201
284
  // Context: https://github.com/mui/mui-x/issues/19650
@@ -203,6 +286,8 @@ export const useGridDataSourceBase = (apiRef, props, options = {}) => {
203
286
  return undefined;
204
287
  }
205
288
  if (props.dataSource) {
289
+ stopPolling();
290
+ apiRef.current.setRows([]);
206
291
  apiRef.current.dataSource.cache.clear();
207
292
  apiRef.current.dataSource.fetchRows();
208
293
  }
@@ -210,7 +295,7 @@ export const useGridDataSourceBase = (apiRef, props, options = {}) => {
210
295
  // ignore the current request on unmount
211
296
  lastRequestId.current += 1;
212
297
  };
213
- }, [apiRef, props.dataSource, currentStrategy]);
298
+ }, [apiRef, props.dataSource, currentStrategy, stopPolling]);
214
299
  return {
215
300
  api: {
216
301
  public: dataSourceApi
@@ -222,13 +307,15 @@ export const useGridDataSourceBase = (apiRef, props, options = {}) => {
222
307
  processor: handleDataUpdate
223
308
  },
224
309
  setStrategyAvailability,
310
+ startPolling,
311
+ stopPolling,
225
312
  cacheChunkManager,
226
313
  cache,
227
314
  events: {
228
315
  strategyAvailabilityChange: handleStrategyActivityChange,
229
- sortModelChange: runIf(standardRowsUpdateStrategyActive, () => debouncedFetchRows()),
230
- filterModelChange: runIf(standardRowsUpdateStrategyActive, () => debouncedFetchRows()),
231
- paginationModelChange: runIf(standardRowsUpdateStrategyActive, () => debouncedFetchRows())
316
+ sortModelChange: runIf(standardRowsUpdateStrategyActive, handleFetchRowsOnParamsChange),
317
+ filterModelChange: runIf(standardRowsUpdateStrategyActive, handleFetchRowsOnParamsChange),
318
+ paginationModelChange: runIf(standardRowsUpdateStrategyActive, handleFetchRowsOnParamsChange)
232
319
  }
233
320
  };
234
321
  };
@@ -184,12 +184,15 @@ export const useGridRowEditing = (apiRef, props) => {
184
184
  const rowParams = apiRef.current.getRowParams(params.id);
185
185
  const newParams = _extends({}, rowParams, {
186
186
  field: params.field,
187
- reason
187
+ reason,
188
+ // Only pass the pressed key when the row editing is controlled via `rowModesModel`.
189
+ // In uncontrolled mode, the default editor already inserts the character and passing it here would duplicate it.
190
+ key: rowModesModelProp && isPrintableKey(event) ? event.key : undefined
188
191
  });
189
192
  apiRef.current.publishEvent('rowEditStart', newParams, event);
190
193
  }
191
194
  }
192
- }, [apiRef, hasFieldsWithErrors]);
195
+ }, [apiRef, hasFieldsWithErrors, rowModesModelProp]);
193
196
  const handleRowEditStart = React.useCallback(params => {
194
197
  const {
195
198
  id,
@@ -201,10 +204,17 @@ export const useGridRowEditing = (apiRef, props) => {
201
204
  fieldToFocus: field
202
205
  };
203
206
  if (reason === GridRowEditStartReasons.printableKeyDown || reason === GridRowEditStartReasons.deleteKeyDown) {
204
- startRowEditModeParams.deleteValue = !!field;
207
+ // If the user typed a printable key, initialize the value with that key
208
+ // to avoid losing the first character when the component is controlled.
209
+ if (rowModesModelProp && reason === GridRowEditStartReasons.printableKeyDown && params.key && field) {
210
+ startRowEditModeParams.initialValue = params.key;
211
+ } else {
212
+ // For Delete / Backspace or for uncontrolled row editing we clear the value
213
+ startRowEditModeParams.deleteValue = !!field;
214
+ }
205
215
  }
206
216
  apiRef.current.startRowEditMode(startRowEditModeParams);
207
- }, [apiRef]);
217
+ }, [apiRef, rowModesModelProp]);
208
218
  const handleRowEditStop = React.useCallback(params => {
209
219
  const {
210
220
  id,
package/esm/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @mui/x-data-grid v8.27.0
2
+ * @mui/x-data-grid v8.27.3
3
3
  *
4
4
  * @license MIT
5
5
  * This source code is licensed under the MIT license found in the
@@ -29,6 +29,7 @@ export { gridHeaderFilteringEditFieldSelector, gridHeaderFilteringMenuSelector }
29
29
  export type { GridSlotsComponentsProps } from "../models/gridSlotsComponentsProps.js";
30
30
  export type { GridFilterInputValueProps } from "../models/gridFilterInputComponent.js";
31
31
  export { useGridColumnMenu, columnMenuStateInitializer } from "../hooks/features/columnMenu/useGridColumnMenu.js";
32
+ export type { GridColumnMenuComponent } from "../components/menu/columnMenu/GridColumnMenuProps.js";
32
33
  export { useGridColumns, columnsStateInitializer } from "../hooks/features/columns/useGridColumns.js";
33
34
  export * from "../hooks/features/columns/gridColumnsUtils.js";
34
35
  export { useGridColumnSpanning } from "../hooks/features/columns/useGridColumnSpanning.js";
@@ -123,7 +123,6 @@ export interface GridStartRowEditModeParams {
123
123
  /**
124
124
  * The initial value for the given `fieldToFocus`.
125
125
  * If `deleteValue` is also true, this value is not used.
126
- * @deprecated No longer needed.
127
126
  */
128
127
  initialValue?: string;
129
128
  }
@@ -73,7 +73,6 @@ export interface GridRowEditStartParams<R extends GridValidRowModel = any> exten
73
73
  reason?: GridRowEditStartReasons;
74
74
  /**
75
75
  * If the reason is related to a keyboard event, it contains which key was pressed.
76
- * @deprecated No longer needed.
77
76
  */
78
77
  key?: string;
79
78
  }
@@ -325,6 +325,13 @@ export interface DataGridPropsWithDefaultValues<R extends GridValidRowModel = an
325
325
  * @default 0
326
326
  */
327
327
  throttleRowsMs: number;
328
+ /**
329
+ * If positive, the Data Grid will periodically revalidate data source rows by re-fetching them from the server when the cache entry has expired.
330
+ * If the refetched rows are different from the current rows, the grid will update the rows.
331
+ * Set to `0` to disable polling.
332
+ * @default 0
333
+ */
334
+ dataSourceRevalidateMs: number;
328
335
  /**
329
336
  * If `true`, reordering columns is disabled.
330
337
  * @default false
@@ -0,0 +1,17 @@
1
+ import type { RefObject } from '@mui/x-internals/types';
2
+ import type { GridPrivateApiCommunity } from "../../../models/api/gridApiCommunity.js";
3
+ import type { GridColDef } from "../../../models/colDef/gridColDef.js";
4
+ import type { GridColumnMenuSlotProps } from "./columnMenuInterfaces.js";
5
+ export interface GetColumnMenuItemKeysParams {
6
+ apiRef: RefObject<GridPrivateApiCommunity>;
7
+ colDef: GridColDef;
8
+ defaultSlots: Record<string, any>;
9
+ defaultSlotProps: Record<string, GridColumnMenuSlotProps>;
10
+ slots?: Record<string, any>;
11
+ slotProps?: Record<string, GridColumnMenuSlotProps>;
12
+ }
13
+ /**
14
+ * Returns the list of column menu item keys (sorted by `displayOrder`) that should be rendered for a given column.
15
+ * This is shared between the column header (to know if menu is empty) and the menu itself (to render items).
16
+ */
17
+ export declare function getColumnMenuItemKeys(params: GetColumnMenuItemKeysParams): string[];
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.getColumnMenuItemKeys = getColumnMenuItemKeys;
8
+ var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
9
+ /**
10
+ * Returns the list of column menu item keys (sorted by `displayOrder`) that should be rendered for a given column.
11
+ * This is shared between the column header (to know if menu is empty) and the menu itself (to render items).
12
+ */
13
+ function getColumnMenuItemKeys(params) {
14
+ const {
15
+ apiRef,
16
+ colDef,
17
+ defaultSlots,
18
+ defaultSlotProps,
19
+ slots = {},
20
+ slotProps = {}
21
+ } = params;
22
+ const processedComponents = (0, _extends2.default)({}, defaultSlots, slots);
23
+ let processedSlotProps = defaultSlotProps;
24
+ if (slotProps && Object.keys(slotProps).length > 0) {
25
+ const mergedProps = (0, _extends2.default)({}, slotProps);
26
+ Object.entries(defaultSlotProps).forEach(([key, currentSlotProps]) => {
27
+ mergedProps[key] = (0, _extends2.default)({}, currentSlotProps, slotProps[key] || {});
28
+ });
29
+ processedSlotProps = mergedProps;
30
+ }
31
+ const defaultItems = apiRef.current.unstable_applyPipeProcessors('columnMenu', [], colDef);
32
+ const defaultComponentKeys = Object.keys(defaultSlots);
33
+ const userItems = Object.keys(slots).filter(key => !defaultComponentKeys.includes(key));
34
+ const uniqueItems = Array.from(new Set([...defaultItems, ...userItems]));
35
+ const cleansedItems = uniqueItems.filter(key => processedComponents[key] != null);
36
+ return cleansedItems.sort((a, b) => {
37
+ const leftItemProps = processedSlotProps[a];
38
+ const rightItemProps = processedSlotProps[b];
39
+ const leftDisplayOrder = Number.isFinite(leftItemProps?.displayOrder) ? leftItemProps.displayOrder : 100;
40
+ const rightDisplayOrder = Number.isFinite(rightItemProps?.displayOrder) ? rightItemProps.displayOrder : 100;
41
+ return leftDisplayOrder - rightDisplayOrder;
42
+ });
43
+ }
@@ -11,6 +11,7 @@ var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")
11
11
  var React = _interopRequireWildcard(require("react"));
12
12
  var _useGridRootProps = require("../../utils/useGridRootProps");
13
13
  var _useGridPrivateApiContext = require("../../utils/useGridPrivateApiContext");
14
+ var _getColumnMenuItemKeys = require("./getColumnMenuItemKeys");
14
15
  const _excluded = ["displayOrder"];
15
16
  const useGridColumnMenuSlots = props => {
16
17
  const apiRef = (0, _useGridPrivateApiContext.useGridPrivateApiContext)();
@@ -35,22 +36,16 @@ const useGridColumnMenuSlots = props => {
35
36
  });
36
37
  return mergedProps;
37
38
  }, [defaultSlotProps, slotProps]);
38
- const defaultItems = apiRef.current.unstable_applyPipeProcessors('columnMenu', [], props.colDef);
39
- const userItems = React.useMemo(() => {
40
- const defaultComponentKeys = Object.keys(defaultSlots);
41
- return Object.keys(slots).filter(key => !defaultComponentKeys.includes(key));
42
- }, [slots, defaultSlots]);
43
39
  return React.useMemo(() => {
44
- const uniqueItems = Array.from(new Set([...defaultItems, ...userItems]));
45
- const cleansedItems = uniqueItems.filter(key => processedComponents[key] != null);
46
- const sorted = cleansedItems.sort((a, b) => {
47
- const leftItemProps = processedSlotProps[a];
48
- const rightItemProps = processedSlotProps[b];
49
- const leftDisplayOrder = Number.isFinite(leftItemProps?.displayOrder) ? leftItemProps.displayOrder : 100;
50
- const rightDisplayOrder = Number.isFinite(rightItemProps?.displayOrder) ? rightItemProps.displayOrder : 100;
51
- return leftDisplayOrder - rightDisplayOrder;
40
+ const sortedKeys = (0, _getColumnMenuItemKeys.getColumnMenuItemKeys)({
41
+ apiRef,
42
+ colDef,
43
+ defaultSlots,
44
+ defaultSlotProps,
45
+ slots,
46
+ slotProps
52
47
  });
53
- return sorted.reduce((acc, key, index) => {
48
+ return sortedKeys.reduce((acc, key, index) => {
54
49
  let itemProps = {
55
50
  colDef,
56
51
  onClick: hideMenu
@@ -60,8 +55,8 @@ const useGridColumnMenuSlots = props => {
60
55
  const customProps = (0, _objectWithoutPropertiesLoose2.default)(processedComponentProps, _excluded);
61
56
  itemProps = (0, _extends2.default)({}, itemProps, customProps);
62
57
  }
63
- return addDividers && index !== sorted.length - 1 ? [...acc, [processedComponents[key], itemProps], [rootProps.slots.baseDivider, {}]] : [...acc, [processedComponents[key], itemProps]];
58
+ return addDividers && index !== sortedKeys.length - 1 ? [...acc, [processedComponents[key], itemProps], [rootProps.slots.baseDivider, {}]] : [...acc, [processedComponents[key], itemProps]];
64
59
  }, []);
65
- }, [addDividers, colDef, defaultItems, hideMenu, processedComponents, processedSlotProps, userItems, rootProps.slots.baseDivider]);
60
+ }, [addDividers, apiRef, colDef, defaultSlotProps, defaultSlots, hideMenu, processedComponents, processedSlotProps, slotProps, slots, rootProps.slots.baseDivider]);
66
61
  };
67
62
  exports.useGridColumnMenuSlots = useGridColumnMenuSlots;
@@ -5,6 +5,9 @@ import type { GridDataSourceCacheDefaultConfig } from "./cache.js";
5
5
  * The parameters for the `fetchRows` method.
6
6
  */
7
7
  export type GridDataSourceFetchRowsParams<T> = Partial<T> & GridGetRowsOptions;
8
+ export interface GridDataSourceFetchRowChildrenOptions {
9
+ showChildrenLoading?: boolean;
10
+ }
8
11
  export interface GridDataSourceApi {
9
12
  /**
10
13
  * The data source API.
@@ -38,7 +41,7 @@ export interface GridDataSourceApiBase {
38
41
  }
39
42
  export interface GridDataSourceBaseOptions {
40
43
  cacheOptions?: GridDataSourceCacheDefaultConfig;
41
- fetchRowChildren?: (parents: GridRowId[]) => void;
44
+ fetchRowChildren?: (parents: GridRowId[], options?: GridDataSourceFetchRowChildrenOptions) => void;
42
45
  clearDataSourceState?: () => void;
43
46
  handleEditRow?: (params: GridUpdateRowParams, updatedRow: GridRowModel) => void;
44
47
  }
@@ -6,17 +6,20 @@ import type { GridPrivateApiCommunity } from "../../../models/api/gridApiCommuni
6
6
  import type { DataGridProcessedProps } from "../../../models/props/DataGridProps.js";
7
7
  import type { GridStrategyProcessor } from "../../core/strategyProcessing/index.js";
8
8
  import type { GridEventListener } from "../../../models/events/index.js";
9
- export declare const useGridDataSourceBase: <Api extends GridPrivateApiCommunity>(apiRef: RefObject<Api>, props: Pick<DataGridProcessedProps, "dataSource" | "dataSourceCache" | "onDataSourceError" | "pageSizeOptions" | "pagination" | "signature">, options?: GridDataSourceBaseOptions) => {
9
+ import type { GridRowId } from "../../../models/gridRows.js";
10
+ export declare const useGridDataSourceBase: <Api extends GridPrivateApiCommunity>(apiRef: RefObject<Api>, props: Pick<DataGridProcessedProps, "dataSource" | "dataSourceCache" | "onDataSourceError" | "pageSizeOptions" | "pagination" | "signature" | "dataSourceRevalidateMs">, options?: GridDataSourceBaseOptions) => {
10
11
  api: {
11
12
  public: GridDataSourceApi;
12
13
  };
13
- debouncedFetchRows: ((parentId?: import("@mui/x-data-grid").GridRowId, params?: import("./models.js").GridDataSourceFetchRowsParams<import("@mui/x-data-grid").GridGetRowsParams>) => Promise<void>) & import("@mui/utils/debounce").Cancelable;
14
+ debouncedFetchRows: ((parentId?: GridRowId, params?: import("./models.js").GridDataSourceFetchRowsParams<import("@mui/x-data-grid").GridGetRowsParams>) => Promise<void>) & import("@mui/utils/debounce").Cancelable;
14
15
  strategyProcessor: {
15
16
  strategyName: DataSourceRowsUpdateStrategy;
16
17
  group: "dataSourceRowsUpdate";
17
18
  processor: GridStrategyProcessor<"dataSourceRowsUpdate">;
18
19
  };
19
20
  setStrategyAvailability: () => void;
21
+ startPolling: () => void;
22
+ stopPolling: () => void;
20
23
  cacheChunkManager: CacheChunkManager;
21
24
  cache: GridDataSourceCache;
22
25
  events: {
@@ -11,6 +11,7 @@ var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")
11
11
  var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose"));
12
12
  var React = _interopRequireWildcard(require("react"));
13
13
  var _useLazyRef = _interopRequireDefault(require("@mui/utils/useLazyRef"));
14
+ var _useEventCallback = _interopRequireDefault(require("@mui/utils/useEventCallback"));
14
15
  var _debounce = _interopRequireDefault(require("@mui/utils/debounce"));
15
16
  var _warning = require("@mui/x-internals/warning");
16
17
  var _isDeepEqual = require("@mui/x-internals/isDeepEqual");
@@ -19,6 +20,7 @@ var _utils = require("../../../utils/utils");
19
20
  var _strategyProcessing = require("../../core/strategyProcessing");
20
21
  var _useGridSelector = require("../../utils/useGridSelector");
21
22
  var _gridPaginationSelector = require("../pagination/gridPaginationSelector");
23
+ var _gridRowsSelector = require("../rows/gridRowsSelector");
22
24
  var _gridDataSourceSelector = require("./gridDataSourceSelector");
23
25
  var _utils2 = require("./utils");
24
26
  var _cache = require("./cache");
@@ -45,7 +47,9 @@ const useGridDataSourceBase = (apiRef, props, options = {}) => {
45
47
  }, [currentStrategy]);
46
48
  const paginationModel = (0, _useGridSelector.useGridSelector)(apiRef, _gridPaginationSelector.gridPaginationModelSelector);
47
49
  const lastRequestId = React.useRef(0);
50
+ const pollingIntervalRef = React.useRef(null);
48
51
  const onDataSourceErrorProp = props.onDataSourceError;
52
+ const revalidateMs = props.dataSourceRevalidateMs;
49
53
  const cacheChunkManager = (0, _useLazyRef.default)(() => {
50
54
  if (!props.pagination) {
51
55
  return new _utils2.CacheChunkManager(paginationModel.pageSize);
@@ -135,6 +139,69 @@ const useGridDataSourceBase = (apiRef, props, options = {}) => {
135
139
  const handleStrategyActivityChange = React.useCallback(() => {
136
140
  setCurrentStrategy(apiRef.current.getActiveStrategy(_strategyProcessing.GridStrategyGroup.DataSource));
137
141
  }, [apiRef]);
142
+ const fetchRowChildrenOption = options.fetchRowChildren;
143
+ const revalidate = (0, _useEventCallback.default)(async () => {
144
+ const getRows = props.dataSource?.getRows;
145
+ if (!getRows || !standardRowsUpdateStrategyActive) {
146
+ return;
147
+ }
148
+ const revalidateExpandedGroups = () => {
149
+ if (currentStrategy !== _utils2.DataSourceRowsUpdateStrategy.GroupedData || !fetchRowChildrenOption) {
150
+ return;
151
+ }
152
+ const rowTree = (0, _gridRowsSelector.gridRowTreeSelector)(apiRef);
153
+ const visibleRows = (0, _gridPaginationSelector.gridVisibleRowsSelector)(apiRef).rows;
154
+ const expandedGroupIds = visibleRows.reduce((acc, row) => {
155
+ const node = rowTree[row.id];
156
+ if (node.type === 'group' && node.id !== _gridRowsUtils.GRID_ROOT_GROUP_ID && node.childrenExpanded === true) {
157
+ acc.push(row.id);
158
+ }
159
+ return acc;
160
+ }, []);
161
+ if (expandedGroupIds.length > 0) {
162
+ fetchRowChildrenOption(expandedGroupIds, {
163
+ showChildrenLoading: false
164
+ });
165
+ }
166
+ };
167
+ const fetchParams = (0, _extends2.default)({}, (0, _gridDataSourceSelector.gridGetRowsParamsSelector)(apiRef), apiRef.current.unstable_applyPipeProcessors('getRowsParams', {}));
168
+ const cacheKeys = cacheChunkManager.getCacheKeys(fetchParams);
169
+ const responses = cacheKeys.map(cacheKey => cache.get(cacheKey));
170
+ if (responses.every(response => response !== undefined)) {
171
+ revalidateExpandedGroups();
172
+ return;
173
+ }
174
+ try {
175
+ const response = await getRows(fetchParams);
176
+ const currentParams = (0, _extends2.default)({}, (0, _gridDataSourceSelector.gridGetRowsParamsSelector)(apiRef), apiRef.current.unstable_applyPipeProcessors('getRowsParams', {}));
177
+ if (!(0, _isDeepEqual.isDeepEqual)(fetchParams, currentParams)) {
178
+ return;
179
+ }
180
+ const cacheResponses = cacheChunkManager.splitResponse(fetchParams, response);
181
+ cacheResponses.forEach((cacheResponse, key) => cache.set(key, cacheResponse));
182
+ apiRef.current.applyStrategyProcessor('dataSourceRowsUpdate', {
183
+ response,
184
+ fetchParams,
185
+ options: {}
186
+ });
187
+ revalidateExpandedGroups();
188
+ } catch {
189
+ // Ignore background revalidation errors.
190
+ }
191
+ });
192
+ const stopPolling = React.useCallback(() => {
193
+ if (pollingIntervalRef.current !== null) {
194
+ clearInterval(pollingIntervalRef.current);
195
+ pollingIntervalRef.current = null;
196
+ }
197
+ }, []);
198
+ const startPolling = (0, _useEventCallback.default)(() => {
199
+ stopPolling();
200
+ if (revalidateMs <= 0 || !standardRowsUpdateStrategyActive) {
201
+ return;
202
+ }
203
+ pollingIntervalRef.current = setInterval(revalidate, revalidateMs);
204
+ });
138
205
  const handleDataUpdate = React.useCallback(params => {
139
206
  if ('error' in params) {
140
207
  apiRef.current.setRows([]);
@@ -151,7 +218,8 @@ const useGridDataSourceBase = (apiRef, props, options = {}) => {
151
218
  params: params.fetchParams,
152
219
  response
153
220
  }, true);
154
- }, [apiRef]);
221
+ startPolling();
222
+ }, [apiRef, startPolling]);
155
223
  const dataSourceUpdateRow = props.dataSource?.updateRow;
156
224
  const handleEditRowOption = options.handleEditRow;
157
225
  const editRow = React.useCallback(async params => {
@@ -191,6 +259,10 @@ const useGridDataSourceBase = (apiRef, props, options = {}) => {
191
259
  }
192
260
  };
193
261
  const debouncedFetchRows = React.useMemo(() => (0, _debounce.default)(fetchRows, 0), [fetchRows]);
262
+ const handleFetchRowsOnParamsChange = React.useCallback(() => {
263
+ stopPolling();
264
+ debouncedFetchRows();
265
+ }, [stopPolling, debouncedFetchRows]);
194
266
  const isFirstRender = React.useRef(true);
195
267
  React.useEffect(() => {
196
268
  if (isFirstRender.current) {
@@ -203,6 +275,17 @@ const useGridDataSourceBase = (apiRef, props, options = {}) => {
203
275
  const newCache = getCache(props.dataSourceCache, options.cacheOptions);
204
276
  setCache(prevCache => prevCache !== newCache ? newCache : prevCache);
205
277
  }, [props.dataSourceCache, options.cacheOptions]);
278
+ React.useEffect(() => {
279
+ if (!standardRowsUpdateStrategyActive) {
280
+ stopPolling();
281
+ }
282
+ }, [standardRowsUpdateStrategyActive, stopPolling]);
283
+ React.useEffect(() => {
284
+ if (revalidateMs <= 0) {
285
+ stopPolling();
286
+ }
287
+ }, [revalidateMs, stopPolling]);
288
+ React.useEffect(() => stopPolling, [stopPolling]);
206
289
  React.useEffect(() => {
207
290
  // Return early if the proper strategy isn't set yet
208
291
  // Context: https://github.com/mui/mui-x/issues/19650
@@ -210,6 +293,8 @@ const useGridDataSourceBase = (apiRef, props, options = {}) => {
210
293
  return undefined;
211
294
  }
212
295
  if (props.dataSource) {
296
+ stopPolling();
297
+ apiRef.current.setRows([]);
213
298
  apiRef.current.dataSource.cache.clear();
214
299
  apiRef.current.dataSource.fetchRows();
215
300
  }
@@ -217,7 +302,7 @@ const useGridDataSourceBase = (apiRef, props, options = {}) => {
217
302
  // ignore the current request on unmount
218
303
  lastRequestId.current += 1;
219
304
  };
220
- }, [apiRef, props.dataSource, currentStrategy]);
305
+ }, [apiRef, props.dataSource, currentStrategy, stopPolling]);
221
306
  return {
222
307
  api: {
223
308
  public: dataSourceApi
@@ -229,13 +314,15 @@ const useGridDataSourceBase = (apiRef, props, options = {}) => {
229
314
  processor: handleDataUpdate
230
315
  },
231
316
  setStrategyAvailability,
317
+ startPolling,
318
+ stopPolling,
232
319
  cacheChunkManager,
233
320
  cache,
234
321
  events: {
235
322
  strategyAvailabilityChange: handleStrategyActivityChange,
236
- sortModelChange: (0, _utils.runIf)(standardRowsUpdateStrategyActive, () => debouncedFetchRows()),
237
- filterModelChange: (0, _utils.runIf)(standardRowsUpdateStrategyActive, () => debouncedFetchRows()),
238
- paginationModelChange: (0, _utils.runIf)(standardRowsUpdateStrategyActive, () => debouncedFetchRows())
323
+ sortModelChange: (0, _utils.runIf)(standardRowsUpdateStrategyActive, handleFetchRowsOnParamsChange),
324
+ filterModelChange: (0, _utils.runIf)(standardRowsUpdateStrategyActive, handleFetchRowsOnParamsChange),
325
+ paginationModelChange: (0, _utils.runIf)(standardRowsUpdateStrategyActive, handleFetchRowsOnParamsChange)
239
326
  }
240
327
  };
241
328
  };
@@ -191,12 +191,15 @@ const useGridRowEditing = (apiRef, props) => {
191
191
  const rowParams = apiRef.current.getRowParams(params.id);
192
192
  const newParams = (0, _extends2.default)({}, rowParams, {
193
193
  field: params.field,
194
- reason
194
+ reason,
195
+ // Only pass the pressed key when the row editing is controlled via `rowModesModel`.
196
+ // In uncontrolled mode, the default editor already inserts the character and passing it here would duplicate it.
197
+ key: rowModesModelProp && (0, _keyboardUtils.isPrintableKey)(event) ? event.key : undefined
195
198
  });
196
199
  apiRef.current.publishEvent('rowEditStart', newParams, event);
197
200
  }
198
201
  }
199
- }, [apiRef, hasFieldsWithErrors]);
202
+ }, [apiRef, hasFieldsWithErrors, rowModesModelProp]);
200
203
  const handleRowEditStart = React.useCallback(params => {
201
204
  const {
202
205
  id,
@@ -208,10 +211,17 @@ const useGridRowEditing = (apiRef, props) => {
208
211
  fieldToFocus: field
209
212
  };
210
213
  if (reason === _gridRowParams.GridRowEditStartReasons.printableKeyDown || reason === _gridRowParams.GridRowEditStartReasons.deleteKeyDown) {
211
- startRowEditModeParams.deleteValue = !!field;
214
+ // If the user typed a printable key, initialize the value with that key
215
+ // to avoid losing the first character when the component is controlled.
216
+ if (rowModesModelProp && reason === _gridRowParams.GridRowEditStartReasons.printableKeyDown && params.key && field) {
217
+ startRowEditModeParams.initialValue = params.key;
218
+ } else {
219
+ // For Delete / Backspace or for uncontrolled row editing we clear the value
220
+ startRowEditModeParams.deleteValue = !!field;
221
+ }
212
222
  }
213
223
  apiRef.current.startRowEditMode(startRowEditModeParams);
214
- }, [apiRef]);
224
+ }, [apiRef, rowModesModelProp]);
215
225
  const handleRowEditStop = React.useCallback(params => {
216
226
  const {
217
227
  id,
package/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @mui/x-data-grid v8.27.0
2
+ * @mui/x-data-grid v8.27.3
3
3
  *
4
4
  * @license MIT
5
5
  * This source code is licensed under the MIT license found in the
@@ -29,6 +29,7 @@ export { gridHeaderFilteringEditFieldSelector, gridHeaderFilteringMenuSelector }
29
29
  export type { GridSlotsComponentsProps } from "../models/gridSlotsComponentsProps.js";
30
30
  export type { GridFilterInputValueProps } from "../models/gridFilterInputComponent.js";
31
31
  export { useGridColumnMenu, columnMenuStateInitializer } from "../hooks/features/columnMenu/useGridColumnMenu.js";
32
+ export type { GridColumnMenuComponent } from "../components/menu/columnMenu/GridColumnMenuProps.js";
32
33
  export { useGridColumns, columnsStateInitializer } from "../hooks/features/columns/useGridColumns.js";
33
34
  export * from "../hooks/features/columns/gridColumnsUtils.js";
34
35
  export { useGridColumnSpanning } from "../hooks/features/columns/useGridColumnSpanning.js";
@@ -123,7 +123,6 @@ export interface GridStartRowEditModeParams {
123
123
  /**
124
124
  * The initial value for the given `fieldToFocus`.
125
125
  * If `deleteValue` is also true, this value is not used.
126
- * @deprecated No longer needed.
127
126
  */
128
127
  initialValue?: string;
129
128
  }